Merge pull request #1092 from eightyeight/walkabout
Walkabout navigation editor
|
|
@ -100,6 +100,12 @@ AIPlayer::AIPlayer()
|
||||||
mTargetInLOS = false;
|
mTargetInLOS = false;
|
||||||
mAimOffset = Point3F(0.0f, 0.0f, 0.0f);
|
mAimOffset = Point3F(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
mJump = None;
|
||||||
|
mNavSize = Regular;
|
||||||
|
mLinkTypes = LinkData(AllFlags);
|
||||||
|
#endif
|
||||||
|
|
||||||
mIsAiControlled = true;
|
mIsAiControlled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,6 +142,27 @@ void AIPlayer::initPersistFields()
|
||||||
|
|
||||||
endGroup( "AI" );
|
endGroup( "AI" );
|
||||||
|
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
addGroup("Pathfinding");
|
||||||
|
|
||||||
|
addField("allowWalk", TypeBool, Offset(mLinkTypes.walk, AIPlayer),
|
||||||
|
"Allow the character to walk on dry land.");
|
||||||
|
addField("allowJump", TypeBool, Offset(mLinkTypes.jump, AIPlayer),
|
||||||
|
"Allow the character to use jump links.");
|
||||||
|
addField("allowDrop", TypeBool, Offset(mLinkTypes.drop, AIPlayer),
|
||||||
|
"Allow the character to use drop links.");
|
||||||
|
addField("allowSwim", TypeBool, Offset(mLinkTypes.swim, AIPlayer),
|
||||||
|
"Allow the character tomove in water.");
|
||||||
|
addField("allowLedge", TypeBool, Offset(mLinkTypes.ledge, AIPlayer),
|
||||||
|
"Allow the character to jump ledges.");
|
||||||
|
addField("allowClimb", TypeBool, Offset(mLinkTypes.climb, AIPlayer),
|
||||||
|
"Allow the character to use climb links.");
|
||||||
|
addField("allowTeleport", TypeBool, Offset(mLinkTypes.teleport, AIPlayer),
|
||||||
|
"Allow the character to use teleporters.");
|
||||||
|
|
||||||
|
endGroup("Pathfinding");
|
||||||
|
#endif // TORQUE_NAVIGATION_ENABLED
|
||||||
|
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,6 +179,16 @@ bool AIPlayer::onAdd()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AIPlayer::onRemove()
|
||||||
|
{
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
clearPath();
|
||||||
|
clearCover();
|
||||||
|
clearFollow();
|
||||||
|
#endif
|
||||||
|
Parent::onRemove();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the speed at which this AI moves
|
* Sets the speed at which this AI moves
|
||||||
*
|
*
|
||||||
|
|
@ -168,6 +205,11 @@ void AIPlayer::setMoveSpeed( F32 speed )
|
||||||
void AIPlayer::stopMove()
|
void AIPlayer::stopMove()
|
||||||
{
|
{
|
||||||
mMoveState = ModeStop;
|
mMoveState = ModeStop;
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
clearPath();
|
||||||
|
clearCover();
|
||||||
|
clearFollow();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -258,6 +300,32 @@ bool AIPlayer::getAIMove(Move *movePtr)
|
||||||
Point3F location = eye.getPosition();
|
Point3F location = eye.getPosition();
|
||||||
Point3F rotation = getRotation();
|
Point3F rotation = getRotation();
|
||||||
|
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
if(mDamageState == Enabled)
|
||||||
|
{
|
||||||
|
if(mMoveState != ModeStop)
|
||||||
|
updateNavMesh();
|
||||||
|
if(!mFollowData.object.isNull())
|
||||||
|
{
|
||||||
|
if(mPathData.path.isNull())
|
||||||
|
{
|
||||||
|
if((getPosition() - mFollowData.object->getPosition()).len() > mFollowData.radius)
|
||||||
|
followObject(mFollowData.object, mFollowData.radius);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if((mPathData.path->mTo - mFollowData.object->getPosition()).len() > mFollowData.radius)
|
||||||
|
repath();
|
||||||
|
else if((getPosition() - mFollowData.object->getPosition()).len() < mFollowData.radius)
|
||||||
|
{
|
||||||
|
clearPath();
|
||||||
|
mMoveState = ModeStop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // TORQUE_NAVIGATION_ENABLED
|
||||||
|
|
||||||
// Orient towards the aim point, aim object, or towards
|
// Orient towards the aim point, aim object, or towards
|
||||||
// our destination.
|
// our destination.
|
||||||
if (mAimObject || mAimLocationSet || mMoveState != ModeStop)
|
if (mAimObject || mAimLocationSet || mMoveState != ModeStop)
|
||||||
|
|
@ -340,7 +408,7 @@ bool AIPlayer::getAIMove(Move *movePtr)
|
||||||
if (mFabs(xDiff) < mMoveTolerance && mFabs(yDiff) < mMoveTolerance)
|
if (mFabs(xDiff) < mMoveTolerance && mFabs(yDiff) < mMoveTolerance)
|
||||||
{
|
{
|
||||||
mMoveState = ModeStop;
|
mMoveState = ModeStop;
|
||||||
throwCallback("onReachDestination");
|
onReachDestination();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -409,7 +477,7 @@ bool AIPlayer::getAIMove(Move *movePtr)
|
||||||
if ( mMoveState != ModeSlowing || locationDelta == 0 )
|
if ( mMoveState != ModeSlowing || locationDelta == 0 )
|
||||||
{
|
{
|
||||||
mMoveState = ModeStuck;
|
mMoveState = ModeStuck;
|
||||||
throwCallback("onMoveStuck");
|
onStuck();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -419,28 +487,53 @@ bool AIPlayer::getAIMove(Move *movePtr)
|
||||||
// Test for target location in sight if it's an object. The LOS is
|
// Test for target location in sight if it's an object. The LOS is
|
||||||
// run from the eye position to the center of the object's bounding,
|
// run from the eye position to the center of the object's bounding,
|
||||||
// which is not very accurate.
|
// which is not very accurate.
|
||||||
if (mAimObject)
|
if (mAimObject) {
|
||||||
{
|
MatrixF eyeMat;
|
||||||
if (checkInLos(mAimObject.getPointer()))
|
getEyeTransform(&eyeMat);
|
||||||
{
|
eyeMat.getColumn(3,&location);
|
||||||
if (!mTargetInLOS)
|
Point3F targetLoc = mAimObject->getBoxCenter();
|
||||||
{
|
|
||||||
throwCallback("onTargetEnterLOS");
|
// This ray ignores non-static shapes. Cast Ray returns true
|
||||||
mTargetInLOS = true;
|
// if it hit something.
|
||||||
|
RayInfo dummy;
|
||||||
|
if (getContainer()->castRay( location, targetLoc,
|
||||||
|
StaticShapeObjectType | StaticObjectType |
|
||||||
|
TerrainObjectType, &dummy)) {
|
||||||
|
if (mTargetInLOS) {
|
||||||
|
throwCallback( "onTargetExitLOS" );
|
||||||
|
mTargetInLOS = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mTargetInLOS)
|
else
|
||||||
{
|
if (!mTargetInLOS) {
|
||||||
throwCallback("onTargetExitLOS");
|
throwCallback( "onTargetEnterLOS" );
|
||||||
mTargetInLOS = false;
|
mTargetInLOS = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replicate the trigger state into the move so that
|
// Replicate the trigger state into the move so that
|
||||||
// triggers can be controlled from scripts.
|
// triggers can be controlled from scripts.
|
||||||
for( U32 i = 0; i < MaxMountedImages; i++ )
|
for( int i = 0; i < MaxTriggerKeys; i++ )
|
||||||
movePtr->trigger[i] = getImageTriggerState(i);
|
movePtr->trigger[i] = getImageTriggerState(i);
|
||||||
|
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
if(mJump == Now)
|
||||||
|
{
|
||||||
|
movePtr->trigger[2] = true;
|
||||||
|
mJump = None;
|
||||||
|
}
|
||||||
|
else if(mJump == Ledge)
|
||||||
|
{
|
||||||
|
// If we're not touching the ground, jump!
|
||||||
|
RayInfo info;
|
||||||
|
if(!getContainer()->castRay(getPosition(), getPosition() - Point3F(0, 0, 0.4f), StaticShapeObjectType, &info))
|
||||||
|
{
|
||||||
|
movePtr->trigger[2] = true;
|
||||||
|
mJump = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // TORQUE_NAVIGATION_ENABLED
|
||||||
|
|
||||||
mLastLocation = location;
|
mLastLocation = location;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -457,6 +550,457 @@ void AIPlayer::throwCallback( const char *name )
|
||||||
Con::executef(getDataBlock(), name, getIdString());
|
Con::executef(getDataBlock(), name, getIdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when we get within mMoveTolerance of our destination set using
|
||||||
|
* setMoveDestination(). Only fires the script callback if we are at the end
|
||||||
|
* of a pathfinding path, or have no pathfinding path.
|
||||||
|
*/
|
||||||
|
void AIPlayer::onReachDestination()
|
||||||
|
{
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
if(!mPathData.path.isNull())
|
||||||
|
{
|
||||||
|
if(mPathData.index == mPathData.path->size() - 1)
|
||||||
|
{
|
||||||
|
// Handle looping paths.
|
||||||
|
if(mPathData.path->mIsLooping)
|
||||||
|
moveToNode(0);
|
||||||
|
// Otherwise end path.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clearPath();
|
||||||
|
throwCallback("onReachDestination");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
moveToNode(mPathData.index + 1);
|
||||||
|
// Throw callback every time if we're on a looping path.
|
||||||
|
//if(mPathData.path->mIsLooping)
|
||||||
|
//throwCallback("onReachDestination");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
throwCallback("onReachDestination");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when we move less than mMoveStuckTolerance in a tick, signalling
|
||||||
|
* that some obstacle is preventing us from getting where we need to go.
|
||||||
|
*/
|
||||||
|
void AIPlayer::onStuck()
|
||||||
|
{
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
if(!mPathData.path.isNull())
|
||||||
|
repath();
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
throwCallback("onMoveStuck");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
// Pathfinding
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void AIPlayer::clearPath()
|
||||||
|
{
|
||||||
|
// Only delete if we own the path.
|
||||||
|
if(!mPathData.path.isNull() && mPathData.owned)
|
||||||
|
mPathData.path->deleteObject();
|
||||||
|
// Reset path data.
|
||||||
|
mPathData = PathData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIPlayer::clearCover()
|
||||||
|
{
|
||||||
|
// Notify cover that we are no longer on our way.
|
||||||
|
if(!mCoverData.cover.isNull())
|
||||||
|
mCoverData.cover->setOccupied(false);
|
||||||
|
mCoverData = CoverData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIPlayer::clearFollow()
|
||||||
|
{
|
||||||
|
mFollowData = FollowData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIPlayer::moveToNode(S32 node)
|
||||||
|
{
|
||||||
|
if(mPathData.path.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// -1 is shorthand for 'last path node'.
|
||||||
|
if(node == -1)
|
||||||
|
node = mPathData.path->size() - 1;
|
||||||
|
|
||||||
|
// Consider slowing down on the last path node.
|
||||||
|
setMoveDestination(mPathData.path->getNode(node), false);
|
||||||
|
|
||||||
|
// Check flags for this segment.
|
||||||
|
if(mPathData.index)
|
||||||
|
{
|
||||||
|
U16 flags = mPathData.path->getFlags(node - 1);
|
||||||
|
// Jump if we must.
|
||||||
|
if(flags & LedgeFlag)
|
||||||
|
mJump = Ledge;
|
||||||
|
else if(flags & JumpFlag)
|
||||||
|
mJump = Now;
|
||||||
|
else
|
||||||
|
// Catch pathing errors.
|
||||||
|
mJump = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store current index.
|
||||||
|
mPathData.index = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AIPlayer::setPathDestination(const Point3F &pos)
|
||||||
|
{
|
||||||
|
// Pathfinding only happens on the server.
|
||||||
|
if(!isServerObject())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!getNavMesh())
|
||||||
|
updateNavMesh();
|
||||||
|
// If we can't find a mesh, just move regularly.
|
||||||
|
if(!getNavMesh())
|
||||||
|
{
|
||||||
|
//setMoveDestination(pos);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new path.
|
||||||
|
NavPath *path = new NavPath();
|
||||||
|
if(path)
|
||||||
|
{
|
||||||
|
path->mMesh = getNavMesh();
|
||||||
|
path->mFrom = getPosition();
|
||||||
|
path->mTo = pos;
|
||||||
|
path->mFromSet = path->mToSet = true;
|
||||||
|
path->mAlwaysRender = true;
|
||||||
|
path->mLinkTypes = mLinkTypes;
|
||||||
|
path->mXray = true;
|
||||||
|
// Paths plan automatically upon being registered.
|
||||||
|
if(!path->registerObject())
|
||||||
|
{
|
||||||
|
delete path;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(path->success())
|
||||||
|
{
|
||||||
|
// Clear any current path we might have.
|
||||||
|
clearPath();
|
||||||
|
clearCover();
|
||||||
|
clearFollow();
|
||||||
|
// Store new path.
|
||||||
|
mPathData.path = path;
|
||||||
|
mPathData.owned = true;
|
||||||
|
// Skip node 0, which we are currently standing on.
|
||||||
|
moveToNode(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Just move normally if we can't path.
|
||||||
|
//setMoveDestination(pos, true);
|
||||||
|
//return;
|
||||||
|
//throwCallback("onPathFailed");
|
||||||
|
path->deleteObject();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIPlayer, setPathDestination, bool, (Point3F goal),,
|
||||||
|
"@brief Tells the AI to find a path to the location provided\n\n"
|
||||||
|
|
||||||
|
"@param goal Coordinates in world space representing location to move to.\n"
|
||||||
|
"@return True if a path was found.\n\n"
|
||||||
|
|
||||||
|
"@see getPathDestination()\n"
|
||||||
|
"@see setMoveDestination()\n")
|
||||||
|
{
|
||||||
|
return object->setPathDestination(goal);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3F AIPlayer::getPathDestination() const
|
||||||
|
{
|
||||||
|
if(!mPathData.path.isNull())
|
||||||
|
return mPathData.path->mTo;
|
||||||
|
return Point3F(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIPlayer, getPathDestination, Point3F, (),,
|
||||||
|
"@brief Get the AIPlayer's current pathfinding destination.\n\n"
|
||||||
|
|
||||||
|
"@return Returns a point containing the \"x y z\" position "
|
||||||
|
"of the AIPlayer's current path destination. If no path destination "
|
||||||
|
"has yet been set, this returns \"0 0 0\"."
|
||||||
|
|
||||||
|
"@see setPathDestination()\n")
|
||||||
|
{
|
||||||
|
return object->getPathDestination();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIPlayer::followNavPath(NavPath *path)
|
||||||
|
{
|
||||||
|
if(!isServerObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get rid of our current path.
|
||||||
|
clearPath();
|
||||||
|
clearCover();
|
||||||
|
clearFollow();
|
||||||
|
|
||||||
|
// Follow new path.
|
||||||
|
mPathData.path = path;
|
||||||
|
mPathData.owned = false;
|
||||||
|
// Start from 0 since we might not already be there.
|
||||||
|
moveToNode(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIPlayer, followNavPath, void, (SimObjectId obj),,
|
||||||
|
"@brief Tell the AIPlayer to follow a path.\n\n"
|
||||||
|
|
||||||
|
"@param obj ID of a NavPath object for the character to follow.")
|
||||||
|
{
|
||||||
|
NavPath *path;
|
||||||
|
if(Sim::findObject(obj, path))
|
||||||
|
object->followNavPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIPlayer::followObject(SceneObject *obj, F32 radius)
|
||||||
|
{
|
||||||
|
if(!isServerObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(setPathDestination(obj->getPosition()))
|
||||||
|
{
|
||||||
|
clearCover();
|
||||||
|
mFollowData.object = obj;
|
||||||
|
mFollowData.radius = radius;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIPlayer, followObject, void, (SimObjectId obj, F32 radius),,
|
||||||
|
"@brief Tell the AIPlayer to follow another object.\n\n"
|
||||||
|
|
||||||
|
"@param obj ID of the object to follow.\n"
|
||||||
|
"@param radius Maximum distance we let the target escape to.")
|
||||||
|
{
|
||||||
|
SceneObject *follow;
|
||||||
|
if(Sim::findObject(obj, follow))
|
||||||
|
object->followObject(follow, radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIPlayer::repath()
|
||||||
|
{
|
||||||
|
// Ineffectual if we don't have a path, or are using someone else's.
|
||||||
|
if(mPathData.path.isNull() || !mPathData.owned)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If we're following, get their position.
|
||||||
|
if(!mFollowData.object.isNull())
|
||||||
|
mPathData.path->mTo = mFollowData.object->getPosition();
|
||||||
|
// Update from position and replan.
|
||||||
|
mPathData.path->mFrom = getPosition();
|
||||||
|
mPathData.path->plan();
|
||||||
|
// Move to first node (skip start pos).
|
||||||
|
moveToNode(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIPlayer, repath, void, (),,
|
||||||
|
"@brief Tells the AI to re-plan its path. Does nothing if the character "
|
||||||
|
"has no path, or if it is following a mission path.\n\n")
|
||||||
|
{
|
||||||
|
object->repath();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CoverSearch
|
||||||
|
{
|
||||||
|
Point3F loc;
|
||||||
|
Point3F from;
|
||||||
|
F32 dist;
|
||||||
|
F32 best;
|
||||||
|
CoverPoint *point;
|
||||||
|
CoverSearch() : loc(0, 0, 0), from(0, 0, 0)
|
||||||
|
{
|
||||||
|
best = -FLT_MAX;
|
||||||
|
point = NULL;
|
||||||
|
dist = FLT_MAX;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void findCoverCallback(SceneObject *obj, void *key)
|
||||||
|
{
|
||||||
|
CoverPoint *p = dynamic_cast<CoverPoint*>(obj);
|
||||||
|
if(!p || p->isOccupied())
|
||||||
|
return;
|
||||||
|
CoverSearch *s = static_cast<CoverSearch*>(key);
|
||||||
|
Point3F dir = s->from - p->getPosition();
|
||||||
|
dir.normalizeSafe();
|
||||||
|
// Score first based on angle of cover point to enemy.
|
||||||
|
F32 score = mDot(p->getNormal(), dir);
|
||||||
|
// Score also based on distance from seeker.
|
||||||
|
score -= (p->getPosition() - s->loc).len() / s->dist;
|
||||||
|
// Finally, consider cover size.
|
||||||
|
score += (p->getSize() + 1) / CoverPoint::NumSizes;
|
||||||
|
score *= p->getQuality();
|
||||||
|
if(score > s->best)
|
||||||
|
{
|
||||||
|
s->best = score;
|
||||||
|
s->point = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AIPlayer::findCover(const Point3F &from, F32 radius)
|
||||||
|
{
|
||||||
|
if(radius <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Create a search state.
|
||||||
|
CoverSearch s;
|
||||||
|
s.loc = getPosition();
|
||||||
|
s.dist = radius;
|
||||||
|
// Direction we seek cover FROM.
|
||||||
|
s.from = from;
|
||||||
|
|
||||||
|
// Find cover points.
|
||||||
|
Box3F box(radius * 2.0f);
|
||||||
|
box.setCenter(getPosition());
|
||||||
|
getContainer()->findObjects(box, MarkerObjectType, findCoverCallback, &s);
|
||||||
|
|
||||||
|
// Go to cover!
|
||||||
|
if(s.point)
|
||||||
|
{
|
||||||
|
// Calling setPathDestination clears cover...
|
||||||
|
bool foundPath = setPathDestination(s.point->getPosition());
|
||||||
|
// Now store the cover info.
|
||||||
|
mCoverData.cover = s.point;
|
||||||
|
s.point->setOccupied(true);
|
||||||
|
return foundPath;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIPlayer, findCover, S32, (Point3F from, F32 radius),,
|
||||||
|
"@brief Tells the AI to find cover nearby.\n\n"
|
||||||
|
|
||||||
|
"@param from Location to find cover from (i.e., enemy position).\n"
|
||||||
|
"@param radius Distance to search for cover.\n"
|
||||||
|
"@return Cover point ID if cover was found, -1 otherwise.\n\n")
|
||||||
|
{
|
||||||
|
if(object->findCover(from, radius))
|
||||||
|
{
|
||||||
|
CoverPoint* cover = object->getCover();
|
||||||
|
return cover ? cover->getId() : -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NavMesh *AIPlayer::findNavMesh() const
|
||||||
|
{
|
||||||
|
// Search for NavMeshes that contain us entirely with the smallest possible
|
||||||
|
// volume.
|
||||||
|
NavMesh *mesh = NULL;
|
||||||
|
SimSet *set = NavMesh::getServerSet();
|
||||||
|
for(U32 i = 0; i < set->size(); i++)
|
||||||
|
{
|
||||||
|
NavMesh *m = static_cast<NavMesh*>(set->at(i));
|
||||||
|
if(m->getWorldBox().isContained(getWorldBox()))
|
||||||
|
{
|
||||||
|
// Check that mesh size is appropriate.
|
||||||
|
if(mMount.object) // Should use isMounted() but it's not const. Grr.
|
||||||
|
{
|
||||||
|
if(!m->mVehicles)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(getNavSize() == Small && !m->mSmallCharacters ||
|
||||||
|
getNavSize() == Regular && !m->mRegularCharacters ||
|
||||||
|
getNavSize() == Large && !m->mLargeCharacters)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!mesh || m->getWorldBox().getVolume() < mesh->getWorldBox().getVolume())
|
||||||
|
mesh = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIPlayer, findNavMesh, S32, (),,
|
||||||
|
"@brief Get the NavMesh object this AIPlayer is currently using.\n\n"
|
||||||
|
|
||||||
|
"@return The ID of the NavPath object this character is using for "
|
||||||
|
"pathfinding. This is determined by the character's location, "
|
||||||
|
"navigation type and other factors. Returns -1 if no NavMesh is "
|
||||||
|
"found.")
|
||||||
|
{
|
||||||
|
NavMesh *mesh = object->getNavMesh();
|
||||||
|
return mesh ? mesh->getId() : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIPlayer::updateNavMesh()
|
||||||
|
{
|
||||||
|
NavMesh *old = mNavMesh;
|
||||||
|
if(mNavMesh.isNull())
|
||||||
|
mNavMesh = findNavMesh();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!mNavMesh->getWorldBox().isContained(getWorldBox()))
|
||||||
|
mNavMesh = findNavMesh();
|
||||||
|
}
|
||||||
|
// See if we need to update our path.
|
||||||
|
if(mNavMesh != old && !mPathData.path.isNull())
|
||||||
|
{
|
||||||
|
setPathDestination(mPathData.path->mTo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIPlayer, getNavMesh, S32, (),,
|
||||||
|
"@brief Return the NavMesh this AIPlayer is using to navigate.\n\n")
|
||||||
|
{
|
||||||
|
NavMesh *m = object->getNavMesh();
|
||||||
|
return m ? m->getId() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIPlayer, setNavSize, void, (const char *size),,
|
||||||
|
"@brief Set the size of NavMesh this character uses. One of \"Small\", \"Regular\" or \"Large\".")
|
||||||
|
{
|
||||||
|
if(!dStrcmp(size, "Small"))
|
||||||
|
object->setNavSize(AIPlayer::Small);
|
||||||
|
else if(!dStrcmp(size, "Regular"))
|
||||||
|
object->setNavSize(AIPlayer::Regular);
|
||||||
|
else if(!dStrcmp(size, "Large"))
|
||||||
|
object->setNavSize(AIPlayer::Large);
|
||||||
|
else
|
||||||
|
Con::errorf("AIPlayer::setNavSize: no such size '%s'.", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIPlayer, getNavSize, const char*, (),,
|
||||||
|
"@brief Return the size of NavMesh this character uses for pathfinding.")
|
||||||
|
{
|
||||||
|
switch(object->getNavSize())
|
||||||
|
{
|
||||||
|
case AIPlayer::Small:
|
||||||
|
return "Small";
|
||||||
|
case AIPlayer::Regular:
|
||||||
|
return "Regular";
|
||||||
|
case AIPlayer::Large:
|
||||||
|
return "Large";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
#endif // TORQUE_NAVIGATION_ENABLED
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
// Console Functions
|
// Console Functions
|
||||||
|
|
@ -711,4 +1255,4 @@ DefineEngineMethod(AIPlayer, checkInFoV, bool, (ShapeBase* obj, F32 fov, bool ch
|
||||||
"@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n")
|
"@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n")
|
||||||
{
|
{
|
||||||
return object->checkInFoV(obj, fov, checkEnabled);
|
return object->checkInFoV(obj, fov, checkEnabled);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,11 @@
|
||||||
#include "T3D/player.h"
|
#include "T3D/player.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
#include "navigation/navPath.h"
|
||||||
|
#include "navigation/navMesh.h"
|
||||||
|
#include "navigation/coverPoint.h"
|
||||||
|
#endif // TORQUE_NAVIGATION_ENABLED
|
||||||
|
|
||||||
class AIPlayer : public Player {
|
class AIPlayer : public Player {
|
||||||
|
|
||||||
|
|
@ -61,6 +66,83 @@ private:
|
||||||
// Utility Methods
|
// Utility Methods
|
||||||
void throwCallback( const char *name );
|
void throwCallback( const char *name );
|
||||||
|
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
/// Should we jump?
|
||||||
|
enum JumpStates {
|
||||||
|
None, ///< No, don't jump.
|
||||||
|
Now, ///< Jump immediately.
|
||||||
|
Ledge, ///< Jump when we walk off a ledge.
|
||||||
|
} mJump;
|
||||||
|
|
||||||
|
/// Stores information about a path.
|
||||||
|
struct PathData {
|
||||||
|
/// Pointer to path object.
|
||||||
|
SimObjectPtr<NavPath> path;
|
||||||
|
/// Do we own our path? If so, we will delete it when finished.
|
||||||
|
bool owned;
|
||||||
|
/// Path node we're at.
|
||||||
|
U32 index;
|
||||||
|
/// Default constructor.
|
||||||
|
PathData() : path(NULL)
|
||||||
|
{
|
||||||
|
owned = false;
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Path we are currently following.
|
||||||
|
PathData mPathData;
|
||||||
|
|
||||||
|
/// Clear out the current path.
|
||||||
|
void clearPath();
|
||||||
|
|
||||||
|
/// Get the current path we're following.
|
||||||
|
NavPath *getPath() { return mPathData.path; }
|
||||||
|
|
||||||
|
/// Stores information about our cover.
|
||||||
|
struct CoverData {
|
||||||
|
/// Pointer to a cover point.
|
||||||
|
SimObjectPtr<CoverPoint> cover;
|
||||||
|
/// Default constructor.
|
||||||
|
CoverData() : cover(NULL) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Current cover we're trying to get to.
|
||||||
|
CoverData mCoverData;
|
||||||
|
|
||||||
|
/// Stop searching for cover.
|
||||||
|
void clearCover();
|
||||||
|
|
||||||
|
/// Information about a target we're following.
|
||||||
|
struct FollowData {
|
||||||
|
/// Object to follow.
|
||||||
|
SimObjectPtr<SceneObject> object;
|
||||||
|
/// Distance at whcih to follow.
|
||||||
|
F32 radius;
|
||||||
|
/// Default constructor.
|
||||||
|
FollowData() : object(NULL)
|
||||||
|
{
|
||||||
|
radius = 5.0f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Current object we're following.
|
||||||
|
FollowData mFollowData;
|
||||||
|
|
||||||
|
/// Stop following me!
|
||||||
|
void clearFollow();
|
||||||
|
|
||||||
|
/// NavMesh we pathfind on.
|
||||||
|
SimObjectPtr<NavMesh> mNavMesh;
|
||||||
|
|
||||||
|
/// Move to the specified node in the current path.
|
||||||
|
void moveToNode(S32 node);
|
||||||
|
#endif // TORQUE_NAVIGATION_ENABLED
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void onReachDestination();
|
||||||
|
virtual void onStuck();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DECLARE_CONOBJECT( AIPlayer );
|
DECLARE_CONOBJECT( AIPlayer );
|
||||||
|
|
||||||
|
|
@ -70,6 +152,7 @@ public:
|
||||||
static void initPersistFields();
|
static void initPersistFields();
|
||||||
|
|
||||||
bool onAdd();
|
bool onAdd();
|
||||||
|
void onRemove();
|
||||||
|
|
||||||
virtual bool getAIMove( Move *move );
|
virtual bool getAIMove( Move *move );
|
||||||
|
|
||||||
|
|
@ -91,6 +174,41 @@ public:
|
||||||
void setMoveDestination( const Point3F &location, bool slowdown );
|
void setMoveDestination( const Point3F &location, bool slowdown );
|
||||||
Point3F getMoveDestination() const { return mMoveDestination; }
|
Point3F getMoveDestination() const { return mMoveDestination; }
|
||||||
void stopMove();
|
void stopMove();
|
||||||
|
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
/// @name Pathfinding
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
enum NavSize {
|
||||||
|
Small,
|
||||||
|
Regular,
|
||||||
|
Large
|
||||||
|
} mNavSize;
|
||||||
|
void setNavSize(NavSize size) { mNavSize = size; updateNavMesh(); }
|
||||||
|
NavSize getNavSize() const { return mNavSize; }
|
||||||
|
|
||||||
|
bool setPathDestination(const Point3F &pos);
|
||||||
|
Point3F getPathDestination() const;
|
||||||
|
|
||||||
|
void followNavPath(NavPath *path);
|
||||||
|
void followObject(SceneObject *obj, F32 radius);
|
||||||
|
|
||||||
|
void repath();
|
||||||
|
|
||||||
|
bool findCover(const Point3F &from, F32 radius);
|
||||||
|
|
||||||
|
NavMesh *findNavMesh() const;
|
||||||
|
void updateNavMesh();
|
||||||
|
NavMesh *getNavMesh() const { return mNavMesh; }
|
||||||
|
|
||||||
|
/// Get cover we are moving to.
|
||||||
|
CoverPoint *getCover() { return mCoverData.cover; }
|
||||||
|
|
||||||
|
/// Types of link we can use.
|
||||||
|
LinkData mLinkTypes;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
#endif // TORQUE_NAVIGATION_ENABLED
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1293,6 +1293,56 @@ bool River::collideBox(const Point3F &start, const Point3F &end, RayInfo* info)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool River::buildPolyList( PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& sphere )
|
||||||
|
{
|
||||||
|
Vector<const RiverSegment*> hitSegments;
|
||||||
|
for ( U32 i = 0; i < mSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
const RiverSegment &segment = mSegments[i];
|
||||||
|
if ( segment.worldbounds.isOverlapped( box ) )
|
||||||
|
{
|
||||||
|
hitSegments.push_back( &segment );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !hitSegments.size() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
polyList->setObject( this );
|
||||||
|
polyList->setTransform( &MatrixF::Identity, Point3F( 1.0f, 1.0f, 1.0f ) );
|
||||||
|
|
||||||
|
for ( U32 i = 0; i < hitSegments.size(); i++ )
|
||||||
|
{
|
||||||
|
const RiverSegment* segment = hitSegments[i];
|
||||||
|
for ( U32 k = 0; k < 2; k++ )
|
||||||
|
{
|
||||||
|
// gIdxArray[0] gives us the top plane (see table definition).
|
||||||
|
U32 idx0 = gIdxArray[0][k][0];
|
||||||
|
U32 idx1 = gIdxArray[0][k][1];
|
||||||
|
U32 idx2 = gIdxArray[0][k][2];
|
||||||
|
|
||||||
|
const Point3F &v0 = (*segment)[idx0];
|
||||||
|
const Point3F &v1 = (*segment)[idx1];
|
||||||
|
const Point3F &v2 = (*segment)[idx2];
|
||||||
|
|
||||||
|
// Add vertices to poly list.
|
||||||
|
U32 i0 = polyList->addPoint(v0);
|
||||||
|
polyList->addPoint(v1);
|
||||||
|
polyList->addPoint(v2);
|
||||||
|
|
||||||
|
// Add plane between them.
|
||||||
|
polyList->begin(0, 0);
|
||||||
|
polyList->vertex(i0);
|
||||||
|
polyList->vertex(i0+1);
|
||||||
|
polyList->vertex(i0+2);
|
||||||
|
polyList->plane(i0, i0+1, i0+2);
|
||||||
|
polyList->end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
F32 River::getWaterCoverage( const Box3F &worldBox ) const
|
F32 River::getWaterCoverage( const Box3F &worldBox ) const
|
||||||
{
|
{
|
||||||
PROFILE_SCOPE( River_GetWaterCoverage );
|
PROFILE_SCOPE( River_GetWaterCoverage );
|
||||||
|
|
|
||||||
|
|
@ -404,6 +404,7 @@ public:
|
||||||
virtual bool castRay(const Point3F &start, const Point3F &end, RayInfo* info);
|
virtual bool castRay(const Point3F &start, const Point3F &end, RayInfo* info);
|
||||||
virtual bool collideBox(const Point3F &start, const Point3F &end, RayInfo* info);
|
virtual bool collideBox(const Point3F &start, const Point3F &end, RayInfo* info);
|
||||||
virtual bool containsPoint( const Point3F& point ) const { return containsPoint( point, NULL ); }
|
virtual bool containsPoint( const Point3F& point ) const { return containsPoint( point, NULL ); }
|
||||||
|
virtual bool buildPolyList( PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& sphere );
|
||||||
|
|
||||||
// WaterObject
|
// WaterObject
|
||||||
virtual F32 getWaterCoverage( const Box3F &worldBox ) const;
|
virtual F32 getWaterCoverage( const Box3F &worldBox ) const;
|
||||||
|
|
|
||||||
|
|
@ -652,6 +652,52 @@ bool WaterBlock::castRay( const Point3F &start, const Point3F &end, RayInfo *inf
|
||||||
return mObjBox.isContained(info->point);
|
return mObjBox.isContained(info->point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WaterBlock::buildPolyList( PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& )
|
||||||
|
{
|
||||||
|
if(context == PLC_Navigation && box.isOverlapped(mWorldBox))
|
||||||
|
{
|
||||||
|
polyList->setObject( this );
|
||||||
|
MatrixF mat(true);
|
||||||
|
Point3F pos = getPosition();
|
||||||
|
pos.x = pos.y = 0;
|
||||||
|
mat.setPosition(pos);
|
||||||
|
polyList->setTransform( &mat, Point3F(1, 1, 1) );
|
||||||
|
|
||||||
|
Box3F ov = box.getOverlap(mWorldBox);
|
||||||
|
Point3F
|
||||||
|
p0(ov.minExtents.x, ov.maxExtents.y, 0),
|
||||||
|
p1(ov.maxExtents.x, ov.maxExtents.y, 0),
|
||||||
|
p2(ov.maxExtents.x, ov.minExtents.y, 0),
|
||||||
|
p3(ov.minExtents.x, ov.minExtents.y, 0);
|
||||||
|
|
||||||
|
// Add vertices to poly list.
|
||||||
|
U32 v0 = polyList->addPoint(p0);
|
||||||
|
polyList->addPoint(p1);
|
||||||
|
polyList->addPoint(p2);
|
||||||
|
polyList->addPoint(p3);
|
||||||
|
|
||||||
|
// Add plane between first three vertices.
|
||||||
|
polyList->begin(0, 0);
|
||||||
|
polyList->vertex(v0);
|
||||||
|
polyList->vertex(v0+1);
|
||||||
|
polyList->vertex(v0+2);
|
||||||
|
polyList->plane(v0, v0+1, v0+2);
|
||||||
|
polyList->end();
|
||||||
|
|
||||||
|
// Add plane between last three vertices.
|
||||||
|
polyList->begin(0, 1);
|
||||||
|
polyList->vertex(v0+2);
|
||||||
|
polyList->vertex(v0+3);
|
||||||
|
polyList->vertex(v0);
|
||||||
|
polyList->plane(v0+2, v0+3, v0);
|
||||||
|
polyList->end();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
F32 WaterBlock::getWaterCoverage( const Box3F &testBox ) const
|
F32 WaterBlock::getWaterCoverage( const Box3F &testBox ) const
|
||||||
{
|
{
|
||||||
Box3F wbox = getWorldBox();
|
Box3F wbox = getWorldBox();
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@ public:
|
||||||
virtual void inspectPostApply();
|
virtual void inspectPostApply();
|
||||||
virtual void setTransform( const MatrixF & mat );
|
virtual void setTransform( const MatrixF & mat );
|
||||||
virtual void setScale( const Point3F &scale );
|
virtual void setScale( const Point3F &scale );
|
||||||
|
virtual bool buildPolyList( PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& sphere );
|
||||||
|
|
||||||
// WaterObject
|
// WaterObject
|
||||||
virtual F32 getWaterCoverage( const Box3F &worldBox ) const;
|
virtual F32 getWaterCoverage( const Box3F &worldBox ) const;
|
||||||
|
|
|
||||||
|
|
@ -816,6 +816,48 @@ F32 WaterPlane::distanceTo( const Point3F& point ) const
|
||||||
return ( point.z - getPosition().z );
|
return ( point.z - getPosition().z );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WaterPlane::buildPolyList( PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& )
|
||||||
|
{
|
||||||
|
if(context == PLC_Navigation)
|
||||||
|
{
|
||||||
|
polyList->setObject( this );
|
||||||
|
polyList->setTransform( &MatrixF::Identity, Point3F( 1.0f, 1.0f, 1.0f ) );
|
||||||
|
|
||||||
|
F32 z = getPosition().z;
|
||||||
|
Point3F
|
||||||
|
p0(box.minExtents.x, box.maxExtents.y, z),
|
||||||
|
p1(box.maxExtents.x, box.maxExtents.y, z),
|
||||||
|
p2(box.maxExtents.x, box.minExtents.y, z),
|
||||||
|
p3(box.minExtents.x, box.minExtents.y, z);
|
||||||
|
|
||||||
|
// Add vertices to poly list.
|
||||||
|
U32 v0 = polyList->addPoint(p0);
|
||||||
|
polyList->addPoint(p1);
|
||||||
|
polyList->addPoint(p2);
|
||||||
|
polyList->addPoint(p3);
|
||||||
|
|
||||||
|
// Add plane between first three vertices.
|
||||||
|
polyList->begin(0, 0);
|
||||||
|
polyList->vertex(v0);
|
||||||
|
polyList->vertex(v0+1);
|
||||||
|
polyList->vertex(v0+2);
|
||||||
|
polyList->plane(v0, v0+1, v0+2);
|
||||||
|
polyList->end();
|
||||||
|
|
||||||
|
// Add plane between last three vertices.
|
||||||
|
polyList->begin(0, 1);
|
||||||
|
polyList->vertex(v0+2);
|
||||||
|
polyList->vertex(v0+3);
|
||||||
|
polyList->vertex(v0);
|
||||||
|
polyList->plane(v0+2, v0+3, v0);
|
||||||
|
polyList->end();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void WaterPlane::inspectPostApply()
|
void WaterPlane::inspectPostApply()
|
||||||
{
|
{
|
||||||
Parent::inspectPostApply();
|
Parent::inspectPostApply();
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ public:
|
||||||
virtual void inspectPostApply();
|
virtual void inspectPostApply();
|
||||||
virtual void setTransform( const MatrixF & mat );
|
virtual void setTransform( const MatrixF & mat );
|
||||||
virtual F32 distanceTo( const Point3F& point ) const;
|
virtual F32 distanceTo( const Point3F& point ) const;
|
||||||
|
virtual bool buildPolyList( PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& sphere );
|
||||||
|
|
||||||
// WaterObject
|
// WaterObject
|
||||||
virtual F32 getWaterCoverage( const Box3F &worldBox ) const;
|
virtual F32 getWaterCoverage( const Box3F &worldBox ) const;
|
||||||
|
|
|
||||||
344
Engine/source/navigation/coverPoint.cpp
Normal file
|
|
@ -0,0 +1,344 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "coverPoint.h"
|
||||||
|
|
||||||
|
#include "math/mathIO.h"
|
||||||
|
#include "scene/sceneRenderState.h"
|
||||||
|
#include "core/stream/bitStream.h"
|
||||||
|
#include "materials/sceneData.h"
|
||||||
|
#include "gfx/gfxDebugEvent.h"
|
||||||
|
#include "gfx/gfxTransformSaver.h"
|
||||||
|
#include "gfx/gfxDrawUtil.h"
|
||||||
|
#include "renderInstance/renderPassManager.h"
|
||||||
|
#include "console/engineAPI.h"
|
||||||
|
|
||||||
|
extern bool gEditingMission;
|
||||||
|
|
||||||
|
IMPLEMENT_CO_NETOBJECT_V1(CoverPoint);
|
||||||
|
|
||||||
|
ConsoleDocClass(CoverPoint,
|
||||||
|
"@brief A type of marker that designates a location AI characters can take cover.\n\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
ImplementEnumType(CoverPointSize,
|
||||||
|
"The size of a cover point.\n")
|
||||||
|
{ CoverPoint::Prone, "Prone", "Only provides cover when prone.\n" },
|
||||||
|
{ CoverPoint::Crouch, "Crouch", "Only provides cover when crouching.\n" },
|
||||||
|
{ CoverPoint::Stand, "Stand", "Provides cover when standing.\n" },
|
||||||
|
EndImplementEnumType;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Object setup and teardown
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
CoverPoint::CoverPoint()
|
||||||
|
{
|
||||||
|
mNetFlags.clear(Ghostable);
|
||||||
|
mTypeMask |= MarkerObjectType;
|
||||||
|
mSize = Stand;
|
||||||
|
mQuality = 1.0f;
|
||||||
|
mOccupied = false;
|
||||||
|
mPeekLeft = false;
|
||||||
|
mPeekRight = false;
|
||||||
|
mPeekOver = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoverPoint::~CoverPoint()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Object Editing
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void CoverPoint::initPersistFields()
|
||||||
|
{
|
||||||
|
addGroup("CoverPoint");
|
||||||
|
|
||||||
|
addField("size", TYPEID<CoverPointSize>(), Offset(mSize, CoverPoint),
|
||||||
|
"The size of this cover point.");
|
||||||
|
|
||||||
|
addField("quality", TypeF32, Offset(mQuality, CoverPoint),
|
||||||
|
"Reliability of this point as solid cover. (0...1)");
|
||||||
|
|
||||||
|
addField("peekLeft", TypeBool, Offset(mPeekLeft, CoverPoint),
|
||||||
|
"Can characters look left around this cover point?");
|
||||||
|
addField("peekRight", TypeBool, Offset(mPeekRight, CoverPoint),
|
||||||
|
"Can characters look right around this cover point?");
|
||||||
|
addField("peekOver", TypeBool, Offset(mPeekOver, CoverPoint),
|
||||||
|
"Can characters look over the top of this cover point?");
|
||||||
|
|
||||||
|
endGroup("CoverPoint");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CoverPoint::onAdd()
|
||||||
|
{
|
||||||
|
if(!Parent::onAdd())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Set up a 1x1x1 bounding box
|
||||||
|
mObjBox.set(Point3F(-0.5f, -0.5f, -0.5f),
|
||||||
|
Point3F( 0.5f, 0.5f, 0.5f));
|
||||||
|
resetWorldBox();
|
||||||
|
|
||||||
|
if(gEditingMission)
|
||||||
|
onEditorEnable();
|
||||||
|
|
||||||
|
addToScene();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverPoint::onRemove()
|
||||||
|
{
|
||||||
|
if(gEditingMission)
|
||||||
|
onEditorDisable();
|
||||||
|
|
||||||
|
removeFromScene();
|
||||||
|
|
||||||
|
Parent::onRemove();
|
||||||
|
|
||||||
|
for(U32 i = 0; i < NumSizes; i++)
|
||||||
|
smVertexBuffer[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverPoint::setTransform(const MatrixF & mat)
|
||||||
|
{
|
||||||
|
Parent::setTransform(mat);
|
||||||
|
setMaskBits(TransformMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverPoint::onEditorEnable()
|
||||||
|
{
|
||||||
|
mNetFlags.set(Ghostable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverPoint::onEditorDisable()
|
||||||
|
{
|
||||||
|
mNetFlags.clear(Ghostable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverPoint::inspectPostApply()
|
||||||
|
{
|
||||||
|
setMaskBits(TransformMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 CoverPoint::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
|
||||||
|
{
|
||||||
|
U32 retMask = Parent::packUpdate(conn, mask, stream);
|
||||||
|
|
||||||
|
stream->writeInt(mSize, 4);
|
||||||
|
|
||||||
|
stream->writeFlag(mOccupied);
|
||||||
|
|
||||||
|
stream->writeFlag(peekLeft());
|
||||||
|
stream->writeFlag(peekRight());
|
||||||
|
stream->writeFlag(peekOver());
|
||||||
|
|
||||||
|
// Write our transform information
|
||||||
|
if(stream->writeFlag(mask & TransformMask))
|
||||||
|
{
|
||||||
|
mathWrite(*stream, getTransform());
|
||||||
|
mathWrite(*stream, getScale());
|
||||||
|
}
|
||||||
|
|
||||||
|
return retMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverPoint::unpackUpdate(NetConnection *conn, BitStream *stream)
|
||||||
|
{
|
||||||
|
Parent::unpackUpdate(conn, stream);
|
||||||
|
|
||||||
|
mSize = (Size)stream->readInt(4);
|
||||||
|
|
||||||
|
setOccupied(stream->readFlag());
|
||||||
|
|
||||||
|
mPeekLeft = stream->readFlag();
|
||||||
|
mPeekRight = stream->readFlag();
|
||||||
|
mPeekOver = stream->readFlag();
|
||||||
|
|
||||||
|
if(stream->readFlag()) // TransformMask
|
||||||
|
{
|
||||||
|
mathRead(*stream, &mObjToWorld);
|
||||||
|
mathRead(*stream, &mObjScale);
|
||||||
|
|
||||||
|
setTransform(mObjToWorld);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Functionality
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Point3F CoverPoint::getNormal() const
|
||||||
|
{
|
||||||
|
return getTransform().getForwardVector();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(CoverPoint, isOccupied, bool, (),,
|
||||||
|
"@brief Returns true if someone is already using this cover point.")
|
||||||
|
{
|
||||||
|
return object->isOccupied();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Object Rendering
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
GFXStateBlockRef CoverPoint::smNormalSB;
|
||||||
|
GFXVertexBufferHandle<CoverPoint::VertexType> CoverPoint::smVertexBuffer[CoverPoint::NumSizes];
|
||||||
|
|
||||||
|
void CoverPoint::initGFXResources()
|
||||||
|
{
|
||||||
|
if(smVertexBuffer[0] != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static const Point3F planePoints[4] =
|
||||||
|
{
|
||||||
|
Point3F(-1.0f, 0.0f, 0.0f), Point3F(-1.0f, 0.0f, 2.0f),
|
||||||
|
Point3F( 1.0f, 0.0f, 0.0f), Point3F( 1.0f, 0.0f, 2.0f),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const U32 planeFaces[6] =
|
||||||
|
{
|
||||||
|
0, 1, 2,
|
||||||
|
1, 2, 3
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Point3F scales[NumSizes] =
|
||||||
|
{
|
||||||
|
Point3F(1.0f, 1.0f, 0.5f), // Prone
|
||||||
|
Point3F(1.0f, 1.0f, 1.0f), // Crouch
|
||||||
|
Point3F(1.0f, 1.0f, 2.0f) // Stand
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ColorI colours[NumSizes] =
|
||||||
|
{
|
||||||
|
ColorI(180, 0, 0, 128), // Prone
|
||||||
|
ColorI(250, 200, 90, 128), // Crouch
|
||||||
|
ColorI( 80, 190, 20, 128) // Stand
|
||||||
|
};
|
||||||
|
|
||||||
|
for(U32 i = 0; i < NumSizes; i++)
|
||||||
|
{
|
||||||
|
// Fill the vertex buffer
|
||||||
|
VertexType *pVert = NULL;
|
||||||
|
smVertexBuffer[i].set(GFX, 6, GFXBufferTypeStatic);
|
||||||
|
|
||||||
|
pVert = smVertexBuffer[i].lock();
|
||||||
|
for(U32 j = 0; j < 6; j++)
|
||||||
|
{
|
||||||
|
pVert[j].point = planePoints[planeFaces[j]] * scales[i] * 0.5f;
|
||||||
|
pVert[j].normal = Point3F(0.0f, -1.0f, 0.0f);
|
||||||
|
pVert[j].color = colours[i];
|
||||||
|
}
|
||||||
|
smVertexBuffer[i].unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up our StateBlock
|
||||||
|
GFXStateBlockDesc desc;
|
||||||
|
desc.cullDefined = true;
|
||||||
|
desc.cullMode = GFXCullNone;
|
||||||
|
desc.setBlend(true);
|
||||||
|
smNormalSB = GFX->createStateBlock(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverPoint::prepRenderImage(SceneRenderState *state)
|
||||||
|
{
|
||||||
|
// Allocate an ObjectRenderInst so that we can submit it to the RenderPassManager
|
||||||
|
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
||||||
|
|
||||||
|
// Now bind our rendering function so that it will get called
|
||||||
|
ri->renderDelegate.bind(this, &CoverPoint::render);
|
||||||
|
|
||||||
|
// Set our RenderInst as a standard object render
|
||||||
|
ri->type = RenderPassManager::RIT_Editor;
|
||||||
|
|
||||||
|
// Set our sorting keys to a default value
|
||||||
|
ri->defaultKey = 0;
|
||||||
|
ri->defaultKey2 = 0;
|
||||||
|
|
||||||
|
// Submit our RenderInst to the RenderPassManager
|
||||||
|
state->getRenderPass()->addInst(ri);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverPoint::render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat)
|
||||||
|
{
|
||||||
|
initGFXResources();
|
||||||
|
|
||||||
|
if(overrideMat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(smVertexBuffer[mSize].isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
PROFILE_SCOPE(CoverPoint_Render);
|
||||||
|
|
||||||
|
// Set up a GFX debug event (this helps with debugging rendering events in external tools)
|
||||||
|
GFXDEBUGEVENT_SCOPE(CoverPoint_Render, ColorI::RED);
|
||||||
|
|
||||||
|
// GFXTransformSaver is a handy helper class that restores
|
||||||
|
// the current GFX matrices to their original values when
|
||||||
|
// it goes out of scope at the end of the function
|
||||||
|
GFXTransformSaver saver;
|
||||||
|
|
||||||
|
// Calculate our object to world transform matrix
|
||||||
|
MatrixF objectToWorld = getRenderTransform();
|
||||||
|
objectToWorld.scale(getScale());
|
||||||
|
|
||||||
|
// Apply our object transform
|
||||||
|
GFX->multWorld(objectToWorld);
|
||||||
|
|
||||||
|
// Set the state block
|
||||||
|
GFX->setStateBlock(smNormalSB);
|
||||||
|
|
||||||
|
// Set up the "generic" shaders
|
||||||
|
// These handle rendering on GFX layers that don't support
|
||||||
|
// fixed function. Otherwise they disable shaders.
|
||||||
|
GFX->setupGenericShaders(GFXDevice::GSModColorTexture);
|
||||||
|
|
||||||
|
// Set the vertex buffer
|
||||||
|
GFX->setVertexBuffer(smVertexBuffer[mSize]);
|
||||||
|
|
||||||
|
// Draw our triangles
|
||||||
|
GFX->drawPrimitive(GFXTriangleList, 0, 2);
|
||||||
|
|
||||||
|
// Data for decorations.
|
||||||
|
GFXStateBlockDesc desc;
|
||||||
|
F32 height = (float)(mSize + 1) / NumSizes * 2.0f;
|
||||||
|
|
||||||
|
// Draw an X if we're occupied.
|
||||||
|
if(isOccupied())
|
||||||
|
{
|
||||||
|
GFX->getDrawUtil()->drawArrow(desc, Point3F(-0.5, 0, 0), Point3F(0.5, 0, height), ColorI::RED);
|
||||||
|
GFX->getDrawUtil()->drawArrow(desc, Point3F(0.5, 0, 0), Point3F(-0.5, 0, height), ColorI::RED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw arrows to represent peek directions.
|
||||||
|
if(peekLeft())
|
||||||
|
GFX->getDrawUtil()->drawArrow(desc, Point3F(0, 0, height * 0.5), Point3F(-0.5, 0, height * 0.5), ColorI::GREEN);
|
||||||
|
if(peekRight())
|
||||||
|
GFX->getDrawUtil()->drawArrow(desc, Point3F(0, 0, height * 0.5), Point3F(0.5, 0, height * 0.5), ColorI::GREEN);
|
||||||
|
if(peekOver())
|
||||||
|
GFX->getDrawUtil()->drawArrow(desc, Point3F(0, 0, height * 0.5), Point3F(0, 0, height), ColorI::GREEN);
|
||||||
|
}
|
||||||
136
Engine/source/navigation/coverPoint.h
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _COVERPOINT_H_
|
||||||
|
#define _COVERPOINT_H_
|
||||||
|
|
||||||
|
#ifndef _SCENEOBJECT_H_
|
||||||
|
#include "scene/sceneObject.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _GFXSTATEBLOCK_H_
|
||||||
|
#include "gfx/gfxStateBlock.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _GFXVERTEXBUFFER_H_
|
||||||
|
#include "gfx/gfxVertexBuffer.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _GFXPRIMITIVEBUFFER_H_
|
||||||
|
#include "gfx/gfxPrimitiveBuffer.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class BaseMatInstance;
|
||||||
|
|
||||||
|
class CoverPoint : public SceneObject
|
||||||
|
{
|
||||||
|
typedef SceneObject Parent;
|
||||||
|
|
||||||
|
/// Network mask bits.
|
||||||
|
enum MaskBits
|
||||||
|
{
|
||||||
|
TransformMask = Parent::NextFreeMask << 0,
|
||||||
|
NextFreeMask = Parent::NextFreeMask << 1
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
CoverPoint();
|
||||||
|
virtual ~CoverPoint();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(CoverPoint);
|
||||||
|
|
||||||
|
/// Amount of cover provided at this point.
|
||||||
|
enum Size {
|
||||||
|
Prone,
|
||||||
|
Crouch,
|
||||||
|
Stand,
|
||||||
|
NumSizes
|
||||||
|
};
|
||||||
|
|
||||||
|
void setSize(Size size) { mSize = size; setMaskBits(TransformMask); }
|
||||||
|
Size getSize() const { return mSize; }
|
||||||
|
|
||||||
|
/// Is this point occupied?
|
||||||
|
bool isOccupied() const { return mOccupied; }
|
||||||
|
void setOccupied(bool occ) { mOccupied = occ; setMaskBits(TransformMask); }
|
||||||
|
|
||||||
|
/// Get the normal of this point (i.e., the direction from which it provides cover).
|
||||||
|
Point3F getNormal() const;
|
||||||
|
|
||||||
|
F32 getQuality() const { return mQuality; }
|
||||||
|
|
||||||
|
bool peekLeft() const { return mPeekLeft; }
|
||||||
|
bool peekRight() const { return mPeekRight; }
|
||||||
|
bool peekOver() const { return mPeekOver; }
|
||||||
|
|
||||||
|
void setPeek(bool left, bool right, bool over) { mPeekLeft = left, mPeekRight = right, mPeekOver = over; }
|
||||||
|
|
||||||
|
/// Init static buffers for rendering.
|
||||||
|
static void initGFXResources();
|
||||||
|
|
||||||
|
/// @name SceneObject
|
||||||
|
/// @{
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
bool onAdd();
|
||||||
|
void onRemove();
|
||||||
|
|
||||||
|
void onEditorEnable();
|
||||||
|
void onEditorDisable();
|
||||||
|
void inspectPostApply();
|
||||||
|
|
||||||
|
void setTransform(const MatrixF &mat);
|
||||||
|
|
||||||
|
void prepRenderImage(SceneRenderState *state);
|
||||||
|
void render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat);
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @name NetObject
|
||||||
|
/// @{
|
||||||
|
U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
|
||||||
|
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef GFXVertexPCN VertexType;
|
||||||
|
static GFXStateBlockRef smNormalSB;
|
||||||
|
static GFXVertexBufferHandle<VertexType> smVertexBuffer[NumSizes];
|
||||||
|
|
||||||
|
/// Size of this point.
|
||||||
|
Size mSize;
|
||||||
|
/// Quality of this point as cover.
|
||||||
|
F32 mQuality;
|
||||||
|
|
||||||
|
/// Can we look left around this cover?
|
||||||
|
bool mPeekLeft;
|
||||||
|
/// Can we look right around this cover?
|
||||||
|
bool mPeekRight;
|
||||||
|
/// Can we look up over this cover?
|
||||||
|
bool mPeekOver;
|
||||||
|
|
||||||
|
/// Is this point currently occupied?
|
||||||
|
bool mOccupied;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef CoverPoint::Size CoverPointSize;
|
||||||
|
DefineEnumType(CoverPointSize);
|
||||||
|
|
||||||
|
#endif
|
||||||
641
Engine/source/navigation/guiNavEditorCtrl.cpp
Normal file
|
|
@ -0,0 +1,641 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "platform/platform.h"
|
||||||
|
#include "guiNavEditorCtrl.h"
|
||||||
|
#include "duDebugDrawTorque.h"
|
||||||
|
#include "console/engineAPI.h"
|
||||||
|
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "math/util/frustum.h"
|
||||||
|
#include "math/mathUtils.h"
|
||||||
|
#include "gfx/primBuilder.h"
|
||||||
|
#include "gfx/gfxDrawUtil.h"
|
||||||
|
#include "scene/sceneRenderState.h"
|
||||||
|
#include "scene/sceneManager.h"
|
||||||
|
#include "gui/core/guiCanvas.h"
|
||||||
|
#include "gui/buttons/guiButtonCtrl.h"
|
||||||
|
#include "gui/worldEditor/undoActions.h"
|
||||||
|
#include "T3D/gameBase/gameConnection.h"
|
||||||
|
|
||||||
|
IMPLEMENT_CONOBJECT(GuiNavEditorCtrl);
|
||||||
|
|
||||||
|
ConsoleDocClass(GuiNavEditorCtrl,
|
||||||
|
"@brief GUI tool that makes up the Navigation Editor\n\n"
|
||||||
|
"Editor use only.\n\n"
|
||||||
|
"@internal"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Each of the mode names directly correlates with the Nav Editor's tool palette.
|
||||||
|
const String GuiNavEditorCtrl::mSelectMode = "SelectMode";
|
||||||
|
const String GuiNavEditorCtrl::mLinkMode = "LinkMode";
|
||||||
|
const String GuiNavEditorCtrl::mCoverMode = "CoverMode";
|
||||||
|
const String GuiNavEditorCtrl::mTileMode = "TileMode";
|
||||||
|
const String GuiNavEditorCtrl::mTestMode = "TestMode";
|
||||||
|
|
||||||
|
GuiNavEditorCtrl::GuiNavEditorCtrl()
|
||||||
|
{
|
||||||
|
mMode = mSelectMode;
|
||||||
|
mIsDirty = false;
|
||||||
|
mStartDragMousePoint = InvalidMousePoint;
|
||||||
|
mMesh = NULL;
|
||||||
|
mCurTile = mTile = -1;
|
||||||
|
mPlayer = mCurPlayer = NULL;
|
||||||
|
mSpawnClass = mSpawnDatablock = "";
|
||||||
|
mLinkStart = Point3F::Max;
|
||||||
|
mLink = mCurLink = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiNavEditorCtrl::~GuiNavEditorCtrl()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorUndoAction::undo()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GuiNavEditorCtrl::onAdd()
|
||||||
|
{
|
||||||
|
if(!Parent::onAdd())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
GFXStateBlockDesc desc;
|
||||||
|
desc.fillMode = GFXFillSolid;
|
||||||
|
desc.setBlend(false);
|
||||||
|
desc.setZReadWrite(false, false);
|
||||||
|
desc.setCullMode(GFXCullNone);
|
||||||
|
|
||||||
|
mZDisableSB = GFX->createStateBlock(desc);
|
||||||
|
|
||||||
|
desc.setZReadWrite(true, true);
|
||||||
|
mZEnableSB = GFX->createStateBlock(desc);
|
||||||
|
|
||||||
|
SceneManager::getPreRenderSignal().notify(this, &GuiNavEditorCtrl::_prepRenderImage);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::initPersistFields()
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::onSleep()
|
||||||
|
{
|
||||||
|
Parent::onSleep();
|
||||||
|
|
||||||
|
//mMode = mSelectMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::selectMesh(NavMesh *mesh)
|
||||||
|
{
|
||||||
|
mesh->setSelected(true);
|
||||||
|
mMesh = mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(GuiNavEditorCtrl, selectMesh, void, (S32 id),,
|
||||||
|
"@brief Select a NavMesh object.")
|
||||||
|
{
|
||||||
|
NavMesh *obj;
|
||||||
|
if(Sim::findObject(id, obj))
|
||||||
|
object->selectMesh(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
S32 GuiNavEditorCtrl::getMeshId()
|
||||||
|
{
|
||||||
|
return mMesh.isNull() ? 0 : mMesh->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(GuiNavEditorCtrl, getMesh, S32, (),,
|
||||||
|
"@brief Select a NavMesh object.")
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
mCurTile = mTile = -1;
|
||||||
|
mLinkStart = Point3F::Max;
|
||||||
|
mLink = mCurLink = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(GuiNavEditorCtrl, deselect, void, (),,
|
||||||
|
"@brief Deselect whatever is currently selected in the editor.")
|
||||||
|
{
|
||||||
|
object->deselect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::deleteLink()
|
||||||
|
{
|
||||||
|
if(!mMesh.isNull() && mLink != -1)
|
||||||
|
{
|
||||||
|
mMesh->selectLink(mLink, false);
|
||||||
|
mMesh->deleteLink(mLink);
|
||||||
|
mLink = -1;
|
||||||
|
Con::executef(this, "onLinkDeselected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(GuiNavEditorCtrl, deleteLink, void, (),,
|
||||||
|
"@brief Delete the currently selected link.")
|
||||||
|
{
|
||||||
|
object->deleteLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::setLinkFlags(const LinkData &d)
|
||||||
|
{
|
||||||
|
if(mMode == mLinkMode && !mMesh.isNull() && mLink != -1)
|
||||||
|
{
|
||||||
|
mMesh->setLinkFlags(mLink, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(GuiNavEditorCtrl, setLinkFlags, void, (U32 flags),,
|
||||||
|
"@Brief Set jump and drop properties of the selected link.")
|
||||||
|
{
|
||||||
|
object->setLinkFlags(LinkData(flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::buildTile()
|
||||||
|
{
|
||||||
|
if(!mMesh.isNull() && mTile != -1)
|
||||||
|
mMesh->buildTile(mTile);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(GuiNavEditorCtrl, buildTile, void, (),,
|
||||||
|
"@brief Build the currently selected tile.")
|
||||||
|
{
|
||||||
|
object->buildTile();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = static_cast<AIPlayer*>(obj);
|
||||||
|
Con::executef(this, "onPlayerSelected", Con::getIntArg(mPlayer->mLinkTypes.getFlags()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
bool &visible,
|
||||||
|
const Gui3DMouseEvent &event_)
|
||||||
|
{
|
||||||
|
//cursor = mAddNodeCursor;
|
||||||
|
//visible = false;
|
||||||
|
|
||||||
|
cursor = NULL;
|
||||||
|
visible = false;
|
||||||
|
|
||||||
|
GuiCanvas *root = getRoot();
|
||||||
|
if(!root)
|
||||||
|
return;
|
||||||
|
|
||||||
|
S32 currCursor = PlatformCursorController::curArrow;
|
||||||
|
|
||||||
|
if(root->mCursorChanged == currCursor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PlatformWindow *window = root->getPlatformWindow();
|
||||||
|
PlatformCursorController *controller = window->getCursorController();
|
||||||
|
|
||||||
|
// We've already changed the cursor,
|
||||||
|
// so set it back before we change it again.
|
||||||
|
if(root->mCursorChanged != -1)
|
||||||
|
controller->popCursor();
|
||||||
|
|
||||||
|
// Now change the cursor shape
|
||||||
|
controller->pushCursor(currCursor);
|
||||||
|
root->mCursorChanged = currCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GuiNavEditorCtrl::get3DCentre(Point3F &pos)
|
||||||
|
{
|
||||||
|
Point3F screen, start, end;
|
||||||
|
|
||||||
|
screen.set(getExtent().x / 2, getExtent().y / 2, 0);
|
||||||
|
unproject(screen, &start);
|
||||||
|
|
||||||
|
screen.z = 1.0f;
|
||||||
|
unproject(screen, &end);
|
||||||
|
|
||||||
|
RayInfo ri;
|
||||||
|
if(gServerContainer.castRay(start, end, StaticObjectType, &ri))
|
||||||
|
{
|
||||||
|
pos = ri.point;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
|
||||||
|
{
|
||||||
|
mGizmo->on3DMouseDown(event);
|
||||||
|
|
||||||
|
if(!isFirstResponder())
|
||||||
|
setFirstResponder();
|
||||||
|
|
||||||
|
mouseLock();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
bool alt = keys & SI_LALT;
|
||||||
|
|
||||||
|
if(mMode == mLinkMode && !mMesh.isNull())
|
||||||
|
{
|
||||||
|
if(gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
|
||||||
|
{
|
||||||
|
U32 link = mMesh->getLink(ri.point);
|
||||||
|
if(link != -1)
|
||||||
|
{
|
||||||
|
if(mLink != -1)
|
||||||
|
mMesh->selectLink(mLink, false);
|
||||||
|
mMesh->selectLink(link, true, false);
|
||||||
|
mLink = link;
|
||||||
|
LinkData d = mMesh->getLinkFlags(mLink);
|
||||||
|
Con::executef(this, "onLinkSelected", Con::getIntArg(d.getFlags()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(mLink != -1)
|
||||||
|
{
|
||||||
|
mMesh->selectLink(mLink, false);
|
||||||
|
mLink = -1;
|
||||||
|
Con::executef(this, "onLinkDeselected");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(mLinkStart != Point3F::Max)
|
||||||
|
{
|
||||||
|
mMesh->addLink(mLinkStart, ri.point);
|
||||||
|
if(!shift)
|
||||||
|
mLinkStart = Point3F::Max;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mLinkStart = ri.point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mMesh->selectLink(mLink, false);
|
||||||
|
mLink = -1;
|
||||||
|
Con::executef(this, "onLinkDeselected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mMode == mTileMode && !mMesh.isNull())
|
||||||
|
{
|
||||||
|
if(gServerContainer.castRay(startPnt, endPnt, StaticShapeObjectType, &ri))
|
||||||
|
{
|
||||||
|
mTile = mMesh->getTile(ri.point);
|
||||||
|
dd.clear();
|
||||||
|
mMesh->renderTileData(dd, mTile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, &ri))
|
||||||
|
{
|
||||||
|
if(dynamic_cast<AIPlayer*>(ri.object))
|
||||||
|
{
|
||||||
|
mPlayer = dynamic_cast<AIPlayer*>(ri.object);
|
||||||
|
Con::executef(this, "onPlayerSelected", Con::getIntArg(mPlayer->mLinkTypes.getFlags()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(!mPlayer.isNull() && gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
|
||||||
|
mPlayer->setPathDestination(ri.point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::on3DMouseUp(const Gui3DMouseEvent & event)
|
||||||
|
{
|
||||||
|
// Keep the Gizmo up to date.
|
||||||
|
mGizmo->on3DMouseUp(event);
|
||||||
|
|
||||||
|
mouseUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event)
|
||||||
|
{
|
||||||
|
//if(mSelRiver != NULL && mSelNode != -1)
|
||||||
|
//mGizmo->on3DMouseMove(event);
|
||||||
|
|
||||||
|
Point3F startPnt = event.pos;
|
||||||
|
Point3F endPnt = event.pos + event.vec * 1000.0f;
|
||||||
|
|
||||||
|
RayInfo ri;
|
||||||
|
|
||||||
|
if(mMode == mLinkMode && !mMesh.isNull())
|
||||||
|
{
|
||||||
|
if(gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
|
||||||
|
{
|
||||||
|
U32 link = mMesh->getLink(ri.point);
|
||||||
|
if(link != -1)
|
||||||
|
{
|
||||||
|
if(link != mLink)
|
||||||
|
{
|
||||||
|
if(mCurLink != -1)
|
||||||
|
mMesh->selectLink(mCurLink, false);
|
||||||
|
mMesh->selectLink(link, true, true);
|
||||||
|
}
|
||||||
|
mCurLink = link;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(mCurLink != mLink)
|
||||||
|
mMesh->selectLink(mCurLink, false);
|
||||||
|
mCurLink = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mMesh->selectLink(mCurLink, false);
|
||||||
|
mCurLink = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select a tile from our current NavMesh.
|
||||||
|
if(mMode == mTileMode && !mMesh.isNull())
|
||||||
|
{
|
||||||
|
if(gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
|
||||||
|
mCurTile = mMesh->getTile(ri.point);
|
||||||
|
else
|
||||||
|
mCurTile = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mMode == mTestMode)
|
||||||
|
{
|
||||||
|
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType, &ri))
|
||||||
|
mCurPlayer = dynamic_cast<AIPlayer*>(ri.object);
|
||||||
|
else
|
||||||
|
mCurPlayer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event)
|
||||||
|
{
|
||||||
|
mGizmo->on3DMouseDragged(event);
|
||||||
|
if(mGizmo->isDirty())
|
||||||
|
{
|
||||||
|
Point3F pos = mGizmo->getPosition();
|
||||||
|
Point3F scale = mGizmo->getScale();
|
||||||
|
const MatrixF &mat = mGizmo->getTransform();
|
||||||
|
VectorF normal;
|
||||||
|
mat.getColumn(2, &normal);
|
||||||
|
|
||||||
|
//mSelRiver->setNode(pos, scale.x, scale.z, normal, mSelNode);
|
||||||
|
mIsDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::on3DMouseEnter(const Gui3DMouseEvent & event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::on3DMouseLeave(const Gui3DMouseEvent & event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::updateGuiInfo()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::onRender(Point2I offset, const RectI &updateRect)
|
||||||
|
{
|
||||||
|
PROFILE_SCOPE(GuiNavEditorCtrl_OnRender);
|
||||||
|
|
||||||
|
Parent::onRender(offset, updateRect);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
GFX->setStateBlock(mZDisableSB);
|
||||||
|
|
||||||
|
// get the projected size...
|
||||||
|
GameConnection* connection = GameConnection::getConnectionToServer();
|
||||||
|
if(!connection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Grab the camera's transform
|
||||||
|
MatrixF mat;
|
||||||
|
connection->getControlCameraTransform(0, &mat);
|
||||||
|
|
||||||
|
// Get the camera position
|
||||||
|
Point3F camPos;
|
||||||
|
mat.getColumn(3,&camPos);
|
||||||
|
|
||||||
|
if(mMode == mLinkMode)
|
||||||
|
{
|
||||||
|
if(mLinkStart != Point3F::Max)
|
||||||
|
{
|
||||||
|
GFXStateBlockDesc desc;
|
||||||
|
desc.setBlend(false);
|
||||||
|
desc.setZReadWrite(true ,true);
|
||||||
|
MatrixF mat(true);
|
||||||
|
mat.setPosition(mLinkStart);
|
||||||
|
Point3F scale(0.8f, 0.8f, 0.8f);
|
||||||
|
GFX->getDrawUtil()->drawTransform(desc, mat, &scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mMode == mTileMode && !mMesh.isNull())
|
||||||
|
{
|
||||||
|
renderBoxOutline(mMesh->getTileBox(mCurTile), ColorI::BLUE);
|
||||||
|
renderBoxOutline(mMesh->getTileBox(mTile), ColorI::GREEN);
|
||||||
|
if(Con::getBoolVariable("$Nav::Editor::renderVoxels", false)) dd.renderGroup(0);
|
||||||
|
if(Con::getBoolVariable("$Nav::Editor::renderInput", false))
|
||||||
|
{
|
||||||
|
dd.depthMask(false);
|
||||||
|
dd.renderGroup(1);
|
||||||
|
dd.depthMask(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mMode == mTestMode)
|
||||||
|
{
|
||||||
|
if(!mCurPlayer.isNull())
|
||||||
|
renderBoxOutline(mCurPlayer->getWorldBox(), ColorI::BLUE);
|
||||||
|
if(!mPlayer.isNull())
|
||||||
|
renderBoxOutline(mPlayer->getWorldBox(), ColorI::GREEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
duDebugDrawTorque d;
|
||||||
|
if(!mMesh.isNull())
|
||||||
|
mMesh->renderLinks(d);
|
||||||
|
d.render();
|
||||||
|
|
||||||
|
// Now draw all the 2d stuff!
|
||||||
|
GFX->setClipRect(updateRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GuiNavEditorCtrl::getStaticPos(const Gui3DMouseEvent & event, Point3F &tpos)
|
||||||
|
{
|
||||||
|
// Find clicked point on the terrain
|
||||||
|
|
||||||
|
Point3F startPnt = event.pos;
|
||||||
|
Point3F endPnt = event.pos + event.vec * 1000.0f;
|
||||||
|
|
||||||
|
RayInfo ri;
|
||||||
|
bool hit;
|
||||||
|
|
||||||
|
hit = gServerContainer.castRay(startPnt, endPnt, StaticShapeObjectType, &ri);
|
||||||
|
tpos = ri.point;
|
||||||
|
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::setMode(String mode, bool sourceShortcut = false)
|
||||||
|
{
|
||||||
|
mMode = mode;
|
||||||
|
Con::executef(this, "onModeSet", mode);
|
||||||
|
|
||||||
|
if(sourceShortcut)
|
||||||
|
Con::executef(this, "paletteSync", mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::submitUndo(const UTF8 *name)
|
||||||
|
{
|
||||||
|
// Grab the mission editor undo manager.
|
||||||
|
UndoManager *undoMan = NULL;
|
||||||
|
if(!Sim::findObject("EUndoManager", undoMan))
|
||||||
|
{
|
||||||
|
Con::errorf("GuiNavEditorCtrl::submitUndo() - EUndoManager not found!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the action.
|
||||||
|
GuiNavEditorUndoAction *action = new GuiNavEditorUndoAction(name);
|
||||||
|
|
||||||
|
action->mNavEditor = this;
|
||||||
|
|
||||||
|
undoMan->addAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiNavEditorCtrl::_prepRenderImage(SceneManager* sceneGraph, const SceneRenderState* state)
|
||||||
|
{
|
||||||
|
/*if(isAwake() && River::smEditorOpen && mSelRiver)
|
||||||
|
{
|
||||||
|
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
||||||
|
ri->type = RenderPassManager::RIT_Editor;
|
||||||
|
ri->renderDelegate.bind(this, &GuiNavEditorCtrl::_renderSelectedRiver);
|
||||||
|
ri->defaultKey = 100;
|
||||||
|
state->getRenderPass()->addInst(ri);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod(GuiNavEditorCtrl, getMode, const char*, 2, 2, "")
|
||||||
|
{
|
||||||
|
return object->getMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleMethod(GuiNavEditorCtrl, setMode, void, 3, 3, "setMode(String mode)")
|
||||||
|
{
|
||||||
|
String newMode = (argv[2]);
|
||||||
|
object->setMode(newMode);
|
||||||
|
}
|
||||||
189
Engine/source/navigation/guiNavEditorCtrl.h
Normal file
|
|
@ -0,0 +1,189 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _GUINAVEDITORCTRL_H_
|
||||||
|
#define _GUINAVEDITORCTRL_H_
|
||||||
|
|
||||||
|
#ifndef _EDITTSCTRL_H_
|
||||||
|
#include "gui/worldEditor/editTSCtrl.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _UNDO_H_
|
||||||
|
#include "util/undo.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _GIZMO_H_
|
||||||
|
#include "gui/worldEditor/gizmo.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "navMesh.h"
|
||||||
|
#include "T3D/aiPlayer.h"
|
||||||
|
|
||||||
|
struct ObjectRenderInst;
|
||||||
|
class SceneManager;
|
||||||
|
class SceneRenderState;
|
||||||
|
class BaseMatInstance;
|
||||||
|
|
||||||
|
class GuiNavEditorCtrl : public EditTSCtrl
|
||||||
|
{
|
||||||
|
typedef EditTSCtrl Parent;
|
||||||
|
friend class GuiNavEditorUndoAction;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const String mSelectMode;
|
||||||
|
static const String mLinkMode;
|
||||||
|
static const String mCoverMode;
|
||||||
|
static const String mTileMode;
|
||||||
|
static const String mTestMode;
|
||||||
|
|
||||||
|
GuiNavEditorCtrl();
|
||||||
|
~GuiNavEditorCtrl();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(GuiNavEditorCtrl);
|
||||||
|
|
||||||
|
/// @name SimObject
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
bool onAdd();
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @name GuiControl
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
virtual void onSleep();
|
||||||
|
virtual void onRender(Point2I offset, const RectI &updateRect);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @name EditTSCtrl
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
void get3DCursor(GuiCursor *&cursor, bool &visible, const Gui3DMouseEvent &event_);
|
||||||
|
bool get3DCentre(Point3F &pos);
|
||||||
|
void on3DMouseDown(const Gui3DMouseEvent & event);
|
||||||
|
void on3DMouseUp(const Gui3DMouseEvent & event);
|
||||||
|
void on3DMouseMove(const Gui3DMouseEvent & event);
|
||||||
|
void on3DMouseDragged(const Gui3DMouseEvent & event);
|
||||||
|
void on3DMouseEnter(const Gui3DMouseEvent & event);
|
||||||
|
void on3DMouseLeave(const Gui3DMouseEvent & event);
|
||||||
|
void updateGuiInfo();
|
||||||
|
void renderScene(const RectI & updateRect);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @name GuiNavEditorCtrl
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
bool getStaticPos(const Gui3DMouseEvent & event, Point3F &tpos);
|
||||||
|
|
||||||
|
void setMode(String mode, bool sourceShortcut);
|
||||||
|
String getMode() { return mMode; }
|
||||||
|
|
||||||
|
void selectMesh(NavMesh *mesh);
|
||||||
|
void deselect();
|
||||||
|
|
||||||
|
S32 getMeshId();
|
||||||
|
S32 getPlayerId();
|
||||||
|
|
||||||
|
String mSpawnClass;
|
||||||
|
String mSpawnDatablock;
|
||||||
|
|
||||||
|
void deleteLink();
|
||||||
|
void setLinkFlags(const LinkData &d);
|
||||||
|
|
||||||
|
void buildTile();
|
||||||
|
|
||||||
|
void spawnPlayer(const Point3F &pos);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void _prepRenderImage(SceneManager* sceneGraph, const SceneRenderState* sceneState);
|
||||||
|
|
||||||
|
void submitUndo(const UTF8 *name = "Action");
|
||||||
|
|
||||||
|
GFXStateBlockRef mZDisableSB;
|
||||||
|
GFXStateBlockRef mZEnableSB;
|
||||||
|
|
||||||
|
bool mSavedDrag;
|
||||||
|
bool mIsDirty;
|
||||||
|
|
||||||
|
String mMode;
|
||||||
|
|
||||||
|
/// Currently-selected NavMesh.
|
||||||
|
SimObjectPtr<NavMesh> mMesh;
|
||||||
|
|
||||||
|
/// @name Link mode
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
Point3F mLinkStart;
|
||||||
|
S32 mCurLink;
|
||||||
|
S32 mLink;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @name Tile mode
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
S32 mCurTile;
|
||||||
|
S32 mTile;
|
||||||
|
|
||||||
|
duDebugDrawTorque dd;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @name Test mode
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
SimObjectPtr<AIPlayer> mPlayer;
|
||||||
|
SimObjectPtr<AIPlayer> mCurPlayer;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
Gui3DMouseEvent mLastMouseEvent;
|
||||||
|
|
||||||
|
#define InvalidMousePoint Point2I(-100,-100)
|
||||||
|
Point2I mStartDragMousePoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GuiNavEditorUndoAction : public UndoAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GuiNavEditorUndoAction(const UTF8* actionName) : UndoAction(actionName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiNavEditorCtrl *mNavEditor;
|
||||||
|
|
||||||
|
SimObjectId mObjId;
|
||||||
|
F32 mMetersPerSegment;
|
||||||
|
U32 mSegmentsPerBatch;
|
||||||
|
|
||||||
|
virtual void undo();
|
||||||
|
virtual void redo() { undo(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
69
Engine/source/navigation/navContext.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "navContext.h"
|
||||||
|
#include "console/sim.h"
|
||||||
|
|
||||||
|
void NavContext::doResetLog()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavContext::log(const rcLogCategory category, const String &msg)
|
||||||
|
{
|
||||||
|
doLog(category, msg.c_str(), msg.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavContext::doLog(const rcLogCategory category, const char* msg, const int len)
|
||||||
|
{
|
||||||
|
if(category == RC_LOG_ERROR)
|
||||||
|
Con::errorf(msg);
|
||||||
|
else
|
||||||
|
Con::printf(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavContext::doResetTimers()
|
||||||
|
{
|
||||||
|
for(U32 i = 0; i < RC_MAX_TIMERS; i++)
|
||||||
|
{
|
||||||
|
mTimers[i][0] = -1;
|
||||||
|
mTimers[i][1] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavContext::doStartTimer(const rcTimerLabel label)
|
||||||
|
{
|
||||||
|
// Store starting time.
|
||||||
|
mTimers[label][0] = Platform::getRealMilliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavContext::doStopTimer(const rcTimerLabel label)
|
||||||
|
{
|
||||||
|
// Compute final time based on starting time.
|
||||||
|
mTimers[label][1] = Platform::getRealMilliseconds() - mTimers[label][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int NavContext::doGetAccumulatedTime(const rcTimerLabel label) const
|
||||||
|
{
|
||||||
|
return mTimers[label][1] == -1
|
||||||
|
? Platform::getRealMilliseconds() - mTimers[label][0]
|
||||||
|
: mTimers[label][1];
|
||||||
|
}
|
||||||
68
Engine/source/navigation/navContext.h
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _NAV_CONTEXT_H_
|
||||||
|
#define _NAV_CONTEXT_H_
|
||||||
|
|
||||||
|
#include "torqueRecast.h"
|
||||||
|
#include <Recast.h>
|
||||||
|
|
||||||
|
/// @brief Implements the rcContext interface in Torque.
|
||||||
|
class NavContext: public rcContext {
|
||||||
|
public:
|
||||||
|
/// Default constructor.
|
||||||
|
NavContext() : rcContext(true) { doResetTimers(); }
|
||||||
|
|
||||||
|
void log(const rcLogCategory category, const String &msg);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// Clears all log entries.
|
||||||
|
virtual void doResetLog();
|
||||||
|
|
||||||
|
/// Logs a message.
|
||||||
|
/// @param[in] category The category of the message.
|
||||||
|
/// @param[in] msg The formatted message.
|
||||||
|
/// @param[in] len The length of the formatted message.
|
||||||
|
virtual void doLog(const rcLogCategory category, const char* msg, const int len);
|
||||||
|
|
||||||
|
/// Clears all timers. (Resets all to unused.)
|
||||||
|
virtual void doResetTimers();
|
||||||
|
|
||||||
|
/// Starts the specified performance timer.
|
||||||
|
/// @param[in] label The category of timer.
|
||||||
|
virtual void doStartTimer(const rcTimerLabel label);
|
||||||
|
|
||||||
|
/// Stops the specified performance timer.
|
||||||
|
/// @param[in] label The category of the timer.
|
||||||
|
virtual void doStopTimer(const rcTimerLabel label);
|
||||||
|
|
||||||
|
/// Returns the total accumulated time of the specified performance timer.
|
||||||
|
/// @param[in] label The category of the timer.
|
||||||
|
/// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started.
|
||||||
|
virtual int doGetAccumulatedTime(const rcTimerLabel label) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Store start time and final time for each timer.
|
||||||
|
S32 mTimers[RC_MAX_TIMERS][2];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Copyright (c) 2013 GarageGames, LLC
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
|
@ -25,16 +25,20 @@
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "torqueRecast.h"
|
|
||||||
#include "scene/sceneObject.h"
|
#include "scene/sceneObject.h"
|
||||||
|
#include "collision/concretePolyList.h"
|
||||||
#include "recastPolyList.h"
|
#include "recastPolyList.h"
|
||||||
|
#include "util/messaging/eventManager.h"
|
||||||
|
|
||||||
|
#include "torqueRecast.h"
|
||||||
#include "duDebugDrawTorque.h"
|
#include "duDebugDrawTorque.h"
|
||||||
|
#include "coverPoint.h"
|
||||||
|
|
||||||
#include <Recast.h>
|
#include <Recast.h>
|
||||||
#include <DetourNavMesh.h>
|
#include <DetourNavMesh.h>
|
||||||
#include <DetourNavMeshBuilder.h>
|
#include <DetourNavMeshBuilder.h>
|
||||||
#include <DebugDraw.h>
|
#include <DebugDraw.h>
|
||||||
|
#include <DetourNavMeshQuery.h>
|
||||||
|
|
||||||
/// @class NavMesh
|
/// @class NavMesh
|
||||||
/// Represents a set of bounds within which a Recast navigation mesh is generated.
|
/// Represents a set of bounds within which a Recast navigation mesh is generated.
|
||||||
|
|
@ -53,6 +57,10 @@ public:
|
||||||
bool build(bool background = true, bool saveIntermediates = false);
|
bool build(bool background = true, bool saveIntermediates = false);
|
||||||
/// Stop a build in progress.
|
/// Stop a build in progress.
|
||||||
void cancelBuild();
|
void cancelBuild();
|
||||||
|
/// Generate cover points from a nav mesh.
|
||||||
|
bool createCoverPoints();
|
||||||
|
/// Remove all cover points
|
||||||
|
void deleteCoverPoints();
|
||||||
|
|
||||||
/// Save the navmesh to a file.
|
/// Save the navmesh to a file.
|
||||||
bool save();
|
bool save();
|
||||||
|
|
@ -65,9 +73,15 @@ public:
|
||||||
/// Instantly rebuild a specific tile.
|
/// Instantly rebuild a specific tile.
|
||||||
void buildTile(const U32 &tile);
|
void buildTile(const U32 &tile);
|
||||||
|
|
||||||
|
/// Rebuild parts of the navmesh where links have changed.
|
||||||
|
void buildLinks();
|
||||||
|
|
||||||
/// Data file to store this nav mesh in. (From engine executable dir.)
|
/// Data file to store this nav mesh in. (From engine executable dir.)
|
||||||
StringTableEntry mFileName;
|
StringTableEntry mFileName;
|
||||||
|
|
||||||
|
/// Name of the SimSet to store cover points in. (Usually a SimGroup.)
|
||||||
|
StringTableEntry mCoverSet;
|
||||||
|
|
||||||
/// Cell width and height.
|
/// Cell width and height.
|
||||||
F32 mCellSize, mCellHeight;
|
F32 mCellSize, mCellHeight;
|
||||||
/// @name Actor data
|
/// @name Actor data
|
||||||
|
|
@ -90,6 +104,17 @@ public:
|
||||||
U32 mMaxPolysPerTile;
|
U32 mMaxPolysPerTile;
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
/// @name Water
|
||||||
|
/// @{
|
||||||
|
enum WaterMethod {
|
||||||
|
Ignore,
|
||||||
|
Solid,
|
||||||
|
Impassable
|
||||||
|
};
|
||||||
|
|
||||||
|
WaterMethod mWaterMethod;
|
||||||
|
/// @}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// Return the index of the tile included by this point.
|
/// Return the index of the tile included by this point.
|
||||||
|
|
@ -98,6 +123,68 @@ public:
|
||||||
/// Return the box of a given tile.
|
/// Return the box of a given tile.
|
||||||
Box3F getTileBox(U32 id);
|
Box3F getTileBox(U32 id);
|
||||||
|
|
||||||
|
/// @name Links
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Add an off-mesh link.
|
||||||
|
S32 addLink(const Point3F &from, const Point3F &to, U32 flags = 0);
|
||||||
|
|
||||||
|
/// Get the ID of the off-mesh link near the point.
|
||||||
|
S32 getLink(const Point3F &pos);
|
||||||
|
|
||||||
|
/// Get the number of links this mesh has.
|
||||||
|
S32 getLinkCount();
|
||||||
|
|
||||||
|
/// Get the starting point of a link.
|
||||||
|
Point3F getLinkStart(U32 idx);
|
||||||
|
|
||||||
|
/// Get the ending point of a link.
|
||||||
|
Point3F getLinkEnd(U32 idx);
|
||||||
|
|
||||||
|
/// Get the flags used by a link.
|
||||||
|
LinkData getLinkFlags(U32 idx);
|
||||||
|
|
||||||
|
/// Set flags used by a link.
|
||||||
|
void setLinkFlags(U32 idx, const LinkData &d);
|
||||||
|
|
||||||
|
/// Set the selected state of a link.
|
||||||
|
void selectLink(U32 idx, bool select, bool hover = true);
|
||||||
|
|
||||||
|
/// Delete the selected link.
|
||||||
|
void deleteLink(U32 idx);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// Should small characters use this mesh?
|
||||||
|
bool mSmallCharacters;
|
||||||
|
/// Should regular-sized characters use this mesh?
|
||||||
|
bool mRegularCharacters;
|
||||||
|
/// Should large characters use this mesh?
|
||||||
|
bool mLargeCharacters;
|
||||||
|
/// Should vehicles use this mesh?
|
||||||
|
bool mVehicles;
|
||||||
|
|
||||||
|
/// @name Annotations
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Should we automatically generate jump-down links?
|
||||||
|
bool mJumpDownLinks;
|
||||||
|
/// Height of a 'small' jump link.
|
||||||
|
F32 mJumpLinkSmall;
|
||||||
|
/// Height of a 'large' jump link.
|
||||||
|
F32 mJumpLinkLarge;
|
||||||
|
|
||||||
|
/// Distance to search for cover.
|
||||||
|
F32 mCoverDist;
|
||||||
|
|
||||||
|
/// Distance to search horizontally when peeking around cover.
|
||||||
|
F32 mPeekDist;
|
||||||
|
|
||||||
|
/// Add cover to walls that don't have corners?
|
||||||
|
bool mInnerCover;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
/// @name SimObject
|
/// @name SimObject
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
|
|
@ -142,6 +229,8 @@ public:
|
||||||
|
|
||||||
void prepRenderImage(SceneRenderState *state);
|
void prepRenderImage(SceneRenderState *state);
|
||||||
void render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat);
|
void render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat);
|
||||||
|
void renderLinks(duDebugDraw &dd);
|
||||||
|
void renderTileData(duDebugDrawTorque &dd, U32 tile);
|
||||||
|
|
||||||
bool mAlwaysRender;
|
bool mAlwaysRender;
|
||||||
|
|
||||||
|
|
@ -151,6 +240,12 @@ public:
|
||||||
~NavMesh();
|
~NavMesh();
|
||||||
DECLARE_CONOBJECT(NavMesh);
|
DECLARE_CONOBJECT(NavMesh);
|
||||||
|
|
||||||
|
/// Return the server-side NavMesh SimSet.
|
||||||
|
static SimSet *getServerSet();
|
||||||
|
|
||||||
|
/// Return the EventManager for all NavMeshes.
|
||||||
|
static EventManager *getEventManager();
|
||||||
|
|
||||||
void inspectPostApply();
|
void inspectPostApply();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -165,6 +260,9 @@ private:
|
||||||
/// Builds the next tile in the dirty list.
|
/// Builds the next tile in the dirty list.
|
||||||
void buildNextTile();
|
void buildNextTile();
|
||||||
|
|
||||||
|
/// Save imtermediate navmesh creation data?
|
||||||
|
bool mSaveIntermediates;
|
||||||
|
|
||||||
/// @name Tiles
|
/// @name Tiles
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
|
|
@ -223,6 +321,9 @@ private:
|
||||||
/// List of tiles.
|
/// List of tiles.
|
||||||
Vector<Tile> mTiles;
|
Vector<Tile> mTiles;
|
||||||
|
|
||||||
|
/// List of tile intermediate data.
|
||||||
|
Vector<TileData> mTileData;
|
||||||
|
|
||||||
/// List of indices to the tile array which are dirty.
|
/// List of indices to the tile array which are dirty.
|
||||||
std::queue<U32> mDirtyTiles;
|
std::queue<U32> mDirtyTiles;
|
||||||
|
|
||||||
|
|
@ -234,6 +335,33 @@ private:
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
/// @name Off-mesh links
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
enum SelectState {
|
||||||
|
Unselected,
|
||||||
|
Hovered,
|
||||||
|
Selected
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<F32> mLinkVerts; ///< Coordinates of each link vertex
|
||||||
|
Vector<bool> mLinksUnsynced; ///< Are the editor links unsynced from the mesh?
|
||||||
|
Vector<F32> mLinkRads; ///< Radius of each link
|
||||||
|
Vector<U8> mLinkDirs; ///< Direction (one-way or bidirectional)
|
||||||
|
Vector<U8> mLinkAreas; ///< Area ID
|
||||||
|
Vector<U16> mLinkFlags; ///< Flags
|
||||||
|
Vector<U32> mLinkIDs; ///< ID number of each link
|
||||||
|
Vector<U8> mLinkSelectStates; ///< Selection state of links
|
||||||
|
Vector<bool> mDeleteLinks; ///< Link will be deleted next build.
|
||||||
|
|
||||||
|
U32 mCurLinkID;
|
||||||
|
|
||||||
|
void eraseLink(U32 idx);
|
||||||
|
void eraseLinks();
|
||||||
|
void setLinkCount(U32 c);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
/// @name Intermediate data
|
/// @name Intermediate data
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
|
|
@ -244,6 +372,21 @@ private:
|
||||||
void updateConfig();
|
void updateConfig();
|
||||||
|
|
||||||
dtNavMesh *nm;
|
dtNavMesh *nm;
|
||||||
|
rcContext *ctx;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @name Cover
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
struct CoverPointData {
|
||||||
|
MatrixF trans;
|
||||||
|
CoverPoint::Size size;
|
||||||
|
bool peek[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Attempt to place cover points along a given edge.
|
||||||
|
bool testEdgeCover(const Point3F &pos, const VectorF &dir, CoverPointData &data);
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
@ -269,6 +412,15 @@ private:
|
||||||
void renderToDrawer();
|
void renderToDrawer();
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
/// Server-side set for all NavMesh objects.
|
||||||
|
static SimObjectPtr<SimSet> smServerSet;
|
||||||
|
|
||||||
|
/// Use this object to manage update events.
|
||||||
|
static SimObjectPtr<EventManager> smEventManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef NavMesh::WaterMethod NavMeshWaterMethod;
|
||||||
|
DefineEnumType(NavMeshWaterMethod);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Copyright (c) 2013 GarageGames, LLC
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
|
@ -22,10 +22,12 @@
|
||||||
|
|
||||||
#include "torqueRecast.h"
|
#include "torqueRecast.h"
|
||||||
#include "navPath.h"
|
#include "navPath.h"
|
||||||
|
#include "duDebugDrawTorque.h"
|
||||||
|
|
||||||
#include "console/consoleTypes.h"
|
#include "console/consoleTypes.h"
|
||||||
#include "console/engineAPI.h"
|
#include "console/engineAPI.h"
|
||||||
#include "console/typeValidators.h"
|
#include "console/typeValidators.h"
|
||||||
|
#include "math/mathTypes.h"
|
||||||
|
|
||||||
#include "scene/sceneRenderState.h"
|
#include "scene/sceneRenderState.h"
|
||||||
#include "gfx/gfxDrawUtil.h"
|
#include "gfx/gfxDrawUtil.h"
|
||||||
|
|
@ -44,8 +46,7 @@ NavPath::NavPath() :
|
||||||
mFrom(0.0f, 0.0f, 0.0f),
|
mFrom(0.0f, 0.0f, 0.0f),
|
||||||
mTo(0.0f, 0.0f, 0.0f)
|
mTo(0.0f, 0.0f, 0.0f)
|
||||||
{
|
{
|
||||||
mTypeMask |= StaticShapeObjectType | MarkerObjectType;
|
mTypeMask |= MarkerObjectType;
|
||||||
mNetFlags.clear(Ghostable);
|
|
||||||
|
|
||||||
mMesh = NULL;
|
mMesh = NULL;
|
||||||
mWaypoints = NULL;
|
mWaypoints = NULL;
|
||||||
|
|
@ -56,43 +57,51 @@ NavPath::NavPath() :
|
||||||
mToSet = false;
|
mToSet = false;
|
||||||
mLength = 0.0f;
|
mLength = 0.0f;
|
||||||
|
|
||||||
|
mCurIndex = -1;
|
||||||
mIsLooping = false;
|
mIsLooping = false;
|
||||||
|
mAutoUpdate = false;
|
||||||
|
mIsSliced = false;
|
||||||
|
|
||||||
|
mMaxIterations = 1;
|
||||||
|
|
||||||
mAlwaysRender = false;
|
mAlwaysRender = false;
|
||||||
mXray = false;
|
mXray = false;
|
||||||
|
mRenderSearch = false;
|
||||||
|
|
||||||
mQuery = dtAllocNavMeshQuery();
|
mQuery = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
NavPath::~NavPath()
|
NavPath::~NavPath()
|
||||||
{
|
{
|
||||||
// Required for Detour.
|
|
||||||
dtFreeNavMeshQuery(mQuery);
|
dtFreeNavMeshQuery(mQuery);
|
||||||
mQuery = NULL;
|
mQuery = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NavPath::setProtectedMesh(void *obj, const char *index, const char *data)
|
void NavPath::checkAutoUpdate()
|
||||||
{
|
{
|
||||||
NavMesh *mesh = NULL;
|
EventManager *em = NavMesh::getEventManager();
|
||||||
NavPath *object = static_cast<NavPath*>(obj);
|
em->removeAll(this);
|
||||||
|
if(mMesh)
|
||||||
if(Sim::findObject(data, mesh))
|
{
|
||||||
object->mMesh = mesh;
|
if(mAutoUpdate)
|
||||||
|
{
|
||||||
return false;
|
em->subscribe(this, "NavMeshRemoved");
|
||||||
|
em->subscribe(this, "NavMeshUpdate");
|
||||||
|
em->subscribe(this, "NavMeshUpdateBox");
|
||||||
|
em->subscribe(this, "NavMeshObstacleAdded");
|
||||||
|
em->subscribe(this, "NavMeshObstacleRemoved");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *NavPath::getProtectedMesh(void *obj, const char *data)
|
bool NavPath::setProtectedMesh(void *obj, const char *index, const char *data)
|
||||||
{
|
{
|
||||||
NavPath *object = static_cast<NavPath*>(obj);
|
NavPath *object = static_cast<NavPath*>(obj);
|
||||||
|
|
||||||
if(object->mMesh.isNull())
|
if(Sim::findObject(data, object->mMesh))
|
||||||
return "";
|
object->checkAutoUpdate();
|
||||||
|
|
||||||
if(object->mMesh->getName())
|
return true;
|
||||||
return object->mMesh->getName();
|
|
||||||
else
|
|
||||||
return object->mMesh->getIdString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NavPath::setProtectedWaypoints(void *obj, const char *index, const char *data)
|
bool NavPath::setProtectedWaypoints(void *obj, const char *index, const char *data)
|
||||||
|
|
@ -111,6 +120,16 @@ bool NavPath::setProtectedWaypoints(void *obj, const char *index, const char *da
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NavPath::setProtectedAutoUpdate(void *obj, const char *index, const char *data)
|
||||||
|
{
|
||||||
|
NavPath *object = static_cast<NavPath*>(obj);
|
||||||
|
|
||||||
|
object->mAutoUpdate = dAtob(data);
|
||||||
|
object->checkAutoUpdate();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool NavPath::setProtectedFrom(void *obj, const char *index, const char *data)
|
bool NavPath::setProtectedFrom(void *obj, const char *index, const char *data)
|
||||||
{
|
{
|
||||||
NavPath *object = static_cast<NavPath*>(obj);
|
NavPath *object = static_cast<NavPath*>(obj);
|
||||||
|
|
@ -150,7 +169,7 @@ const char *NavPath::getProtectedFrom(void *obj, const char *data)
|
||||||
if(object->mFromSet)
|
if(object->mFromSet)
|
||||||
return data;
|
return data;
|
||||||
else
|
else
|
||||||
return "";
|
return StringTable->insert("");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *NavPath::getProtectedTo(void *obj, const char *data)
|
const char *NavPath::getProtectedTo(void *obj, const char *data)
|
||||||
|
|
@ -160,29 +179,10 @@ const char *NavPath::getProtectedTo(void *obj, const char *data)
|
||||||
if(object->mToSet)
|
if(object->mToSet)
|
||||||
return data;
|
return data;
|
||||||
else
|
else
|
||||||
return "";
|
return StringTable->insert("");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NavPath::setProtectedAlwaysRender(void *obj, const char *index, const char *data)
|
IRangeValidator ValidIterations(1, S32_MAX);
|
||||||
{
|
|
||||||
NavPath *path = static_cast<NavPath*>(obj);
|
|
||||||
bool always = dAtob(data);
|
|
||||||
if(always)
|
|
||||||
{
|
|
||||||
if(!gEditingMission)
|
|
||||||
path->mNetFlags.set(Ghostable);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(!gEditingMission)
|
|
||||||
path->mNetFlags.clear(Ghostable);
|
|
||||||
}
|
|
||||||
path->mAlwaysRender = always;
|
|
||||||
path->setMaskBits(PathMask);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static IRangeValidator NaturalNumber(1, S32_MAX);
|
|
||||||
|
|
||||||
void NavPath::initPersistFields()
|
void NavPath::initPersistFields()
|
||||||
{
|
{
|
||||||
|
|
@ -195,25 +195,52 @@ void NavPath::initPersistFields()
|
||||||
&setProtectedTo, &getProtectedTo,
|
&setProtectedTo, &getProtectedTo,
|
||||||
"World location this path should end at.");
|
"World location this path should end at.");
|
||||||
|
|
||||||
addProtectedField("mesh", TYPEID<NavMesh>(), Offset(mMesh, NavPath),
|
addProtectedField("mesh", TypeRealString, Offset(mMeshName, NavPath),
|
||||||
&setProtectedMesh, &getProtectedMesh,
|
&setProtectedMesh, &defaultProtectedGetFn,
|
||||||
"NavMesh object this path travels within.");
|
"Name of the NavMesh object this path travels within.");
|
||||||
addProtectedField("waypoints", TYPEID<SimPath::Path>(), Offset(mWaypoints, NavPath),
|
addProtectedField("waypoints", TYPEID<SimPath::Path>(), Offset(mWaypoints, NavPath),
|
||||||
&setProtectedWaypoints, &defaultProtectedGetFn,
|
&setProtectedWaypoints, &defaultProtectedGetFn,
|
||||||
"Path containing waypoints for this NavPath to visit.");
|
"Path containing waypoints for this NavPath to visit.");
|
||||||
|
|
||||||
addField("isLooping", TypeBool, Offset(mIsLooping, NavPath),
|
addField("isLooping", TypeBool, Offset(mIsLooping, NavPath),
|
||||||
"Does this path loop?");
|
"Does this path loop?");
|
||||||
|
addField("isSliced", TypeBool, Offset(mIsSliced, NavPath),
|
||||||
|
"Plan this path over multiple updates instead of all at once.");
|
||||||
|
addFieldV("maxIterations", TypeS32, Offset(mMaxIterations, NavPath), &ValidIterations,
|
||||||
|
"Maximum iterations of path planning this path does per tick.");
|
||||||
|
addProtectedField("autoUpdate", TypeBool, Offset(mAutoUpdate, NavPath),
|
||||||
|
&setProtectedAutoUpdate, &defaultProtectedGetFn,
|
||||||
|
"If set, this path will automatically replan when its navigation mesh changes.");
|
||||||
|
|
||||||
endGroup("NavPath");
|
endGroup("NavPath");
|
||||||
|
|
||||||
|
addGroup("Flags");
|
||||||
|
|
||||||
|
addField("allowWalk", TypeBool, Offset(mLinkTypes.walk, NavPath),
|
||||||
|
"Allow the path to use dry land.");
|
||||||
|
addField("allowJump", TypeBool, Offset(mLinkTypes.jump, NavPath),
|
||||||
|
"Allow the path to use jump links.");
|
||||||
|
addField("allowDrop", TypeBool, Offset(mLinkTypes.drop, NavPath),
|
||||||
|
"Allow the path to use drop links.");
|
||||||
|
addField("allowSwim", TypeBool, Offset(mLinkTypes.swim, NavPath),
|
||||||
|
"Allow the path tomove in water.");
|
||||||
|
addField("allowLedge", TypeBool, Offset(mLinkTypes.ledge, NavPath),
|
||||||
|
"Allow the path to jump ledges.");
|
||||||
|
addField("allowClimb", TypeBool, Offset(mLinkTypes.climb, NavPath),
|
||||||
|
"Allow the path to use climb links.");
|
||||||
|
addField("allowTeleport", TypeBool, Offset(mLinkTypes.teleport, NavPath),
|
||||||
|
"Allow the path to use teleporters.");
|
||||||
|
|
||||||
|
endGroup("Flags");
|
||||||
|
|
||||||
addGroup("NavPath Render");
|
addGroup("NavPath Render");
|
||||||
|
|
||||||
addProtectedField("alwaysRender", TypeBool, Offset(mAlwaysRender, NavMesh),
|
addField("alwaysRender", TypeBool, Offset(mAlwaysRender, NavPath),
|
||||||
&setProtectedAlwaysRender, &defaultProtectedGetFn,
|
"Render this NavPath even when not selected.");
|
||||||
"Display this NavPath even outside the editor.");
|
|
||||||
addField("xray", TypeBool, Offset(mXray, NavPath),
|
addField("xray", TypeBool, Offset(mXray, NavPath),
|
||||||
"Render this NavPath through other objects.");
|
"Render this NavPath through other objects.");
|
||||||
|
addField("renderSearch", TypeBool, Offset(mRenderSearch, NavPath),
|
||||||
|
"Render the closed list of this NavPath's search.");
|
||||||
|
|
||||||
endGroup("NavPath Render");
|
endGroup("NavPath Render");
|
||||||
|
|
||||||
|
|
@ -225,59 +252,62 @@ bool NavPath::onAdd()
|
||||||
if(!Parent::onAdd())
|
if(!Parent::onAdd())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
addToScene();
|
if(gEditingMission)
|
||||||
|
|
||||||
// Ghost immediately if the editor's already open.
|
|
||||||
if(gEditingMission || mAlwaysRender)
|
|
||||||
mNetFlags.set(Ghostable);
|
mNetFlags.set(Ghostable);
|
||||||
|
|
||||||
// Automatically find a path if we can.
|
|
||||||
if(isServerObject())
|
|
||||||
plan();
|
|
||||||
|
|
||||||
// Set initial world bounds and stuff.
|
|
||||||
resize();
|
resize();
|
||||||
|
|
||||||
|
addToScene();
|
||||||
|
|
||||||
|
if(isServerObject())
|
||||||
|
{
|
||||||
|
mQuery = dtAllocNavMeshQuery();
|
||||||
|
if(!mQuery)
|
||||||
|
return false;
|
||||||
|
checkAutoUpdate();
|
||||||
|
if(!plan())
|
||||||
|
setProcessTick(true);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavPath::onRemove()
|
void NavPath::onRemove()
|
||||||
{
|
{
|
||||||
// Remove from simulation.
|
|
||||||
removeFromScene();
|
|
||||||
|
|
||||||
Parent::onRemove();
|
Parent::onRemove();
|
||||||
|
|
||||||
|
removeFromScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NavPath::init()
|
bool NavPath::init()
|
||||||
{
|
{
|
||||||
// Check that enough data is provided.
|
mStatus = DT_FAILURE;
|
||||||
if(mMesh.isNull() || !mMesh->getNavMesh())
|
|
||||||
|
// Check that all the right data is provided.
|
||||||
|
if(!mMesh || !mMesh->getNavMesh())
|
||||||
return false;
|
return false;
|
||||||
if(!(mFromSet && mToSet) && !(!mWaypoints.isNull() && mWaypoints->size()))
|
if(!(mFromSet && mToSet) && !(mWaypoints && mWaypoints->size()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Initialise query in Detour.
|
// Initialise our query.
|
||||||
if(dtStatusFailed(mQuery->init(mMesh->getNavMesh(), MaxPathLen)))
|
if(dtStatusFailed(mQuery->init(mMesh->getNavMesh(), MaxPathLen)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
mPoints.clear();
|
mPoints.clear();
|
||||||
|
mFlags.clear();
|
||||||
mVisitPoints.clear();
|
mVisitPoints.clear();
|
||||||
mLength = 0.0f;
|
mLength = 0.0f;
|
||||||
|
|
||||||
// Send path data to clients who are ghosting this object.
|
|
||||||
if(isServerObject())
|
if(isServerObject())
|
||||||
setMaskBits(PathMask);
|
setMaskBits(PathMask);
|
||||||
|
|
||||||
// Add points we need to visit in reverse order.
|
// Add points we need to visit in reverse order.
|
||||||
if(mWaypoints && mWaypoints->size())
|
if(mWaypoints && mWaypoints->size())
|
||||||
{
|
{
|
||||||
// Add destination. For looping paths, that includes 'from'.
|
|
||||||
if(mIsLooping && mFromSet)
|
if(mIsLooping && mFromSet)
|
||||||
mVisitPoints.push_back(mFrom);
|
mVisitPoints.push_back(mFrom);
|
||||||
if(mToSet)
|
if(mToSet)
|
||||||
mVisitPoints.push_front(mTo);
|
mVisitPoints.push_front(mTo);
|
||||||
// Add waypoints.
|
|
||||||
for(S32 i = mWaypoints->size() - 1; i >= 0; i--)
|
for(S32 i = mWaypoints->size() - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
SceneObject *s = dynamic_cast<SceneObject*>(mWaypoints->at(i));
|
SceneObject *s = dynamic_cast<SceneObject*>(mWaypoints->at(i));
|
||||||
|
|
@ -289,13 +319,11 @@ bool NavPath::init()
|
||||||
mVisitPoints.push_front(s->getPosition());
|
mVisitPoints.push_front(s->getPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add source (only ever specified by 'from').
|
|
||||||
if(mFromSet)
|
if(mFromSet)
|
||||||
mVisitPoints.push_back(mFrom);
|
mVisitPoints.push_back(mFrom);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Add (from,) to and from
|
|
||||||
if(mIsLooping)
|
if(mIsLooping)
|
||||||
mVisitPoints.push_back(mFrom);
|
mVisitPoints.push_back(mFrom);
|
||||||
mVisitPoints.push_back(mTo);
|
mVisitPoints.push_back(mTo);
|
||||||
|
|
@ -316,7 +344,6 @@ void NavPath::resize()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grow a box to just fit over all our points.
|
|
||||||
Point3F max(mPoints[0]), min(mPoints[0]), pos(0.0f);
|
Point3F max(mPoints[0]), min(mPoints[0]), pos(0.0f);
|
||||||
for(U32 i = 1; i < mPoints.size(); i++)
|
for(U32 i = 1; i < mPoints.size(); i++)
|
||||||
{
|
{
|
||||||
|
|
@ -341,20 +368,38 @@ void NavPath::resize()
|
||||||
|
|
||||||
bool NavPath::plan()
|
bool NavPath::plan()
|
||||||
{
|
{
|
||||||
|
// Initialise filter.
|
||||||
|
mFilter.setIncludeFlags(mLinkTypes.getFlags());
|
||||||
|
|
||||||
|
// Initialise query and visit locations.
|
||||||
if(!init())
|
if(!init())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(!visitNext())
|
if(mIsSliced)
|
||||||
return false;
|
return planSliced();
|
||||||
|
else
|
||||||
|
return planInstant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NavPath::planSliced()
|
||||||
|
{
|
||||||
|
bool visited = visitNext();
|
||||||
|
|
||||||
|
if(visited)
|
||||||
|
setProcessTick(true);
|
||||||
|
|
||||||
|
return visited;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NavPath::planInstant()
|
||||||
|
{
|
||||||
|
setProcessTick(false);
|
||||||
|
visitNext();
|
||||||
|
S32 store = mMaxIterations;
|
||||||
|
mMaxIterations = INT_MAX;
|
||||||
while(update());
|
while(update());
|
||||||
|
mMaxIterations = store;
|
||||||
if(!finalise())
|
return finalise();
|
||||||
return false;
|
|
||||||
|
|
||||||
resize();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NavPath::visitNext()
|
bool NavPath::visitNext()
|
||||||
|
|
@ -364,23 +409,32 @@ bool NavPath::visitNext()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Current leg of journey.
|
// Current leg of journey.
|
||||||
Point3F start = mVisitPoints[s-1];
|
Point3F &start = mVisitPoints[s-1];
|
||||||
Point3F end = mVisitPoints[s-2];
|
Point3F &end = mVisitPoints[s-2];
|
||||||
|
|
||||||
|
// Drop to height of statics.
|
||||||
|
RayInfo info;
|
||||||
|
if(getContainer()->castRay(start, start - Point3F(0, 0, mMesh->mWalkableHeight * 2.0f), StaticObjectType, &info))
|
||||||
|
start = info.point;
|
||||||
|
if(getContainer()->castRay(end + Point3F(0, 0, 0.1f), end - Point3F(0, 0, mMesh->mWalkableHeight * 2.0f), StaticObjectType, &info))
|
||||||
|
end = info.point;
|
||||||
|
|
||||||
// Convert to Detour-friendly coordinates and data structures.
|
// Convert to Detour-friendly coordinates and data structures.
|
||||||
F32 from[] = {start.x, start.z, -start.y};
|
F32 from[] = {start.x, start.z, -start.y};
|
||||||
F32 to[] = {end.x, end.z, -end.y};
|
F32 to[] = {end.x, end.z, -end.y};
|
||||||
F32 extents[] = {1.0f, 1.0f, 1.0f};
|
F32 extx = mMesh->mWalkableRadius * 4.0f;
|
||||||
|
F32 extz = mMesh->mWalkableHeight;
|
||||||
|
F32 extents[] = {extx, extz, extx};
|
||||||
dtPolyRef startRef, endRef;
|
dtPolyRef startRef, endRef;
|
||||||
|
|
||||||
if(dtStatusFailed(mQuery->findNearestPoly(from, extents, &mFilter, &startRef, from)) || !startRef)
|
if(dtStatusFailed(mQuery->findNearestPoly(from, extents, &mFilter, &startRef, NULL)) || !startRef)
|
||||||
{
|
{
|
||||||
Con::errorf("No NavMesh polygon near visit point (%g, %g, %g) of NavPath %s",
|
Con::errorf("No NavMesh polygon near visit point (%g, %g, %g) of NavPath %s",
|
||||||
start.x, start.y, start.z, getIdString());
|
start.x, start.y, start.z, getIdString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dtStatusFailed(mQuery->findNearestPoly(to, extents, &mFilter, &endRef, to)) || !startRef)
|
if(dtStatusFailed(mQuery->findNearestPoly(to, extents, &mFilter, &endRef, NULL)) || !endRef)
|
||||||
{
|
{
|
||||||
Con::errorf("No NavMesh polygon near visit point (%g, %g, %g) of NavPath %s",
|
Con::errorf("No NavMesh polygon near visit point (%g, %g, %g) of NavPath %s",
|
||||||
end.x, end.y, end.z, getIdString());
|
end.x, end.y, end.z, getIdString());
|
||||||
|
|
@ -397,20 +451,16 @@ bool NavPath::visitNext()
|
||||||
|
|
||||||
bool NavPath::update()
|
bool NavPath::update()
|
||||||
{
|
{
|
||||||
// StatusInProgress means a query is underway.
|
|
||||||
if(dtStatusInProgress(mStatus))
|
if(dtStatusInProgress(mStatus))
|
||||||
mStatus = mQuery->updateSlicedFindPath(INT_MAX, NULL);
|
mStatus = mQuery->updateSlicedFindPath(mMaxIterations, NULL);
|
||||||
// StatusSucceeded means the query found its destination.
|
|
||||||
if(dtStatusSucceed(mStatus))
|
if(dtStatusSucceed(mStatus))
|
||||||
{
|
{
|
||||||
// Finalize the path. Need to use the static path length cap again.
|
// Add points from this leg.
|
||||||
dtPolyRef path[MaxPathLen];
|
dtPolyRef path[MaxPathLen];
|
||||||
S32 pathLen;
|
S32 pathLen;
|
||||||
mStatus = mQuery->finalizeSlicedFindPath(path, &pathLen, MaxPathLen);
|
mStatus = mQuery->finalizeSlicedFindPath(path, &pathLen, MaxPathLen);
|
||||||
// Apparently stuff can go wrong during finalizing, so check the status again.
|
|
||||||
if(dtStatusSucceed(mStatus) && pathLen)
|
if(dtStatusSucceed(mStatus) && pathLen)
|
||||||
{
|
{
|
||||||
// These next few blocks are straight from Detour example code.
|
|
||||||
F32 straightPath[MaxPathLen * 3];
|
F32 straightPath[MaxPathLen * 3];
|
||||||
S32 straightPathLen;
|
S32 straightPathLen;
|
||||||
dtPolyRef straightPathPolys[MaxPathLen];
|
dtPolyRef straightPathPolys[MaxPathLen];
|
||||||
|
|
@ -422,19 +472,19 @@ bool NavPath::update()
|
||||||
F32 from[] = {start.x, start.z, -start.y};
|
F32 from[] = {start.x, start.z, -start.y};
|
||||||
F32 to[] = {end.x, end.z, -end.y};
|
F32 to[] = {end.x, end.z, -end.y};
|
||||||
|
|
||||||
// Straightens out the path.
|
|
||||||
mQuery->findStraightPath(from, to, path, pathLen,
|
mQuery->findStraightPath(from, to, path, pathLen,
|
||||||
straightPath, straightPathFlags,
|
straightPath, straightPathFlags,
|
||||||
straightPathPolys, &straightPathLen, MaxPathLen);
|
straightPathPolys, &straightPathLen, MaxPathLen);
|
||||||
|
|
||||||
// Convert Detour point path to list of Torque points.
|
|
||||||
s = mPoints.size();
|
s = mPoints.size();
|
||||||
mPoints.increment(straightPathLen);
|
mPoints.increment(straightPathLen);
|
||||||
|
mFlags.increment(straightPathLen);
|
||||||
for(U32 i = 0; i < straightPathLen; i++)
|
for(U32 i = 0; i < straightPathLen; i++)
|
||||||
{
|
{
|
||||||
F32 *f = straightPath + i * 3;
|
F32 *f = straightPath + i * 3;
|
||||||
mPoints[s + i] = RCtoDTS(f);
|
mPoints[s + i] = RCtoDTS(f);
|
||||||
// Accumulate length if we're not the first vertex.
|
mMesh->getNavMesh()->getPolyFlags(straightPathPolys[i], &mFlags[s + i]);
|
||||||
|
// Add to length
|
||||||
if(s > 0 || i > 0)
|
if(s > 0 || i > 0)
|
||||||
mLength += (mPoints[s+i] - mPoints[s+i-1]).len();
|
mLength += (mPoints[s+i] - mPoints[s+i-1]).len();
|
||||||
}
|
}
|
||||||
|
|
@ -467,30 +517,37 @@ bool NavPath::update()
|
||||||
|
|
||||||
bool NavPath::finalise()
|
bool NavPath::finalise()
|
||||||
{
|
{
|
||||||
// Stop ticking.
|
|
||||||
setProcessTick(false);
|
setProcessTick(false);
|
||||||
|
|
||||||
// Reset world bounds and stuff.
|
|
||||||
resize();
|
resize();
|
||||||
|
|
||||||
return dtStatusSucceed(mStatus);
|
return success();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavPath::processTick(const Move *move)
|
void NavPath::processTick(const Move *move)
|
||||||
{
|
{
|
||||||
|
if(!mMesh)
|
||||||
|
if(Sim::findObject(mMeshName.c_str(), mMesh))
|
||||||
|
plan();
|
||||||
if(dtStatusInProgress(mStatus))
|
if(dtStatusInProgress(mStatus))
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
Point3F NavPath::getNode(S32 idx)
|
Point3F NavPath::getNode(S32 idx) const
|
||||||
{
|
{
|
||||||
if(idx < getCount() && idx >= 0)
|
if(idx < size() && idx >= 0)
|
||||||
return mPoints[idx];
|
return mPoints[idx];
|
||||||
Con::errorf("Trying to access out-of-bounds path index %d (path length: %d)!", idx, getCount());
|
|
||||||
return Point3F(0,0,0);
|
return Point3F(0,0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
S32 NavPath::getCount()
|
U16 NavPath::getFlags(S32 idx) const
|
||||||
|
{
|
||||||
|
if(idx < size() && idx >= 0)
|
||||||
|
return mFlags[idx];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
S32 NavPath::size() const
|
||||||
{
|
{
|
||||||
return mPoints.size();
|
return mPoints.size();
|
||||||
}
|
}
|
||||||
|
|
@ -498,18 +555,11 @@ S32 NavPath::getCount()
|
||||||
void NavPath::onEditorEnable()
|
void NavPath::onEditorEnable()
|
||||||
{
|
{
|
||||||
mNetFlags.set(Ghostable);
|
mNetFlags.set(Ghostable);
|
||||||
if(isClientObject() && !mAlwaysRender)
|
|
||||||
addToScene();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavPath::onEditorDisable()
|
void NavPath::onEditorDisable()
|
||||||
{
|
{
|
||||||
if(!mAlwaysRender)
|
mNetFlags.clear(Ghostable);
|
||||||
{
|
|
||||||
mNetFlags.clear(Ghostable);
|
|
||||||
if(isClientObject())
|
|
||||||
removeFromScene();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavPath::inspectPostApply()
|
void NavPath::inspectPostApply()
|
||||||
|
|
@ -530,7 +580,7 @@ void NavPath::prepRenderImage(SceneRenderState *state)
|
||||||
{
|
{
|
||||||
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
||||||
ri->renderDelegate.bind(this, &NavPath::renderSimple);
|
ri->renderDelegate.bind(this, &NavPath::renderSimple);
|
||||||
ri->type = RenderPassManager::RIT_Object;
|
ri->type = RenderPassManager::RIT_Editor;
|
||||||
ri->translucentSort = true;
|
ri->translucentSort = true;
|
||||||
ri->defaultKey = 1;
|
ri->defaultKey = 1;
|
||||||
state->getRenderPass()->addInst(ri);
|
state->getRenderPass()->addInst(ri);
|
||||||
|
|
@ -577,6 +627,18 @@ void NavPath::renderSimple(ObjectRenderInst *ri, SceneRenderState *state, BaseMa
|
||||||
for (U32 i = 0; i < mPoints.size(); i++)
|
for (U32 i = 0; i < mPoints.size(); i++)
|
||||||
PrimBuild::vertex3fv(mPoints[i]);
|
PrimBuild::vertex3fv(mPoints[i]);
|
||||||
PrimBuild::end();
|
PrimBuild::end();
|
||||||
|
|
||||||
|
if(mRenderSearch && getServerObject())
|
||||||
|
{
|
||||||
|
NavPath *np = static_cast<NavPath*>(getServerObject());
|
||||||
|
if(np->mQuery && !dtStatusSucceed(np->mStatus))
|
||||||
|
{
|
||||||
|
duDebugDrawTorque dd;
|
||||||
|
dd.overrideColor(duRGBA(250, 20, 20, 255));
|
||||||
|
duDebugDrawNavMeshNodes(&dd, *np->mQuery);
|
||||||
|
dd.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 NavPath::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
|
U32 NavPath::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
|
||||||
|
|
@ -586,6 +648,7 @@ U32 NavPath::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
|
||||||
stream->writeFlag(mIsLooping);
|
stream->writeFlag(mIsLooping);
|
||||||
stream->writeFlag(mAlwaysRender);
|
stream->writeFlag(mAlwaysRender);
|
||||||
stream->writeFlag(mXray);
|
stream->writeFlag(mXray);
|
||||||
|
stream->writeFlag(mRenderSearch);
|
||||||
|
|
||||||
if(stream->writeFlag(mFromSet))
|
if(stream->writeFlag(mFromSet))
|
||||||
mathWrite(*stream, mFrom);
|
mathWrite(*stream, mFrom);
|
||||||
|
|
@ -596,7 +659,10 @@ U32 NavPath::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
|
||||||
{
|
{
|
||||||
stream->writeInt(mPoints.size(), 32);
|
stream->writeInt(mPoints.size(), 32);
|
||||||
for(U32 i = 0; i < mPoints.size(); i++)
|
for(U32 i = 0; i < mPoints.size(); i++)
|
||||||
|
{
|
||||||
mathWrite(*stream, mPoints[i]);
|
mathWrite(*stream, mPoints[i]);
|
||||||
|
stream->writeInt(mFlags[i], 16);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retMask;
|
return retMask;
|
||||||
|
|
@ -609,6 +675,7 @@ void NavPath::unpackUpdate(NetConnection *conn, BitStream *stream)
|
||||||
mIsLooping = stream->readFlag();
|
mIsLooping = stream->readFlag();
|
||||||
mAlwaysRender = stream->readFlag();
|
mAlwaysRender = stream->readFlag();
|
||||||
mXray = stream->readFlag();
|
mXray = stream->readFlag();
|
||||||
|
mRenderSearch = stream->readFlag();
|
||||||
|
|
||||||
if((mFromSet = stream->readFlag()) == true)
|
if((mFromSet = stream->readFlag()) == true)
|
||||||
mathRead(*stream, &mFrom);
|
mathRead(*stream, &mFrom);
|
||||||
|
|
@ -618,27 +685,55 @@ void NavPath::unpackUpdate(NetConnection *conn, BitStream *stream)
|
||||||
if(stream->readFlag())
|
if(stream->readFlag())
|
||||||
{
|
{
|
||||||
mPoints.clear();
|
mPoints.clear();
|
||||||
|
mFlags.clear();
|
||||||
mPoints.setSize(stream->readInt(32));
|
mPoints.setSize(stream->readInt(32));
|
||||||
|
mFlags.setSize(mPoints.size());
|
||||||
for(U32 i = 0; i < mPoints.size(); i++)
|
for(U32 i = 0; i < mPoints.size(); i++)
|
||||||
{
|
{
|
||||||
Point3F p;
|
Point3F p;
|
||||||
mathRead(*stream, &p);
|
mathRead(*stream, &p);
|
||||||
mPoints[i] = p;
|
mPoints[i] = p;
|
||||||
|
mFlags[i] = stream->readInt(16);
|
||||||
}
|
}
|
||||||
resize();
|
resize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DefineEngineMethod(NavPath, replan, bool, (),,
|
DefineEngineMethod(NavPath, plan, bool, (),,
|
||||||
"@brief Find a path using the already-specified path properties.")
|
"@brief Find a path using the already-specified path properties.")
|
||||||
{
|
{
|
||||||
return object->plan();
|
return object->plan();
|
||||||
}
|
}
|
||||||
|
|
||||||
DefineEngineMethod(NavPath, getCount, S32, (),,
|
DefineEngineMethod(NavPath, onNavMeshUpdate, void, (const char *data),,
|
||||||
|
"@brief Callback when this path's NavMesh is loaded or rebuilt.")
|
||||||
|
{
|
||||||
|
if(object->mMesh && !dStrcmp(data, object->mMesh->getIdString()))
|
||||||
|
object->plan();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(NavPath, onNavMeshUpdateBox, void, (const char *data),,
|
||||||
|
"@brief Callback when a particular area in this path's NavMesh is rebuilt.")
|
||||||
|
{
|
||||||
|
String s(data);
|
||||||
|
U32 space = s.find(' ');
|
||||||
|
if(space != String::NPos)
|
||||||
|
{
|
||||||
|
String id = s.substr(0, space);
|
||||||
|
if(!object->mMesh || id.compare(object->mMesh->getIdString()))
|
||||||
|
return;
|
||||||
|
String boxstr = s.substr(space + 1);
|
||||||
|
Box3F box;
|
||||||
|
castConsoleTypeFromString(box, boxstr.c_str());
|
||||||
|
if(object->getWorldBox().isOverlapped(box))
|
||||||
|
object->plan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(NavPath, size, S32, (),,
|
||||||
"@brief Return the number of nodes in this path.")
|
"@brief Return the number of nodes in this path.")
|
||||||
{
|
{
|
||||||
return object->getCount();
|
return object->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
DefineEngineMethod(NavPath, getNode, Point3F, (S32 idx),,
|
DefineEngineMethod(NavPath, getNode, Point3F, (S32 idx),,
|
||||||
|
|
@ -647,8 +742,14 @@ DefineEngineMethod(NavPath, getNode, Point3F, (S32 idx),,
|
||||||
return object->getNode(idx);
|
return object->getNode(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(NavPath, getFlags, S32, (S32 idx),,
|
||||||
|
"@brief Get a specified node along the path.")
|
||||||
|
{
|
||||||
|
return (S32)object->getFlags(idx);
|
||||||
|
}
|
||||||
|
|
||||||
DefineEngineMethod(NavPath, getLength, F32, (),,
|
DefineEngineMethod(NavPath, getLength, F32, (),,
|
||||||
"@brief Get the length of this path in Torque units (i.e. the total distance it covers).")
|
"@brief Get the length of this path.")
|
||||||
{
|
{
|
||||||
return object->getLength();
|
return object->getLength();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Copyright (c) 2013 GarageGames, LLC
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
|
@ -30,33 +30,33 @@
|
||||||
|
|
||||||
class NavPath: public SceneObject {
|
class NavPath: public SceneObject {
|
||||||
typedef SceneObject Parent;
|
typedef SceneObject Parent;
|
||||||
/// Maximum size of Detour path.
|
static const U32 MaxPathLen = 2048;
|
||||||
static const U32 MaxPathLen = 1024;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @name NavPath
|
/// @name NavPath
|
||||||
/// Functions for planning and accessing the path.
|
/// Functions for planning and accessing the path.
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
SimObjectPtr<NavMesh> mMesh;
|
String mMeshName;
|
||||||
SimObjectPtr<SimPath::Path> mWaypoints;
|
NavMesh *mMesh;
|
||||||
|
SimPath::Path *mWaypoints;
|
||||||
|
|
||||||
/// Location to start at.
|
|
||||||
Point3F mFrom;
|
Point3F mFrom;
|
||||||
/// Has a starting location been set?
|
|
||||||
bool mFromSet;
|
bool mFromSet;
|
||||||
/// Location to end at.
|
|
||||||
Point3F mTo;
|
Point3F mTo;
|
||||||
/// Has an end been set?
|
|
||||||
bool mToSet;
|
bool mToSet;
|
||||||
|
|
||||||
/// This path should include a segment from the end to the start.
|
|
||||||
bool mIsLooping;
|
bool mIsLooping;
|
||||||
|
bool mAutoUpdate;
|
||||||
|
bool mIsSliced;
|
||||||
|
|
||||||
|
S32 mMaxIterations;
|
||||||
|
|
||||||
/// Render even when not selected in the editor.
|
|
||||||
bool mAlwaysRender;
|
bool mAlwaysRender;
|
||||||
/// Render on top of other objects.
|
|
||||||
bool mXray;
|
bool mXray;
|
||||||
|
bool mRenderSearch;
|
||||||
|
|
||||||
|
/// What sort of link types are we allowed to move on?
|
||||||
|
LinkData mLinkTypes;
|
||||||
|
|
||||||
/// Plan the path.
|
/// Plan the path.
|
||||||
bool plan();
|
bool plan();
|
||||||
|
|
@ -69,20 +69,28 @@ public:
|
||||||
/// @return True if the plan was successful overall.
|
/// @return True if the plan was successful overall.
|
||||||
bool finalise();
|
bool finalise();
|
||||||
|
|
||||||
|
/// Did the path plan successfully?
|
||||||
|
bool success() const { return dtStatusSucceed(mStatus); }
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// @name Path interface
|
/// @name Path interface
|
||||||
|
/// These functions are provided to make NavPath behave
|
||||||
|
/// similarly to the existing Path class, despite NavPath
|
||||||
|
/// not being a SimSet.
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/// Return world-space position of a path node.
|
|
||||||
/// @param[in] idx Node index to retrieve.
|
|
||||||
Point3F getNode(S32 idx);
|
|
||||||
|
|
||||||
/// Return the number of nodes in this path.
|
|
||||||
S32 getCount();
|
|
||||||
|
|
||||||
/// Return the length of this path.
|
/// Return the length of this path.
|
||||||
F32 getLength() { return mLength; };
|
F32 getLength() const { return mLength; };
|
||||||
|
|
||||||
|
/// Get the number of nodes in a path.
|
||||||
|
S32 size() const;
|
||||||
|
|
||||||
|
/// Return world-space position of a path node.
|
||||||
|
Point3F getNode(S32 idx) const;
|
||||||
|
|
||||||
|
/// Get the flags for a given path node.
|
||||||
|
U16 getFlags(S32 idx) const;
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
@ -128,39 +136,46 @@ private:
|
||||||
/// Create appropriate data structures and stuff.
|
/// Create appropriate data structures and stuff.
|
||||||
bool init();
|
bool init();
|
||||||
|
|
||||||
/// 'Visit' the most recent two points on our visit list.
|
/// Plan the path.
|
||||||
|
bool planInstant();
|
||||||
|
|
||||||
|
/// Start a sliced plan.
|
||||||
|
/// @return True if the plan initialised successfully.
|
||||||
|
bool planSliced();
|
||||||
|
|
||||||
|
/// Add points of the path between the two specified points.
|
||||||
|
//bool addPoints(Point3F from, Point3F to, Vector<Point3F> *points);
|
||||||
|
|
||||||
|
/// 'Visit' the last two points on our visit list.
|
||||||
bool visitNext();
|
bool visitNext();
|
||||||
|
|
||||||
/// Detour path query.
|
|
||||||
dtNavMeshQuery *mQuery;
|
dtNavMeshQuery *mQuery;
|
||||||
/// Current status of our Detour query.
|
|
||||||
dtStatus mStatus;
|
dtStatus mStatus;
|
||||||
/// Filter that provides the movement costs for paths.
|
|
||||||
dtQueryFilter mFilter;
|
dtQueryFilter mFilter;
|
||||||
|
S32 mCurIndex;
|
||||||
/// List of points the path should visit (waypoints, if you will).
|
|
||||||
Vector<Point3F> mVisitPoints;
|
|
||||||
/// List of points in the final path.
|
|
||||||
Vector<Point3F> mPoints;
|
Vector<Point3F> mPoints;
|
||||||
|
Vector<U16> mFlags;
|
||||||
/// Total length of path in world units.
|
Vector<Point3F> mVisitPoints;
|
||||||
F32 mLength;
|
F32 mLength;
|
||||||
|
|
||||||
/// Resets our world transform and bounds to fit our point list.
|
/// Resets our world transform and bounds to fit our point list.
|
||||||
void resize();
|
void resize();
|
||||||
|
|
||||||
/// @name Protected console getters/setters
|
/// Function used to set mMesh object from console.
|
||||||
/// @{
|
|
||||||
static bool setProtectedMesh(void *obj, const char *index, const char *data);
|
static bool setProtectedMesh(void *obj, const char *index, const char *data);
|
||||||
static const char *getProtectedMesh(void *obj, const char *data);
|
|
||||||
|
/// Function used to set mWaypoints from console.
|
||||||
static bool setProtectedWaypoints(void *obj, const char *index, const char *data);
|
static bool setProtectedWaypoints(void *obj, const char *index, const char *data);
|
||||||
|
|
||||||
static bool setProtectedAlwaysRender(void *obj, const char *index, const char *data);
|
void checkAutoUpdate();
|
||||||
|
/// Function used to protect auto-update flag.
|
||||||
|
static bool setProtectedAutoUpdate(void *obj, const char *index, const char *data);
|
||||||
|
|
||||||
|
/// @name Protected from and to vectors
|
||||||
|
/// @{
|
||||||
static bool setProtectedFrom(void *obj, const char *index, const char *data);
|
static bool setProtectedFrom(void *obj, const char *index, const char *data);
|
||||||
static const char *getProtectedFrom(void *obj, const char *data);
|
|
||||||
|
|
||||||
static bool setProtectedTo(void *obj, const char *index, const char *data);
|
static bool setProtectedTo(void *obj, const char *index, const char *data);
|
||||||
|
static const char *getProtectedFrom(void *obj, const char *data);
|
||||||
static const char *getProtectedTo(void *obj, const char *data);
|
static const char *getProtectedTo(void *obj, const char *data);
|
||||||
/// @}
|
/// @}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ U32 RecastPolyList::addPoint(const Point3F &p)
|
||||||
verts = newverts;
|
verts = newverts;
|
||||||
}
|
}
|
||||||
Point3F v = p;
|
Point3F v = p;
|
||||||
|
v.convolve(mScale);
|
||||||
mMatrix.mulP(v);
|
mMatrix.mulP(v);
|
||||||
// Insert the new vertex.
|
// Insert the new vertex.
|
||||||
verts[nverts*3] = v.x;
|
verts[nverts*3] = v.x;
|
||||||
|
|
|
||||||
|
|
@ -69,4 +69,36 @@ enum PolyFlags {
|
||||||
AllFlags = 0xffff
|
AllFlags = 0xffff
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Stores information about a link.
|
||||||
|
struct LinkData {
|
||||||
|
bool walk;
|
||||||
|
bool jump;
|
||||||
|
bool drop;
|
||||||
|
bool swim;
|
||||||
|
bool ledge;
|
||||||
|
bool climb;
|
||||||
|
bool teleport;
|
||||||
|
LinkData(U16 flags = 0)
|
||||||
|
{
|
||||||
|
walk = flags & WalkFlag;
|
||||||
|
jump = flags & JumpFlag;
|
||||||
|
drop = flags & DropFlag;
|
||||||
|
swim = flags & SwimFlag;
|
||||||
|
ledge = flags & LedgeFlag;
|
||||||
|
climb = flags & ClimbFlag;
|
||||||
|
teleport = flags & TeleportFlag;
|
||||||
|
}
|
||||||
|
U16 getFlags() const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(walk ? WalkFlag : 0) |
|
||||||
|
(jump ? JumpFlag : 0) |
|
||||||
|
(drop ? DropFlag : 0) |
|
||||||
|
(swim ? SwimFlag : 0) |
|
||||||
|
(ledge ? LedgeFlag : 0) |
|
||||||
|
(climb ? ClimbFlag : 0) |
|
||||||
|
(teleport ? TeleportFlag : 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -562,7 +562,7 @@ bool TerrainBlock::buildPolyList(PolyListContext context, AbstractPolyList* poly
|
||||||
|
|
||||||
// Add the missing points
|
// Add the missing points
|
||||||
U32 vi[5];
|
U32 vi[5];
|
||||||
for (S32 i = 0; i < 4 ; i++)
|
for (int i = 0; i < 4 ; i++)
|
||||||
{
|
{
|
||||||
S32 dx = i >> 1;
|
S32 dx = i >> 1;
|
||||||
S32 dy = dx ^ (i & 1);
|
S32 dy = dx ^ (i & 1);
|
||||||
|
|
|
||||||
392
Templates/Empty/game/tools/navEditor/CreateNewNavMeshDlg.gui
Normal file
|
|
@ -0,0 +1,392 @@
|
||||||
|
//--- OBJECT WRITE BEGIN ---
|
||||||
|
%guiContent = new GuiControl(CreateNewNavMeshDlg) {
|
||||||
|
position = "0 0";
|
||||||
|
extent = "1024 768";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
|
||||||
|
new GuiWindowCtrl() {
|
||||||
|
text = "New NavMesh";
|
||||||
|
resizeWidth = "0";
|
||||||
|
resizeHeight = "0";
|
||||||
|
canMove = "1";
|
||||||
|
canClose = "1";
|
||||||
|
canMinimize = "0";
|
||||||
|
canMaximize = "0";
|
||||||
|
canCollapse = "0";
|
||||||
|
closeCommand = "Canvas.popDialog(CreateNewNavMeshDlg);";
|
||||||
|
edgeSnap = "1";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "283 240";
|
||||||
|
extent = "200 176";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiWindowProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Name:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "12 29";
|
||||||
|
extent = "39 21";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
historySize = "0";
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
text = "Nav";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "59 30";
|
||||||
|
extent = "129 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "MeshName";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Position:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "12 51";
|
||||||
|
extent = "39 21";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
historySize = "0";
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
text = "0 0 0";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "59 52";
|
||||||
|
extent = "129 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "MeshPosition";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Scale:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "12 73";
|
||||||
|
extent = "39 21";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
historySize = "0";
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
text = "50 50 20";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "59 74";
|
||||||
|
extent = "129 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "MeshScale";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl(MeshMissionBounds) {
|
||||||
|
text = " Fit NavMesh to mission area";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "1";
|
||||||
|
position = "22 99";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
tooltip = "Positions and scales the NavMesh so it includes all your mission objects.";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl(MeshTerrainBounds) {
|
||||||
|
text = " Include terrain";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
position = "22 121";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
tooltip = "Consider terrain when calculating NavMesh bounds.";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
text = "Create!";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
position = "12 146";
|
||||||
|
extent = "87 19";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiButtonProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
command = "CreateNewNavMeshDlg.create();";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
text = "Cancel";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
position = "104 146";
|
||||||
|
extent = "84 19";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiButtonProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
command = "Canvas.popDialog(CreateNewNavMeshDlg);";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
//--- OBJECT WRITE END ---
|
||||||
|
|
||||||
|
function CreateNewNavMeshDlg::onWake(%this)
|
||||||
|
{
|
||||||
|
%this-->MeshName.setText("Nav");
|
||||||
|
%this-->MeshPosition.setText("0 0 0");
|
||||||
|
%this-->MeshScale.setText("50 50 20");
|
||||||
|
MeshMissionBounds.setStateOn(false);
|
||||||
|
MeshTerrainBounds.setStateOn(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MissionBoundsExtents(%group)
|
||||||
|
{
|
||||||
|
%box = "0 0 0 0 0 0";
|
||||||
|
foreach(%obj in %group)
|
||||||
|
{
|
||||||
|
%cls = %obj.getClassName();
|
||||||
|
if(%cls $= "SimGroup" || %cls $= "SimSet" || %cls $= "Path")
|
||||||
|
{
|
||||||
|
// Need to recursively check grouped objects.
|
||||||
|
%wbox = MissionBoundsExtents(%obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Skip objects that are too big and shouldn't really be considered
|
||||||
|
// part of the scene, or are global bounds and we therefore can't get
|
||||||
|
// any sensible information out of them.
|
||||||
|
if(%cls $= "LevelInfo")
|
||||||
|
continue;
|
||||||
|
if(!MeshTerrainBounds.isStateOn() && %cls $= "TerrainBlock")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!(%obj.getType() & $TypeMasks::StaticObjectType) ||
|
||||||
|
%obj.getType() & $TypeMasks::EnvironmentObjectType)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(%obj.isGlobalBounds())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
%wbox = %obj.getWorldBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update min point.
|
||||||
|
for(%j = 0; %j < 3; %j++)
|
||||||
|
{
|
||||||
|
if(GetWord(%box, %j) > GetWord(%wbox, %j))
|
||||||
|
%box = SetWord(%box, %j, GetWord(%wbox, %j));
|
||||||
|
}
|
||||||
|
// Update max point.
|
||||||
|
for(%j = 3; %j < 6; %j++)
|
||||||
|
{
|
||||||
|
if(GetWord(%box, %j) < GetWord(%wbox, %j))
|
||||||
|
%box = SetWord(%box, %j, GetWord(%wbox, %j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return %box;
|
||||||
|
}
|
||||||
|
|
||||||
|
function CreateNewNavMeshDlg::create(%this)
|
||||||
|
{
|
||||||
|
%name = %this-->MeshName.getText();
|
||||||
|
if(%name $= "" || nameToID(%name) != -1)
|
||||||
|
{
|
||||||
|
MessageBoxOk("Error", "A NavMesh must have a unique name!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%mesh = 0;
|
||||||
|
|
||||||
|
if(MeshMissionBounds.isStateOn())
|
||||||
|
{
|
||||||
|
if(!isObject(MissionGroup))
|
||||||
|
{
|
||||||
|
MessageBoxOk("Error", "You must have a MissionGroup to use the mission bounds function.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Get maximum extents of all objects.
|
||||||
|
%box = MissionBoundsExtents(MissionGroup);
|
||||||
|
%pos = GetBoxCenter(%box);
|
||||||
|
%scale = (GetWord(%box, 3) - GetWord(%box, 0)) / 2 + 5
|
||||||
|
SPC (GetWord(%box, 4) - GetWord(%box, 1)) / 2 + 5
|
||||||
|
SPC (GetWord(%box, 5) - GetWord(%box, 2)) / 2 + 5;
|
||||||
|
|
||||||
|
%mesh = new NavMesh(%name)
|
||||||
|
{
|
||||||
|
position = %pos;
|
||||||
|
scale = %scale;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%mesh = new NavMesh(%name)
|
||||||
|
{
|
||||||
|
position = %this-->MeshPosition.getText();
|
||||||
|
scale = %this-->MeshScale.getText();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
MissionGroup.add(%mesh);
|
||||||
|
NavEditorGui.selectObject(%mesh);
|
||||||
|
|
||||||
|
Canvas.popDialog(CreateNewNavMeshDlg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MeshMissionBounds::onClick(%this)
|
||||||
|
{
|
||||||
|
MeshTerrainBounds.setActive(%this.isStateOn());
|
||||||
|
}
|
||||||
169
Templates/Empty/game/tools/navEditor/NavEditorConsoleDlg.gui
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
//--- OBJECT WRITE BEGIN ---
|
||||||
|
%guiContent = new GuiWindowCtrl(NavEditorConsoleDlg) {
|
||||||
|
text = "Nav Console";
|
||||||
|
resizeWidth = "1";
|
||||||
|
resizeHeight = "1";
|
||||||
|
canMove = "1";
|
||||||
|
canClose = "1";
|
||||||
|
canMinimize = "1";
|
||||||
|
canMaximize = "1";
|
||||||
|
canCollapse = "0";
|
||||||
|
closeCommand = "NavEditorConsoleDlg.setVisible(false);";
|
||||||
|
edgeSnap = "1";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "238 170";
|
||||||
|
extent = "320 240";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiWindowProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "3 222";
|
||||||
|
extent = "149 13";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "top";
|
||||||
|
profile = "GuiTextProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "StatusLeft";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiScrollCtrl() {
|
||||||
|
willFirstRespond = "1";
|
||||||
|
hScrollBar = "dynamic";
|
||||||
|
vScrollBar = "dynamic";
|
||||||
|
lockHorizScroll = "1";
|
||||||
|
lockVertScroll = "0";
|
||||||
|
constantThumbHeight = "0";
|
||||||
|
childMargin = "0 0";
|
||||||
|
mouseWheelScrollSpeed = "-1";
|
||||||
|
margin = "-14 41 3 3";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "0";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "0";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "3 23";
|
||||||
|
extent = "314 194";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "relative";
|
||||||
|
vertSizing = "relative";
|
||||||
|
profile = "GuiEditorScrollProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "OutputScroll";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiListBoxCtrl() {
|
||||||
|
allowMultipleSelections = "0";
|
||||||
|
fitParentWidth = "1";
|
||||||
|
colorBullet = "1";
|
||||||
|
position = "1 1";
|
||||||
|
extent = "312 16";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "relative";
|
||||||
|
vertSizing = "relative";
|
||||||
|
profile = "GuiListBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
internalName = "Output";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
//--- OBJECT WRITE END ---
|
||||||
|
|
||||||
|
new ScriptMsgListener(NavEditorConsoleListener);
|
||||||
|
getNavMeshEventManager().subscribe(NavEditorConsoleListener, "NavMeshCreated");
|
||||||
|
getNavMeshEventManager().subscribe(NavEditorConsoleListener, "NavMeshRemoved");
|
||||||
|
getNavMeshEventManager().subscribe(NavEditorConsoleListener, "NavMeshStartUpdate");
|
||||||
|
getNavMeshEventManager().subscribe(NavEditorConsoleListener, "NavMeshUpdate");
|
||||||
|
getNavMeshEventManager().subscribe(NavEditorConsoleListener, "NavMeshTileUpdate");
|
||||||
|
|
||||||
|
function NavEditorConsoleListener::onNavMeshCreated(%this, %data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorConsoleListener::onNavMeshRemoved(%this, %data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorConsoleListener::onNavMeshStartUpdate(%this, %data)
|
||||||
|
{
|
||||||
|
NavEditorConsoleDlg-->Output.clearItems();
|
||||||
|
NavEditorConsoleDlg-->Output.addItem("Build starting for NavMesh" SPC %data, "0 0.6 0");
|
||||||
|
NavEditorConsoleDlg-->OutputScroll.scrollToBottom();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorConsoleListener::onNavMeshUpdate(%this, %data)
|
||||||
|
{
|
||||||
|
%message = "";
|
||||||
|
if(getWordCount(%data) == 2)
|
||||||
|
{
|
||||||
|
%seconds = getWord(%data, 1);
|
||||||
|
%minutes = mFloor(%seconds / 60);
|
||||||
|
%seconds -= %minutes * 60;
|
||||||
|
%message = "Built NavMesh" SPC getWord(%data, 0) SPC "in" SPC %minutes @ "m" SPC mRound(%seconds) @ "s";
|
||||||
|
if(NavEditorGui.playSoundWhenDone)
|
||||||
|
{
|
||||||
|
sfxPlayOnce(Audio2D, "tools/navEditor/done.wav");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%message = "Loaded NavMesh" SPC %data;
|
||||||
|
}
|
||||||
|
NavEditorConsoleDlg-->Output.addItem(%message, "0 0.6 0");
|
||||||
|
NavEditorConsoleDlg-->OutputScroll.scrollToBottom();
|
||||||
|
NavEditorConsoleDlg->StatusLeft.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorConsoleListener::onNavMeshTileUpdate(%this, %data)
|
||||||
|
{
|
||||||
|
%mesh = getWord(%data, 0);
|
||||||
|
%index = getWord(%data, 1);
|
||||||
|
%total = getWord(%data, 2);
|
||||||
|
%tile = getWords(%data, 3, 4);
|
||||||
|
%success = getWord(%data, 5) == "1";
|
||||||
|
if(!%success)
|
||||||
|
{
|
||||||
|
%message = "NavMesh" SPC %mesh SPC "tile" SPC %tile SPC "build failed!";
|
||||||
|
NavEditorConsoleDlg-->Output.addItem(%message, "1 0 0");
|
||||||
|
NavEditorConsoleDlg-->OutputScroll.scrollToBottom();
|
||||||
|
}
|
||||||
|
%percent = %index / %total * 100;
|
||||||
|
NavEditorConsoleDlg->StatusLeft.setText("Build progress:" SPC mRound(%percent) @ "%");
|
||||||
|
}
|
||||||
854
Templates/Empty/game/tools/navEditor/NavEditorGui.gui
Normal file
|
|
@ -0,0 +1,854 @@
|
||||||
|
//--- OBJECT WRITE BEGIN ---
|
||||||
|
%guiContent = new GuiNavEditorCtrl(NavEditorGui, EditorGuiGroup) {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "NavEditorProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "height";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "800 600";
|
||||||
|
MinExtent = "8 8";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
Docking = "None";
|
||||||
|
Margin = "0 0 0 0";
|
||||||
|
Padding = "0 0 0 0";
|
||||||
|
AnchorTop = "0";
|
||||||
|
AnchorBottom = "0";
|
||||||
|
AnchorLeft = "0";
|
||||||
|
AnchorRight = "0";
|
||||||
|
cameraZRot = "0";
|
||||||
|
forceFOV = "0";
|
||||||
|
renderMissionArea = "0";
|
||||||
|
missionAreaFillColor = "255 0 0 20";
|
||||||
|
missionAreaFrameColor = "255 0 0 128";
|
||||||
|
allowBorderMove = "0";
|
||||||
|
borderMovePixelSize = "20";
|
||||||
|
borderMoveSpeed = "0.1";
|
||||||
|
consoleFrameColor = "255 0 0 255";
|
||||||
|
consoleFillColor = "0 0 0 0";
|
||||||
|
consoleSphereLevel = "1";
|
||||||
|
consoleCircleSegments = "32";
|
||||||
|
consoleLineWidth = "1";
|
||||||
|
GizmoProfile = "GlobalGizmoProfile";
|
||||||
|
|
||||||
|
new GuiWindowCollapseCtrl(NavEditorTreeWindow) {
|
||||||
|
internalName = "";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "GuiWindowProfile";
|
||||||
|
HorizSizing = "windowRelative";
|
||||||
|
VertSizing = "windowRelative";
|
||||||
|
Position = getWord($pref::Video::mode, 0) - 209
|
||||||
|
SPC getWord(EditorGuiToolbar.extent, 1) - 1;
|
||||||
|
Extent = "210 167";
|
||||||
|
MinExtent = "210 100";
|
||||||
|
canSave = "1";
|
||||||
|
isDecoy = "0";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
Margin = "0 0 0 0";
|
||||||
|
Padding = "0 0 0 0";
|
||||||
|
AnchorTop = "1";
|
||||||
|
AnchorBottom = "0";
|
||||||
|
AnchorLeft = "1";
|
||||||
|
AnchorRight = "0";
|
||||||
|
resizeWidth = "1";
|
||||||
|
resizeHeight = "1";
|
||||||
|
canMove = "1";
|
||||||
|
canClose = "0";
|
||||||
|
canMinimize = "0";
|
||||||
|
canMaximize = "0";
|
||||||
|
minSize = "50 50";
|
||||||
|
EdgeSnap = "1";
|
||||||
|
text = "Navigation";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
position = "115 2";
|
||||||
|
extent = "90 18";
|
||||||
|
text = "New NavMesh";
|
||||||
|
command = "Canvas.pushDialog(CreateNewNavMeshDlg);";
|
||||||
|
};
|
||||||
|
|
||||||
|
new GuiContainer(){
|
||||||
|
profile = GuiDefaultProfile;
|
||||||
|
Position = "5 25";
|
||||||
|
Extent = "200 120";
|
||||||
|
Docking = "Client";
|
||||||
|
Margin = "3 1 3 3 ";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "height";
|
||||||
|
isContainer = "1";
|
||||||
|
|
||||||
|
new GuiScrollCtrl() {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "GuiEditorScrollProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "height";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "200 118";
|
||||||
|
MinExtent = "8 8";
|
||||||
|
canSave = "1";
|
||||||
|
isDecoy = "0";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
Docking = "Client";
|
||||||
|
Margin = "0 0 0 0";
|
||||||
|
Padding = "0 0 0 0";
|
||||||
|
AnchorTop = "1";
|
||||||
|
AnchorBottom = "0";
|
||||||
|
AnchorLeft = "1";
|
||||||
|
AnchorRight = "0";
|
||||||
|
willFirstRespond = "1";
|
||||||
|
hScrollBar = "alwaysOff";
|
||||||
|
vScrollBar = "dynamic";
|
||||||
|
lockHorizScroll = "true";
|
||||||
|
lockVertScroll = "false";
|
||||||
|
constantThumbHeight = "0";
|
||||||
|
childMargin = "0 0";
|
||||||
|
mouseWheelScrollSpeed = "-1";
|
||||||
|
|
||||||
|
new GuiTreeViewCtrl(NavTreeView) {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "ToolsGuiTreeViewProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "1 1";
|
||||||
|
Extent = "193 21";
|
||||||
|
MinExtent = "8 8";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
hovertime = "1000";
|
||||||
|
tabSize = "16";
|
||||||
|
textOffset = "2";
|
||||||
|
fullRowSelect = "0";
|
||||||
|
itemHeight = "21";
|
||||||
|
destroyTreeOnSleep = "1";
|
||||||
|
MouseDragging = "0";
|
||||||
|
MultipleSelections = "0";
|
||||||
|
DeleteObjectAllowed = "1";
|
||||||
|
DragToItemAllowed = "0";
|
||||||
|
showRoot = "0";
|
||||||
|
internalNamesOnly = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiWindowCollapseCtrl(NavEditorOptionsWindow) {
|
||||||
|
internalName = "Window";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "GuiWindowProfile";
|
||||||
|
HorizSizing = "windowRelative";
|
||||||
|
VertSizing = "windowRelative";
|
||||||
|
Position = getWord($pref::Video::mode, 0) - 209
|
||||||
|
SPC getWord(EditorGuiToolbar.extent, 1) + getWord(NavEditorTreeWindow.extent, 1) - 2;
|
||||||
|
Extent = "210 530";
|
||||||
|
MinExtent = "210 300";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
Margin = "0 0 0 0";
|
||||||
|
Padding = "0 0 0 0";
|
||||||
|
AnchorTop = "0";
|
||||||
|
AnchorBottom = "0";
|
||||||
|
AnchorLeft = "0";
|
||||||
|
AnchorRight = "0";
|
||||||
|
resizeWidth = "1";
|
||||||
|
resizeHeight = "1";
|
||||||
|
canMove = "1";
|
||||||
|
canClose = "0";
|
||||||
|
canMinimize = "0";
|
||||||
|
canMaximize = "0";
|
||||||
|
minSize = "50 50";
|
||||||
|
EdgeSnap = "1";
|
||||||
|
text = "Properties";
|
||||||
|
|
||||||
|
new GuiContainer(){ //Actions
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "inspectorStyleRolloutDarkProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "4 24";
|
||||||
|
Extent = "202 85";
|
||||||
|
Docking = "Top";
|
||||||
|
Margin = "3 3 3 3";
|
||||||
|
internalName = "ActionsBox";
|
||||||
|
|
||||||
|
new GuiTextCtrl(){
|
||||||
|
Profile = "GuiDefaultProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "5 0";
|
||||||
|
Extent = "86 18";
|
||||||
|
text = "Actions";
|
||||||
|
};
|
||||||
|
new GuiStackControl()
|
||||||
|
{
|
||||||
|
internalName = "SelectActions";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "190 64";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "182 18";
|
||||||
|
text = "Build NavMesh";
|
||||||
|
command = "NavEditorGui.buildSelectedMeshes();";
|
||||||
|
};
|
||||||
|
new GuiControl() {
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
Extent = "182 20";
|
||||||
|
position = "0 20";
|
||||||
|
|
||||||
|
new GuiCheckboxCtrl() {
|
||||||
|
internalName = "BackgroundBuildButton";
|
||||||
|
text = "Background";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "75 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
variable = "NavEditorGui.backgroundBuild";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckboxCtrl() {
|
||||||
|
position = "75 0";
|
||||||
|
internalName = "SaveIntermediatesButton";
|
||||||
|
text = "Keep intermediates";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "105 20";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
variable = "NavEditorGui.saveIntermediates";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiCheckboxCtrl() {
|
||||||
|
internalName = "BuildSoundButton";
|
||||||
|
text = "Play sound when done";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "150 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
variable = "NavEditorGui.playSoundWhenDone";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiStackControl()
|
||||||
|
{
|
||||||
|
internalName = "LinkActions";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "190 64";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "182 18";
|
||||||
|
text = "Rebuild links";
|
||||||
|
command = "NavEditorGui.buildLinks();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiStackControl()
|
||||||
|
{
|
||||||
|
internalName = "CoverActions";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "190 64";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "182 18";
|
||||||
|
text = "Create Cover";
|
||||||
|
command = "NavEditorGui.createCoverPoints();";
|
||||||
|
};
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "182 18";
|
||||||
|
text = "Delete Cover";
|
||||||
|
command = "NavEditorGui.deleteCoverPoints();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiStackControl()
|
||||||
|
{
|
||||||
|
internalName = "TileActions";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "190 64";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "182 18";
|
||||||
|
text = "Rebuild tile";
|
||||||
|
command = "NavEditorGui.buildTile();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiStackControl()
|
||||||
|
{
|
||||||
|
internalName = "TestActions";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "190 64";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "180 18";
|
||||||
|
text = "Spawn";
|
||||||
|
command = "NavEditorGui.spawnPlayer();";
|
||||||
|
};
|
||||||
|
new GuiControl() {
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
Extent = "190 18";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "90 18";
|
||||||
|
text = "Delete";
|
||||||
|
command = "NavEditorGui.getPlayer().delete();";
|
||||||
|
};
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
position = "100 0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "90 18";
|
||||||
|
text = "Find cover";
|
||||||
|
command = "NavEditorGui.findCover();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiControl() {
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
Extent = "190 18";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "90 18";
|
||||||
|
text = "Follow";
|
||||||
|
command = "NavEditorGui.followObject();";
|
||||||
|
};
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
position = "100 0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "90 18";
|
||||||
|
text = "Stop";
|
||||||
|
command = "NavEditorGui.getPlayer().stop();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiContainer(){
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "inspectorStyleRolloutDarkProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "4 112";
|
||||||
|
Extent = "202 31";
|
||||||
|
Docking = "Top";
|
||||||
|
Margin = "0 0 3 3";
|
||||||
|
|
||||||
|
new GuiTextCtrl(){
|
||||||
|
Profile = "GuiDefaultProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "5 0";
|
||||||
|
Extent = "121 18";
|
||||||
|
text = "Properties";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
new GuiScrollCtrl() {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "GuiEditorScrollProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "height";
|
||||||
|
Position = "4 129";
|
||||||
|
Extent = "202 357";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
Docking = "Client";
|
||||||
|
Margin = "-14 41 3 3";
|
||||||
|
Padding = "0 0 0 0";
|
||||||
|
AnchorTop = "0";
|
||||||
|
AnchorBottom = "0";
|
||||||
|
AnchorLeft = "0";
|
||||||
|
AnchorRight = "0";
|
||||||
|
willFirstRespond = "1";
|
||||||
|
hScrollBar = "alwaysOff";
|
||||||
|
vScrollBar = "dynamic";
|
||||||
|
lockHorizScroll = "true";
|
||||||
|
lockVertScroll = "false";
|
||||||
|
constantThumbHeight = "0";
|
||||||
|
childMargin = "0 0";
|
||||||
|
internalName = "PropertiesBox";
|
||||||
|
|
||||||
|
new GuiInspector(NavInspector) {
|
||||||
|
StackingType = "Vertical";
|
||||||
|
HorizStacking = "Left to Right";
|
||||||
|
VertStacking = "Top to Bottom";
|
||||||
|
Padding = "1";
|
||||||
|
name = "NavInspector";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "GuiTransparentProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "height";
|
||||||
|
Position = "1 1";
|
||||||
|
Extent = "178 16";
|
||||||
|
MinExtent = "16 16";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
dividerMargin = "5";
|
||||||
|
};
|
||||||
|
|
||||||
|
new GuiStackControl() {
|
||||||
|
internalName = "LinkProperties";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "186 64";
|
||||||
|
padding = "2 2 2 2";
|
||||||
|
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkWalkFlag";
|
||||||
|
class = "NavMeshLinkFlagButton";
|
||||||
|
text = " Walk";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "This link is just ordinary flat ground.";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkJumpFlag";
|
||||||
|
class = "NavMeshLinkFlagButton";
|
||||||
|
text = " Jump";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Does this link require a jump?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkDropFlag";
|
||||||
|
class = "NavMeshLinkFlagButton";
|
||||||
|
text = " Drop";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Does this link involve a significant drop?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkLedgeFlag";
|
||||||
|
class = "NavMeshLinkFlagButton";
|
||||||
|
text = " Ledge";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Should the character jump at the next ledge?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkClimbFlag";
|
||||||
|
class = "NavMeshLinkFlagButton";
|
||||||
|
text = " Climb";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Does this link involve climbing?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkTeleportFlag";
|
||||||
|
class = "NavMeshLinkFlagButton";
|
||||||
|
text = " Teleport";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Is this link a teleporter?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiStackControl() {
|
||||||
|
internalName = "TileProperties";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "186 64";
|
||||||
|
padding = "2 2 2 2";
|
||||||
|
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
text = " Display input geometry";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
variable = "$Nav::Editor::renderInput";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
text = " Display voxels";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
variable = "$Nav::Editor::renderVoxels";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiStackControl() {
|
||||||
|
internalName = "TestProperties";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "186 64";
|
||||||
|
padding = "2 2 2 2";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Cover";
|
||||||
|
profile = "GuiTextProfile";
|
||||||
|
extent = "180 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
internalName = "CoverRadius";
|
||||||
|
text = "10";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
extent = "40 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Radius for cover-finding.";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
internalName = "CoverPosition";
|
||||||
|
text = "LocalClientConnection.getControlObject().getPosition();";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
extent = "140 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Position to find cover from.";
|
||||||
|
};
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Follow";
|
||||||
|
profile = "GuiTextProfile";
|
||||||
|
extent = "180 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
internalName = "FollowRadius";
|
||||||
|
text = "1";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
extent = "40 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Radius for following.";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
internalName = "FollowObject";
|
||||||
|
text = "LocalClientConnection.player";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
extent = "140 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Object to follow.";
|
||||||
|
};
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Movement";
|
||||||
|
profile = "GuiTextProfile";
|
||||||
|
extent = "180 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkWalkFlag";
|
||||||
|
class = "NavMeshTestFlagButton";
|
||||||
|
text = " Walk";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Can this character walk on ground?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkJumpFlag";
|
||||||
|
class = "NavMeshTestFlagButton";
|
||||||
|
text = " Jump";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Can this character jump?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkDropFlag";
|
||||||
|
class = "NavMeshTestFlagButton";
|
||||||
|
text = " Drop";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Can this character drop over edges?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkLedgeFlag";
|
||||||
|
class = "NavMeshTestFlagButton";
|
||||||
|
text = " Ledge";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Can this character jump from ledges?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkClimbFlag";
|
||||||
|
class = "NavMeshTestFlagButton";
|
||||||
|
text = " Climb";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Can this character climb?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkTeleportFlag";
|
||||||
|
class = "NavMeshTestFlagButton";
|
||||||
|
text = " Teleport";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Can this character teleport?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiMLTextCtrl(NavFieldInfoControl) {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "0";
|
||||||
|
Profile = "GuiInspectorFieldInfoMLTextProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "top";
|
||||||
|
Position = "1 485";
|
||||||
|
Extent = "202 42";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
lineSpacing = "2";
|
||||||
|
allowColorChars = "0";
|
||||||
|
maxChars = "-1";
|
||||||
|
useURLMouseCursor = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- OBJECT WRITE END ---
|
||||||
506
Templates/Empty/game/tools/navEditor/NavEditorSettingsTab.gui
Normal file
|
|
@ -0,0 +1,506 @@
|
||||||
|
//--- OBJECT WRITE BEGIN ---
|
||||||
|
%guiContent = new GuiTabPageCtrl(ENavEditorSettingsPage) {
|
||||||
|
fitBook = "1";
|
||||||
|
text = "Navigation Editor";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "0 0";
|
||||||
|
extent = "208 292";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "height";
|
||||||
|
profile = "GuiSolidDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
|
||||||
|
new GuiScrollCtrl() {
|
||||||
|
willFirstRespond = "1";
|
||||||
|
hScrollBar = "alwaysOff";
|
||||||
|
vScrollBar = "dynamic";
|
||||||
|
lockHorizScroll = "1";
|
||||||
|
lockVertScroll = "0";
|
||||||
|
constantThumbHeight = "0";
|
||||||
|
childMargin = "0 0";
|
||||||
|
mouseWheelScrollSpeed = "-1";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "0 0";
|
||||||
|
extent = "208 292";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "height";
|
||||||
|
profile = "GuiScrollProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiStackControl() {
|
||||||
|
stackingType = "Vertical";
|
||||||
|
horizStacking = "Left to Right";
|
||||||
|
vertStacking = "Top to Bottom";
|
||||||
|
padding = "0";
|
||||||
|
dynamicSize = "1";
|
||||||
|
dynamicNonStackExtent = "0";
|
||||||
|
dynamicPos = "0";
|
||||||
|
changeChildSizeToFit = "1";
|
||||||
|
changeChildPosition = "1";
|
||||||
|
position = "1 1";
|
||||||
|
extent = "206 124";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiRolloutCtrl() {
|
||||||
|
caption = "Test spawn";
|
||||||
|
margin = "0 3 0 0";
|
||||||
|
defaultHeight = "40";
|
||||||
|
expanded = "1";
|
||||||
|
clickCollapse = "1";
|
||||||
|
hideHeader = "0";
|
||||||
|
autoCollapseSiblings = "0";
|
||||||
|
position = "0 0";
|
||||||
|
extent = "206 62";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiRolloutProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiStackControl() {
|
||||||
|
stackingType = "Vertical";
|
||||||
|
horizStacking = "Left to Right";
|
||||||
|
vertStacking = "Top to Bottom";
|
||||||
|
padding = "3";
|
||||||
|
dynamicSize = "1";
|
||||||
|
dynamicNonStackExtent = "0";
|
||||||
|
dynamicPos = "0";
|
||||||
|
changeChildSizeToFit = "1";
|
||||||
|
changeChildPosition = "1";
|
||||||
|
position = "0 20";
|
||||||
|
extent = "206 39";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiControl() {
|
||||||
|
position = "0 0";
|
||||||
|
extent = "206 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Spawn class:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "5 1";
|
||||||
|
extent = "70 16";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiPopUpMenuCtrlEx() {
|
||||||
|
maxPopupHeight = "200";
|
||||||
|
sbUsesNAColor = "0";
|
||||||
|
reverseTextList = "0";
|
||||||
|
bitmapBounds = "16 16";
|
||||||
|
hotTrackCallback = "0";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "81 0";
|
||||||
|
extent = "121 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiPopUpMenuProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "SpawnClassOptions";
|
||||||
|
class = "ESettingsWindowPopup";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
editorSettingsRead = "NavEditorPlugin.readSettings();";
|
||||||
|
editorSettingsValue = "NavEditor/SpawnClass";
|
||||||
|
editorSettingsWrite = "NavEditorPlugin.writeSettings();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiControl() {
|
||||||
|
position = "0 21";
|
||||||
|
extent = "206 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Datablock:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "5 1";
|
||||||
|
extent = "70 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
historySize = "0";
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
text = "DefaultPlayerData";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "81 0";
|
||||||
|
extent = "121 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
class = "ESettingsWindowTextEdit";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
editorSettingsRead = "NavEditorPlugin.readSettings();";
|
||||||
|
editorSettingsValue = "NavEditor/SpawnDatablock";
|
||||||
|
editorSettingsWrite = "NavEditorPlugin.writeSettings();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiRolloutCtrl() {
|
||||||
|
caption = "Colors";
|
||||||
|
margin = "0 3 0 0";
|
||||||
|
defaultHeight = "40";
|
||||||
|
expanded = "1";
|
||||||
|
clickCollapse = "1";
|
||||||
|
hideHeader = "0";
|
||||||
|
autoCollapseSiblings = "0";
|
||||||
|
position = "0 62";
|
||||||
|
extent = "206 62";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiRolloutProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiStackControl() {
|
||||||
|
stackingType = "Vertical";
|
||||||
|
horizStacking = "Left to Right";
|
||||||
|
vertStacking = "Top to Bottom";
|
||||||
|
padding = "3";
|
||||||
|
dynamicSize = "1";
|
||||||
|
dynamicNonStackExtent = "0";
|
||||||
|
dynamicPos = "0";
|
||||||
|
changeChildSizeToFit = "1";
|
||||||
|
changeChildPosition = "1";
|
||||||
|
position = "0 20";
|
||||||
|
extent = "206 39";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiControl() {
|
||||||
|
position = "0 0";
|
||||||
|
extent = "206 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
class = "ESettingsWindowColor";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
editorSettingsRead = "NavEditorPlugin.readSettings();";
|
||||||
|
editorSettingsValue = "NavEditor/HoverSplineColor";
|
||||||
|
editorSettingsWrite = "NavEditorPlugin.writeSettings();";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Hover Spline:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "0 1";
|
||||||
|
extent = "70 16";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
historySize = "0";
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "80 0";
|
||||||
|
extent = "104 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
internalName = "ColorEdit";
|
||||||
|
class = "ESettingsWindowColorEdit";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
};
|
||||||
|
new GuiSwatchButtonCtrl() {
|
||||||
|
color = "0 0 0 0";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
position = "188 2";
|
||||||
|
extent = "14 14";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "left";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
internalName = "ColorButton";
|
||||||
|
class = "ESettingsWindowColorButton";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiControl() {
|
||||||
|
position = "0 21";
|
||||||
|
extent = "206 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
class = "ESettingsWindowColor";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
editorSettingsRead = "NavEditorPlugin.readSettings();";
|
||||||
|
editorSettingsValue = "NavEditor/SelectedSplineColor";
|
||||||
|
editorSettingsWrite = "NavEditorPlugin.writeSettings();";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Sel. Spline:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "0 1";
|
||||||
|
extent = "70 16";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
historySize = "0";
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "80 0";
|
||||||
|
extent = "104 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
internalName = "ColorEdit";
|
||||||
|
class = "ESettingsWindowColorEdit";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
};
|
||||||
|
new GuiSwatchButtonCtrl() {
|
||||||
|
color = "0 0 0 0";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
position = "188 2";
|
||||||
|
extent = "14 14";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "left";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
internalName = "ColorButton";
|
||||||
|
class = "ESettingsWindowColorButton";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
//--- OBJECT WRITE END ---
|
||||||
144
Templates/Empty/game/tools/navEditor/NavEditorToolbar.gui
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
//--- OBJECT WRITE BEGIN ---
|
||||||
|
%guiContent = new GuiControl(NavEditorToolbar,EditorGuiGroup) {
|
||||||
|
position = "306 0";
|
||||||
|
extent = "800 32";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "NavEditorToolbar";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
enabled = "1";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Navigation Editor";
|
||||||
|
maxLength = "255";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "6 6";
|
||||||
|
extent = "150 20";
|
||||||
|
minExtent = "8 8";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiBitmapCtrl() {
|
||||||
|
bitmap = "core/art/gui/images/separator-h.png";
|
||||||
|
wrap = "0";
|
||||||
|
position = "90 3";
|
||||||
|
extent = "2 26";
|
||||||
|
minExtent = "1 1";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiButtonCtrl(NavEditorAboutBtn) {
|
||||||
|
text = "Console";
|
||||||
|
groupNum = "7";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
position = "100 6";
|
||||||
|
extent = "54 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiButtonProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
command = "NavEditorConsoleDlg.setVisible(!NavEditorConsoleDlg.isVisible());";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
tooltip = "Show Console";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
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 = "GuiCheckBoxProfile";
|
||||||
|
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 = "GuiCheckBoxProfile";
|
||||||
|
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 = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
variable = "$Nav::Editor::renderBVTree";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
internalName = "BVTreeButton";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
//--- OBJECT WRITE END ---
|
||||||
BIN
Templates/Empty/game/tools/navEditor/done.wav
Normal file
BIN
Templates/Empty/game/tools/navEditor/images/nav-cover_d.png
Normal file
|
After Width: | Height: | Size: 525 B |
BIN
Templates/Empty/game/tools/navEditor/images/nav-cover_h.png
Normal file
|
After Width: | Height: | Size: 633 B |
BIN
Templates/Empty/game/tools/navEditor/images/nav-cover_n.png
Normal file
|
After Width: | Height: | Size: 307 B |
BIN
Templates/Empty/game/tools/navEditor/images/nav-editor_d.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Templates/Empty/game/tools/navEditor/images/nav-editor_h.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Templates/Empty/game/tools/navEditor/images/nav-editor_n.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Templates/Empty/game/tools/navEditor/images/nav-link_d.png
Normal file
|
After Width: | Height: | Size: 692 B |
BIN
Templates/Empty/game/tools/navEditor/images/nav-link_h.png
Normal file
|
After Width: | Height: | Size: 894 B |
BIN
Templates/Empty/game/tools/navEditor/images/nav-link_n.png
Normal file
|
After Width: | Height: | Size: 384 B |
285
Templates/Empty/game/tools/navEditor/main.cs
Normal file
|
|
@ -0,0 +1,285 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// These values should align with enum PolyFlags in walkabout/nav.h
|
||||||
|
$Nav::WalkFlag = 1 << 0;
|
||||||
|
$Nav::SwimFlag = 1 << 1;
|
||||||
|
$Nav::JumpFlag = 1 << 2;
|
||||||
|
$Nav::LedgeFlag = 1 << 3;
|
||||||
|
$Nav::DropFlag = 1 << 4;
|
||||||
|
$Nav::ClimbFlag = 1 << 5;
|
||||||
|
$Nav::TeleportFlag = 1 << 6;
|
||||||
|
|
||||||
|
function initializeNavEditor()
|
||||||
|
{
|
||||||
|
echo(" % - Initializing Navigation Editor");
|
||||||
|
|
||||||
|
// Execute all relevant scripts and GUIs.
|
||||||
|
exec("./NavEditor.cs");
|
||||||
|
exec("./NavEditorGui.gui");
|
||||||
|
exec("./NavEditorToolbar.gui");
|
||||||
|
exec("./NavEditorConsoleDlg.gui");
|
||||||
|
exec("./CreateNewNavMeshDlg.gui");
|
||||||
|
|
||||||
|
// Add ourselves to EditorGui, where all the other tools reside
|
||||||
|
NavEditorGui.setVisible(false);
|
||||||
|
NavEditorToolbar.setVisible(false);
|
||||||
|
NavEditorOptionsWindow.setVisible(false);
|
||||||
|
NavEditorTreeWindow.setVisible(false);
|
||||||
|
NavEditorConsoleDlg.setVisible(false);
|
||||||
|
|
||||||
|
EditorGui.add(NavEditorGui);
|
||||||
|
EditorGui.add(NavEditorToolbar);
|
||||||
|
EditorGui.add(NavEditorOptionsWindow);
|
||||||
|
EditorGui.add(NavEditorTreeWindow);
|
||||||
|
EditorGui.add(NavEditorConsoleDlg);
|
||||||
|
|
||||||
|
new ScriptObject(NavEditorPlugin)
|
||||||
|
{
|
||||||
|
superClass = "EditorPlugin";
|
||||||
|
editorGui = NavEditorGui;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bind shortcuts for the nav editor.
|
||||||
|
%map = new ActionMap();
|
||||||
|
%map.bindCmd(keyboard, "1", "ENavEditorSelectModeBtn.performClick();", "");
|
||||||
|
%map.bindCmd(keyboard, "2", "ENavEditorLinkModeBtn.performClick();", "");
|
||||||
|
%map.bindCmd(keyboard, "3", "ENavEditorCoverModeBtn.performClick();", "");
|
||||||
|
%map.bindCmd(keyboard, "4", "ENavEditorTileModeBtn.performClick();", "");
|
||||||
|
%map.bindCmd(keyboard, "5", "ENavEditorTestModeBtn.performClick();", "");
|
||||||
|
%map.bindCmd(keyboard, "c", "NavEditorConsoleBtn.performClick();", "");
|
||||||
|
NavEditorPlugin.map = %map;
|
||||||
|
|
||||||
|
NavEditorPlugin.initSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyNavEditor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::onWorldEditorStartup(%this)
|
||||||
|
{
|
||||||
|
// Add ourselves to the window menu.
|
||||||
|
%accel = EditorGui.addToEditorsMenu("Navigation Editor", "", NavEditorPlugin);
|
||||||
|
|
||||||
|
// Add ourselves to the ToolsToolbar.
|
||||||
|
%tooltip = "Navigation Editor (" @ %accel @ ")";
|
||||||
|
EditorGui.addToToolsToolbar("NavEditorPlugin", "NavEditorPalette", expandFilename("tools/navEditor/images/nav-editor"), %tooltip);
|
||||||
|
|
||||||
|
GuiWindowCtrl::attach(NavEditorOptionsWindow, NavEditorTreeWindow);
|
||||||
|
|
||||||
|
// Add ourselves to the Editor Settings window.
|
||||||
|
exec("./NavEditorSettingsTab.gui");
|
||||||
|
ESettingsWindow.addTabPage(ENavEditorSettingsPage);
|
||||||
|
ENavEditorSettingsPage.init();
|
||||||
|
|
||||||
|
// Add items to World Editor Creator
|
||||||
|
EWCreatorWindow.beginGroup("Navigation");
|
||||||
|
|
||||||
|
EWCreatorWindow.registerMissionObject("CoverPoint", "Cover point");
|
||||||
|
|
||||||
|
EWCreatorWindow.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ENavEditorSettingsPage::init(%this)
|
||||||
|
{
|
||||||
|
// Initialises the settings controls in the settings dialog box.
|
||||||
|
%this-->SpawnClassOptions.clear();
|
||||||
|
%this-->SpawnClassOptions.add("AIPlayer");
|
||||||
|
%this-->SpawnClassOptions.setFirstSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::onActivated(%this)
|
||||||
|
{
|
||||||
|
%this.readSettings();
|
||||||
|
|
||||||
|
// Set a global variable so everyone knows we're editing!
|
||||||
|
$Nav::EditorOpen = true;
|
||||||
|
|
||||||
|
// Start off in Select mode.
|
||||||
|
ToolsPaletteArray->NavEditorSelectMode.performClick();
|
||||||
|
EditorGui.bringToFront(NavEditorGui);
|
||||||
|
|
||||||
|
NavEditorGui.setVisible(true);
|
||||||
|
NavEditorGui.makeFirstResponder(true);
|
||||||
|
NavEditorToolbar.setVisible(true);
|
||||||
|
|
||||||
|
NavEditorOptionsWindow.setVisible(true);
|
||||||
|
NavEditorTreeWindow.setVisible(true);
|
||||||
|
|
||||||
|
// Inspect the ServerNavMeshSet, which contains all the NavMesh objects
|
||||||
|
// in the mission.
|
||||||
|
if(!isObject(ServerNavMeshSet))
|
||||||
|
new SimSet(ServerNavMeshSet);
|
||||||
|
if(ServerNavMeshSet.getCount() == 0)
|
||||||
|
MessageBoxYesNo("No NavMesh", "There is no NavMesh in this level. Would you like to create one?" SPC
|
||||||
|
"If not, please use the Nav Editor to create a new NavMesh.",
|
||||||
|
"Canvas.pushDialog(CreateNewNavMeshDlg);");
|
||||||
|
NavTreeView.open(ServerNavMeshSet, true);
|
||||||
|
|
||||||
|
// Push our keybindings to the top. (See initializeNavEditor for where this
|
||||||
|
// map was created.)
|
||||||
|
%this.map.push();
|
||||||
|
|
||||||
|
// Store this on a dynamic field
|
||||||
|
// in order to restore whatever setting
|
||||||
|
// the user had before.
|
||||||
|
%this.prevGizmoAlignment = GlobalGizmoProfile.alignment;
|
||||||
|
|
||||||
|
// Always use Object alignment.
|
||||||
|
GlobalGizmoProfile.alignment = "Object";
|
||||||
|
|
||||||
|
// Set the status until some other editing mode adds useful information.
|
||||||
|
EditorGuiStatusBar.setInfo("Navigation editor.");
|
||||||
|
EditorGuiStatusBar.setSelection("");
|
||||||
|
|
||||||
|
// Allow the Gui to setup.
|
||||||
|
NavEditorGui.onEditorActivated();
|
||||||
|
|
||||||
|
Parent::onActivated(%this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::onDeactivated(%this)
|
||||||
|
{
|
||||||
|
%this.writeSettings();
|
||||||
|
|
||||||
|
$Nav::EditorOpen = false;
|
||||||
|
|
||||||
|
NavEditorGui.setVisible(false);
|
||||||
|
NavEditorToolbar.setVisible(false);
|
||||||
|
NavEditorOptionsWindow.setVisible(false);
|
||||||
|
NavEditorTreeWindow.setVisible(false);
|
||||||
|
%this.map.pop();
|
||||||
|
|
||||||
|
// Restore the previous Gizmo alignment settings.
|
||||||
|
GlobalGizmoProfile.alignment = %this.prevGizmoAlignment;
|
||||||
|
|
||||||
|
// Allow the Gui to cleanup.
|
||||||
|
NavEditorGui.onEditorDeactivated();
|
||||||
|
|
||||||
|
Parent::onDeactivated(%this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::onEditMenuSelect(%this, %editMenu)
|
||||||
|
{
|
||||||
|
%hasSelection = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::handleDelete(%this)
|
||||||
|
{
|
||||||
|
// Event happens when the user hits 'delete'.
|
||||||
|
NavEditorGui.deleteSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::handleEscape(%this)
|
||||||
|
{
|
||||||
|
return NavEditorGui.onEscapePressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::isDirty(%this)
|
||||||
|
{
|
||||||
|
return NavEditorGui.isDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::onSaveMission(%this, %missionFile)
|
||||||
|
{
|
||||||
|
if(NavEditorGui.isDirty)
|
||||||
|
{
|
||||||
|
MissionGroup.save(%missionFile);
|
||||||
|
NavEditorGui.isDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Settings
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function NavEditorPlugin::initSettings(%this)
|
||||||
|
{
|
||||||
|
EditorSettings.beginGroup("NavEditor", true);
|
||||||
|
|
||||||
|
EditorSettings.setDefaultValue("SpawnClass", "AIPlayer");
|
||||||
|
EditorSettings.setDefaultValue("SpawnDatablock", "DefaultPlayerData");
|
||||||
|
|
||||||
|
EditorSettings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::readSettings(%this)
|
||||||
|
{
|
||||||
|
EditorSettings.beginGroup("NavEditor", true);
|
||||||
|
|
||||||
|
// 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.spawnDatablock = EditorSettings.value("SpawnDatablock");
|
||||||
|
NavEditorGui.backgroundBuild = EditorSettings.value("BackgroundBuild");
|
||||||
|
NavEditorGui.saveIntermediates = EditorSettings.value("SaveIntermediates");
|
||||||
|
NavEditorGui.playSoundWhenDone = EditorSettings.value("PlaySoundWhenDone");
|
||||||
|
|
||||||
|
EditorSettings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::writeSettings(%this)
|
||||||
|
{
|
||||||
|
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("SpawnDatablock", NavEditorGui.spawnDatablock);
|
||||||
|
EditorSettings.setValue("BackgroundBuild", NavEditorGui.backgroundBuild);
|
||||||
|
EditorSettings.setValue("SaveIntermediates", NavEditorGui.saveIntermediates);
|
||||||
|
EditorSettings.setValue("PlaySoundWhenDone", NavEditorGui.playSoundWhenDone);
|
||||||
|
|
||||||
|
EditorSettings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ESettingsWindowPopup::onWake(%this)
|
||||||
|
{
|
||||||
|
%this.setSelected(%this.findText(EditorSettings.value(%this.editorSettingsValue)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function ESettingsWindowPopup::onSelect(%this)
|
||||||
|
{
|
||||||
|
EditorSettings.setValue(%this.editorSettingsValue, %this.getText());
|
||||||
|
eval(%this.editorSettingsRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Demo
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function OnWalkaboutDemoLimit()
|
||||||
|
{
|
||||||
|
MessageBoxOK("Walkabout demo",
|
||||||
|
"This demo only allows two NavMeshes to be created. Sorry!");
|
||||||
|
}
|
||||||
|
|
||||||
|
function OnWalkaboutDemoSave()
|
||||||
|
{
|
||||||
|
MessageBoxOK("Walkabout demo",
|
||||||
|
"This demo doesn't allow you to save NavMeshes. Sorry!" SPC
|
||||||
|
"The rest of your mission will still be saved.");
|
||||||
|
}
|
||||||
360
Templates/Empty/game/tools/navEditor/navEditor.cs
Normal file
|
|
@ -0,0 +1,360 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
$Nav::EditorOpen = false;
|
||||||
|
|
||||||
|
function NavEditorGui::onEditorActivated(%this)
|
||||||
|
{
|
||||||
|
if(%this.selectedObject)
|
||||||
|
%this.selectObject(%this.selectedObject);
|
||||||
|
%this.prepSelectionMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onEditorDeactivated(%this)
|
||||||
|
{
|
||||||
|
if(%this.getMesh())
|
||||||
|
%this.deselect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onModeSet(%this, %mode)
|
||||||
|
{
|
||||||
|
// Callback when the nav editor changes mode. Set the appropriate dynamic
|
||||||
|
// GUI contents in the properties/actions boxes.
|
||||||
|
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);
|
||||||
|
|
||||||
|
switch$(%mode)
|
||||||
|
{
|
||||||
|
case "SelectMode":
|
||||||
|
NavInspector.setVisible(true);
|
||||||
|
%actions->SelectActions.setVisible(true);
|
||||||
|
case "LinkMode":
|
||||||
|
%actions->LinkActions.setVisible(true);
|
||||||
|
%properties->LinkProperties.setVisible(true);
|
||||||
|
case "CoverMode":
|
||||||
|
//
|
||||||
|
%actions->CoverActions.setVisible(true);
|
||||||
|
case "TileMode":
|
||||||
|
%actions->TileActions.setVisible(true);
|
||||||
|
%properties->TileProperties.setVisible(true);
|
||||||
|
case "TestMode":
|
||||||
|
%actions->TestActions.setVisible(true);
|
||||||
|
%properties->TestProperties.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::paletteSync(%this, %mode)
|
||||||
|
{
|
||||||
|
// Synchronise the palette (small buttons on the left) with the actual mode
|
||||||
|
// the nav editor is in.
|
||||||
|
%evalShortcut = "ToolsPaletteArray-->" @ %mode @ ".setStateOn(1);";
|
||||||
|
eval(%evalShortcut);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onEscapePressed(%this)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::selectObject(%this, %obj)
|
||||||
|
{
|
||||||
|
NavTreeView.clearSelection();
|
||||||
|
if(isObject(%obj))
|
||||||
|
NavTreeView.selectItem(%obj);
|
||||||
|
%this.onObjectSelected(%obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onObjectSelected(%this, %obj)
|
||||||
|
{
|
||||||
|
if(isObject(%this.selectedObject))
|
||||||
|
%this.deselect();
|
||||||
|
%this.selectedObject = %obj;
|
||||||
|
if(isObject(%obj))
|
||||||
|
{
|
||||||
|
%this.selectMesh(%obj);
|
||||||
|
NavInspector.inspect(%obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::deleteMesh(%this)
|
||||||
|
{
|
||||||
|
if(isObject(%this.selectedObject))
|
||||||
|
{
|
||||||
|
%this.selectedObject.delete();
|
||||||
|
%this.selectObject(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::deleteSelected(%this)
|
||||||
|
{
|
||||||
|
switch$(%this.getMode())
|
||||||
|
{
|
||||||
|
case "SelectMode":
|
||||||
|
// Try to delete the selected NavMesh.
|
||||||
|
if(isObject(NavEditorGui.selectedObject))
|
||||||
|
MessageBoxYesNo("Warning",
|
||||||
|
"Are you sure you want to delete" SPC NavEditorGui.selectedObject.getName(),
|
||||||
|
"NavEditorGui.deleteMesh();");
|
||||||
|
case "TestMode":
|
||||||
|
%this.getPlayer().delete();
|
||||||
|
%this.onPlayerDeselected();
|
||||||
|
case "LinkMode":
|
||||||
|
%this.deleteLink();
|
||||||
|
%this.isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::buildSelectedMeshes(%this)
|
||||||
|
{
|
||||||
|
if(isObject(%this.getMesh()))
|
||||||
|
{
|
||||||
|
%this.getMesh().build(NavEditorGui.backgroundBuild, NavEditorGui.saveIntermediates);
|
||||||
|
%this.isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::buildLinks(%this)
|
||||||
|
{
|
||||||
|
if(isObject(%this.getMesh()))
|
||||||
|
{
|
||||||
|
%this.getMesh().buildLinks();
|
||||||
|
%this.isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLinkData(%control, %flags)
|
||||||
|
{
|
||||||
|
%control->LinkWalkFlag.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->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 getLinkFlags(%control)
|
||||||
|
{
|
||||||
|
return (%control->LinkWalkFlag.isStateOn() ? $Nav::WalkFlag : 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 disableLinkData(%control)
|
||||||
|
{
|
||||||
|
%control->LinkWalkFlag.setActive(false);
|
||||||
|
%control->LinkJumpFlag.setActive(false);
|
||||||
|
%control->LinkDropFlag.setActive(false);
|
||||||
|
%control->LinkLedgeFlag.setActive(false);
|
||||||
|
%control->LinkClimbFlag.setActive(false);
|
||||||
|
%control->LinkTeleportFlag.setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onLinkSelected(%this, %flags)
|
||||||
|
{
|
||||||
|
updateLinkData(NavEditorOptionsWindow-->LinkProperties, %flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onPlayerSelected(%this, %flags)
|
||||||
|
{
|
||||||
|
updateLinkData(NavEditorOptionsWindow-->TestProperties, %flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::updateLinkFlags(%this)
|
||||||
|
{
|
||||||
|
if(isObject(%this.getMesh()))
|
||||||
|
{
|
||||||
|
%properties = NavEditorOptionsWindow-->LinkProperties;
|
||||||
|
%this.setLinkFlags(getLinkFlags(%properties));
|
||||||
|
%this.isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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::onLinkDeselected(%this)
|
||||||
|
{
|
||||||
|
disableLinkData(NavEditorOptionsWindow-->LinkProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onPlayerDeselected(%this)
|
||||||
|
{
|
||||||
|
disableLinkData(NavEditorOptionsWindow-->TestProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::createCoverPoints(%this)
|
||||||
|
{
|
||||||
|
if(isObject(%this.getMesh()))
|
||||||
|
{
|
||||||
|
%this.getMesh().createCoverPoints();
|
||||||
|
%this.isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::deleteCoverPoints(%this)
|
||||||
|
{
|
||||||
|
if(isObject(%this.getMesh()))
|
||||||
|
{
|
||||||
|
%this.getMesh().deleteCoverPoints();
|
||||||
|
%this.isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::findCover(%this)
|
||||||
|
{
|
||||||
|
if(%this.getMode() $= "TestMode" && isObject(%this.getPlayer()))
|
||||||
|
{
|
||||||
|
%pos = LocalClientConnection.getControlObject().getPosition();
|
||||||
|
%text = NavEditorOptionsWindow-->TestProperties->CoverPosition.getText();
|
||||||
|
if(%text !$= "")
|
||||||
|
%pos = eval(%text);
|
||||||
|
%this.getPlayer().findCover(%pos, NavEditorOptionsWindow-->TestProperties->CoverRadius.getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::followObject(%this)
|
||||||
|
{
|
||||||
|
if(%this.getMode() $= "TestMode" && isObject(%this.getPlayer()))
|
||||||
|
{
|
||||||
|
%obj = LocalClientConnection.player;
|
||||||
|
%text = NavEditorOptionsWindow-->TestProperties->FollowObject.getText();
|
||||||
|
if(%text !$= "")
|
||||||
|
{
|
||||||
|
eval("%obj = " @ %text);
|
||||||
|
if(!isObject(%obj))
|
||||||
|
MessageBoxOk("Error", "Cannot find object" SPC %text);
|
||||||
|
}
|
||||||
|
if(isObject(%obj))
|
||||||
|
%this.getPlayer().followObject(%obj, NavEditorOptionsWindow-->TestProperties->FollowRadius.getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavInspector::inspect(%this, %obj)
|
||||||
|
{
|
||||||
|
%name = "";
|
||||||
|
if(isObject(%obj))
|
||||||
|
%name = %obj.getName();
|
||||||
|
else
|
||||||
|
NavFieldInfoControl.setText("");
|
||||||
|
|
||||||
|
Parent::inspect(%this, %obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavInspector::onInspectorFieldModified(%this, %object, %fieldName, %arrayIndex, %oldValue, %newValue)
|
||||||
|
{
|
||||||
|
// Same work to do as for the regular WorldEditor Inspector.
|
||||||
|
Inspector::onInspectorFieldModified(%this, %object, %fieldName, %arrayIndex, %oldValue, %newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavInspector::onFieldSelected(%this, %fieldName, %fieldTypeStr, %fieldDoc)
|
||||||
|
{
|
||||||
|
NavFieldInfoControl.setText("<font:ArialBold:14>" @ %fieldName @ "<font:ArialItalic:14> (" @ %fieldTypeStr @ ") " NL "<font:Arial:14>" @ %fieldDoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavTreeView::onInspect(%this, %obj)
|
||||||
|
{
|
||||||
|
NavInspector.inspect(%obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavTreeView::onSelect(%this, %obj)
|
||||||
|
{
|
||||||
|
NavInspector.inspect(%obj);
|
||||||
|
NavEditorGui.onObjectSelected(%obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::prepSelectionMode(%this)
|
||||||
|
{
|
||||||
|
%this.setMode("SelectMode");
|
||||||
|
ToolsPaletteArray-->NavEditorSelectMode.setStateOn(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function ENavEditorPaletteButton::onClick(%this)
|
||||||
|
{
|
||||||
|
// When clicking on a pelette button, add its description to the bottom of
|
||||||
|
// the editor window.
|
||||||
|
EditorGuiStatusBar.setInfo(%this.DetailedDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function NavMeshLinkFlagButton::onClick(%this)
|
||||||
|
{
|
||||||
|
NavEditorGui.updateLinkFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavMeshTestFlagButton::onClick(%this)
|
||||||
|
{
|
||||||
|
NavEditorGui.updateTestFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
singleton GuiControlProfile(NavEditorProfile)
|
||||||
|
{
|
||||||
|
canKeyFocus = true;
|
||||||
|
opaque = true;
|
||||||
|
fillColor = "192 192 192 192";
|
||||||
|
category = "Editor";
|
||||||
|
};
|
||||||
|
|
||||||
|
singleton GuiControlProfile(GuiSimpleBorderProfile)
|
||||||
|
{
|
||||||
|
opaque = false;
|
||||||
|
border = 1;
|
||||||
|
category = "Editor";
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
%paletteId = new GuiControl(NavEditorPalette,EditorGuiGroup) {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "GuiDefaultProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "1024 768";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
hovertime = "1000";
|
||||||
|
|
||||||
|
new GuiBitmapButtonCtrl(ENavEditorSelectModeBtn) {
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
class = ENavEditorPaletteButton;
|
||||||
|
internalName = "NavEditorSelectMode";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "25 19";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
Command = "NavEditorGui.prepSelectionMode();";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
ToolTip = "View NavMesh (1).";
|
||||||
|
DetailedDesc = "";
|
||||||
|
hovertime = "1000";
|
||||||
|
bitmap = "tools/gui/images/menubar/visibility-toggle";
|
||||||
|
buttonType = "RadioButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
};
|
||||||
|
new GuiBitmapButtonCtrl(ENavEditorLinkModeBtn) {
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
class = ENavEditorPaletteButton;
|
||||||
|
internalName = "NavEditorLinkMode";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "25 19";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
Command = "NavEditorGui.setMode(\"LinkMode\");";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
ToolTip = "Create off-mesh links (2).";
|
||||||
|
DetailedDesc = "Click to select/add. Shift-click to add multiple end points.";
|
||||||
|
hovertime = "1000";
|
||||||
|
bitmap = "tools/navEditor/images/nav-link";
|
||||||
|
buttonType = "RadioButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
};
|
||||||
|
new GuiBitmapButtonCtrl(ENavEditorCoverModeBtn) {
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
class = ENavEditorPaletteButton;
|
||||||
|
internalName = "NavEditorCoverMode";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "25 19";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
Command = "NavEditorGui.setMode(\"CoverMode\");";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
ToolTip = "Edit cover (3).";
|
||||||
|
DetailedDesc = "";
|
||||||
|
hovertime = "1000";
|
||||||
|
bitmap = "tools/navEditor/images/nav-cover";
|
||||||
|
buttonType = "RadioButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
};
|
||||||
|
new GuiBitmapButtonCtrl(ENavEditorTileModeBtn) {
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
class = ENavEditorPaletteButton;
|
||||||
|
internalName = "NavEditorTileMode";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "25 19";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
Command = "NavEditorGui.setMode(\"TileMode\");";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
ToolTip = "View tiles (4).";
|
||||||
|
DetailedDesc = "Click to select.";
|
||||||
|
hovertime = "1000";
|
||||||
|
bitmap = "tools/gui/images/menubar/select-bounds";
|
||||||
|
buttonType = "RadioButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
};
|
||||||
|
new GuiBitmapButtonCtrl(ENavEditorTestModeBtn) {
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
class = ENavEditorPaletteButton;
|
||||||
|
internalName = "NavEditorTestMode";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "25 19";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
Command = "NavEditorGui.setMode(\"TestMode\");";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
ToolTip = "Test pathfinding (5).";
|
||||||
|
DetailedDesc = "Click to select/move character, CTRL-click to spawn, SHIFT-click to deselect.";
|
||||||
|
hovertime = "1000";
|
||||||
|
bitmap = "tools/worldEditor/images/toolbar/3rd-person-camera";
|
||||||
|
buttonType = "RadioButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
HorizSizing = "right";
|
HorizSizing = "right";
|
||||||
VertSizing = "bottom";
|
VertSizing = "bottom";
|
||||||
Position = "0 31";
|
Position = "0 31";
|
||||||
Extent = (29 + 4) * 14 + 12 SPC "33";
|
Extent = "0 33";
|
||||||
MinExtent = "8 2";
|
MinExtent = "8 2";
|
||||||
canSave = "1";
|
canSave = "1";
|
||||||
Visible = "1";
|
Visible = "1";
|
||||||
|
|
|
||||||
|
|
@ -384,6 +384,7 @@ function EditorGui::addToToolsToolbar( %this, %pluginName, %internalName, %bitma
|
||||||
useMouseEvents = "0";
|
useMouseEvents = "0";
|
||||||
};
|
};
|
||||||
ToolsToolbarArray.add(%button);
|
ToolsToolbarArray.add(%button);
|
||||||
|
EWToolsToolbar.setExtent((25 + 8) * (%count + 1) + 12 SPC "33");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,6 @@ function EWCreatorWindow::init( %this )
|
||||||
%this.registerMissionObject( "SFXSpace", "Sound Space" );
|
%this.registerMissionObject( "SFXSpace", "Sound Space" );
|
||||||
%this.registerMissionObject( "OcclusionVolume", "Occlusion Volume" );
|
%this.registerMissionObject( "OcclusionVolume", "Occlusion Volume" );
|
||||||
%this.registerMissionObject( "AccumulationVolume", "Accumulation Volume" );
|
%this.registerMissionObject( "AccumulationVolume", "Accumulation Volume" );
|
||||||
%this.registerMissionObject("NavMesh", "Navigation mesh");
|
|
||||||
%this.registerMissionObject("NavPath", "Path");
|
|
||||||
|
|
||||||
%this.endGroup();
|
%this.endGroup();
|
||||||
|
|
||||||
|
|
@ -788,4 +786,4 @@ function genericCreateObject( %class )
|
||||||
|
|
||||||
// In case the caller wants it.
|
// In case the caller wants it.
|
||||||
return %obj;
|
return %obj;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
392
Templates/Full/game/tools/navEditor/CreateNewNavMeshDlg.gui
Normal file
|
|
@ -0,0 +1,392 @@
|
||||||
|
//--- OBJECT WRITE BEGIN ---
|
||||||
|
%guiContent = new GuiControl(CreateNewNavMeshDlg) {
|
||||||
|
position = "0 0";
|
||||||
|
extent = "1024 768";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
|
||||||
|
new GuiWindowCtrl() {
|
||||||
|
text = "New NavMesh";
|
||||||
|
resizeWidth = "0";
|
||||||
|
resizeHeight = "0";
|
||||||
|
canMove = "1";
|
||||||
|
canClose = "1";
|
||||||
|
canMinimize = "0";
|
||||||
|
canMaximize = "0";
|
||||||
|
canCollapse = "0";
|
||||||
|
closeCommand = "Canvas.popDialog(CreateNewNavMeshDlg);";
|
||||||
|
edgeSnap = "1";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "283 240";
|
||||||
|
extent = "200 176";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiWindowProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Name:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "12 29";
|
||||||
|
extent = "39 21";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
historySize = "0";
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
text = "Nav";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "59 30";
|
||||||
|
extent = "129 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "MeshName";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Position:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "12 51";
|
||||||
|
extent = "39 21";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
historySize = "0";
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
text = "0 0 0";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "59 52";
|
||||||
|
extent = "129 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "MeshPosition";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Scale:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "12 73";
|
||||||
|
extent = "39 21";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
historySize = "0";
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
text = "50 50 20";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "59 74";
|
||||||
|
extent = "129 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "MeshScale";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl(MeshMissionBounds) {
|
||||||
|
text = " Fit NavMesh to mission area";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "1";
|
||||||
|
position = "22 99";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
tooltip = "Positions and scales the NavMesh so it includes all your mission objects.";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl(MeshTerrainBounds) {
|
||||||
|
text = " Include terrain";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
position = "22 121";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
tooltip = "Consider terrain when calculating NavMesh bounds.";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
text = "Create!";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
position = "12 146";
|
||||||
|
extent = "87 19";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiButtonProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
command = "CreateNewNavMeshDlg.create();";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
text = "Cancel";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
position = "104 146";
|
||||||
|
extent = "84 19";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiButtonProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
command = "Canvas.popDialog(CreateNewNavMeshDlg);";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
//--- OBJECT WRITE END ---
|
||||||
|
|
||||||
|
function CreateNewNavMeshDlg::onWake(%this)
|
||||||
|
{
|
||||||
|
%this-->MeshName.setText("Nav");
|
||||||
|
%this-->MeshPosition.setText("0 0 0");
|
||||||
|
%this-->MeshScale.setText("50 50 20");
|
||||||
|
MeshMissionBounds.setStateOn(false);
|
||||||
|
MeshTerrainBounds.setStateOn(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MissionBoundsExtents(%group)
|
||||||
|
{
|
||||||
|
%box = "0 0 0 0 0 0";
|
||||||
|
foreach(%obj in %group)
|
||||||
|
{
|
||||||
|
%cls = %obj.getClassName();
|
||||||
|
if(%cls $= "SimGroup" || %cls $= "SimSet" || %cls $= "Path")
|
||||||
|
{
|
||||||
|
// Need to recursively check grouped objects.
|
||||||
|
%wbox = MissionBoundsExtents(%obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Skip objects that are too big and shouldn't really be considered
|
||||||
|
// part of the scene, or are global bounds and we therefore can't get
|
||||||
|
// any sensible information out of them.
|
||||||
|
if(%cls $= "LevelInfo")
|
||||||
|
continue;
|
||||||
|
if(!MeshTerrainBounds.isStateOn() && %cls $= "TerrainBlock")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!(%obj.getType() & $TypeMasks::StaticObjectType) ||
|
||||||
|
%obj.getType() & $TypeMasks::EnvironmentObjectType)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(%obj.isGlobalBounds())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
%wbox = %obj.getWorldBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update min point.
|
||||||
|
for(%j = 0; %j < 3; %j++)
|
||||||
|
{
|
||||||
|
if(GetWord(%box, %j) > GetWord(%wbox, %j))
|
||||||
|
%box = SetWord(%box, %j, GetWord(%wbox, %j));
|
||||||
|
}
|
||||||
|
// Update max point.
|
||||||
|
for(%j = 3; %j < 6; %j++)
|
||||||
|
{
|
||||||
|
if(GetWord(%box, %j) < GetWord(%wbox, %j))
|
||||||
|
%box = SetWord(%box, %j, GetWord(%wbox, %j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return %box;
|
||||||
|
}
|
||||||
|
|
||||||
|
function CreateNewNavMeshDlg::create(%this)
|
||||||
|
{
|
||||||
|
%name = %this-->MeshName.getText();
|
||||||
|
if(%name $= "" || nameToID(%name) != -1)
|
||||||
|
{
|
||||||
|
MessageBoxOk("Error", "A NavMesh must have a unique name!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%mesh = 0;
|
||||||
|
|
||||||
|
if(MeshMissionBounds.isStateOn())
|
||||||
|
{
|
||||||
|
if(!isObject(MissionGroup))
|
||||||
|
{
|
||||||
|
MessageBoxOk("Error", "You must have a MissionGroup to use the mission bounds function.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Get maximum extents of all objects.
|
||||||
|
%box = MissionBoundsExtents(MissionGroup);
|
||||||
|
%pos = GetBoxCenter(%box);
|
||||||
|
%scale = (GetWord(%box, 3) - GetWord(%box, 0)) / 2 + 5
|
||||||
|
SPC (GetWord(%box, 4) - GetWord(%box, 1)) / 2 + 5
|
||||||
|
SPC (GetWord(%box, 5) - GetWord(%box, 2)) / 2 + 5;
|
||||||
|
|
||||||
|
%mesh = new NavMesh(%name)
|
||||||
|
{
|
||||||
|
position = %pos;
|
||||||
|
scale = %scale;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%mesh = new NavMesh(%name)
|
||||||
|
{
|
||||||
|
position = %this-->MeshPosition.getText();
|
||||||
|
scale = %this-->MeshScale.getText();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
MissionGroup.add(%mesh);
|
||||||
|
NavEditorGui.selectObject(%mesh);
|
||||||
|
|
||||||
|
Canvas.popDialog(CreateNewNavMeshDlg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MeshMissionBounds::onClick(%this)
|
||||||
|
{
|
||||||
|
MeshTerrainBounds.setActive(%this.isStateOn());
|
||||||
|
}
|
||||||
169
Templates/Full/game/tools/navEditor/NavEditorConsoleDlg.gui
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
//--- OBJECT WRITE BEGIN ---
|
||||||
|
%guiContent = new GuiWindowCtrl(NavEditorConsoleDlg) {
|
||||||
|
text = "Nav Console";
|
||||||
|
resizeWidth = "1";
|
||||||
|
resizeHeight = "1";
|
||||||
|
canMove = "1";
|
||||||
|
canClose = "1";
|
||||||
|
canMinimize = "1";
|
||||||
|
canMaximize = "1";
|
||||||
|
canCollapse = "0";
|
||||||
|
closeCommand = "NavEditorConsoleDlg.setVisible(false);";
|
||||||
|
edgeSnap = "1";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "238 170";
|
||||||
|
extent = "320 240";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiWindowProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "3 222";
|
||||||
|
extent = "149 13";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "top";
|
||||||
|
profile = "GuiTextProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "StatusLeft";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiScrollCtrl() {
|
||||||
|
willFirstRespond = "1";
|
||||||
|
hScrollBar = "dynamic";
|
||||||
|
vScrollBar = "dynamic";
|
||||||
|
lockHorizScroll = "1";
|
||||||
|
lockVertScroll = "0";
|
||||||
|
constantThumbHeight = "0";
|
||||||
|
childMargin = "0 0";
|
||||||
|
mouseWheelScrollSpeed = "-1";
|
||||||
|
margin = "-14 41 3 3";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "0";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "0";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "3 23";
|
||||||
|
extent = "314 194";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "relative";
|
||||||
|
vertSizing = "relative";
|
||||||
|
profile = "GuiEditorScrollProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "OutputScroll";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiListBoxCtrl() {
|
||||||
|
allowMultipleSelections = "0";
|
||||||
|
fitParentWidth = "1";
|
||||||
|
colorBullet = "1";
|
||||||
|
position = "1 1";
|
||||||
|
extent = "312 16";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "relative";
|
||||||
|
vertSizing = "relative";
|
||||||
|
profile = "GuiListBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
internalName = "Output";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
//--- OBJECT WRITE END ---
|
||||||
|
|
||||||
|
new ScriptMsgListener(NavEditorConsoleListener);
|
||||||
|
getNavMeshEventManager().subscribe(NavEditorConsoleListener, "NavMeshCreated");
|
||||||
|
getNavMeshEventManager().subscribe(NavEditorConsoleListener, "NavMeshRemoved");
|
||||||
|
getNavMeshEventManager().subscribe(NavEditorConsoleListener, "NavMeshStartUpdate");
|
||||||
|
getNavMeshEventManager().subscribe(NavEditorConsoleListener, "NavMeshUpdate");
|
||||||
|
getNavMeshEventManager().subscribe(NavEditorConsoleListener, "NavMeshTileUpdate");
|
||||||
|
|
||||||
|
function NavEditorConsoleListener::onNavMeshCreated(%this, %data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorConsoleListener::onNavMeshRemoved(%this, %data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorConsoleListener::onNavMeshStartUpdate(%this, %data)
|
||||||
|
{
|
||||||
|
NavEditorConsoleDlg-->Output.clearItems();
|
||||||
|
NavEditorConsoleDlg-->Output.addItem("Build starting for NavMesh" SPC %data, "0 0.6 0");
|
||||||
|
NavEditorConsoleDlg-->OutputScroll.scrollToBottom();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorConsoleListener::onNavMeshUpdate(%this, %data)
|
||||||
|
{
|
||||||
|
%message = "";
|
||||||
|
if(getWordCount(%data) == 2)
|
||||||
|
{
|
||||||
|
%seconds = getWord(%data, 1);
|
||||||
|
%minutes = mFloor(%seconds / 60);
|
||||||
|
%seconds -= %minutes * 60;
|
||||||
|
%message = "Built NavMesh" SPC getWord(%data, 0) SPC "in" SPC %minutes @ "m" SPC mRound(%seconds) @ "s";
|
||||||
|
if(NavEditorGui.playSoundWhenDone)
|
||||||
|
{
|
||||||
|
sfxPlayOnce(Audio2D, "tools/navEditor/done.wav");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%message = "Loaded NavMesh" SPC %data;
|
||||||
|
}
|
||||||
|
NavEditorConsoleDlg-->Output.addItem(%message, "0 0.6 0");
|
||||||
|
NavEditorConsoleDlg-->OutputScroll.scrollToBottom();
|
||||||
|
NavEditorConsoleDlg->StatusLeft.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorConsoleListener::onNavMeshTileUpdate(%this, %data)
|
||||||
|
{
|
||||||
|
%mesh = getWord(%data, 0);
|
||||||
|
%index = getWord(%data, 1);
|
||||||
|
%total = getWord(%data, 2);
|
||||||
|
%tile = getWords(%data, 3, 4);
|
||||||
|
%success = getWord(%data, 5) == "1";
|
||||||
|
if(!%success)
|
||||||
|
{
|
||||||
|
%message = "NavMesh" SPC %mesh SPC "tile" SPC %tile SPC "build failed!";
|
||||||
|
NavEditorConsoleDlg-->Output.addItem(%message, "1 0 0");
|
||||||
|
NavEditorConsoleDlg-->OutputScroll.scrollToBottom();
|
||||||
|
}
|
||||||
|
%percent = %index / %total * 100;
|
||||||
|
NavEditorConsoleDlg->StatusLeft.setText("Build progress:" SPC mRound(%percent) @ "%");
|
||||||
|
}
|
||||||
854
Templates/Full/game/tools/navEditor/NavEditorGui.gui
Normal file
|
|
@ -0,0 +1,854 @@
|
||||||
|
//--- OBJECT WRITE BEGIN ---
|
||||||
|
%guiContent = new GuiNavEditorCtrl(NavEditorGui, EditorGuiGroup) {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "NavEditorProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "height";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "800 600";
|
||||||
|
MinExtent = "8 8";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
Docking = "None";
|
||||||
|
Margin = "0 0 0 0";
|
||||||
|
Padding = "0 0 0 0";
|
||||||
|
AnchorTop = "0";
|
||||||
|
AnchorBottom = "0";
|
||||||
|
AnchorLeft = "0";
|
||||||
|
AnchorRight = "0";
|
||||||
|
cameraZRot = "0";
|
||||||
|
forceFOV = "0";
|
||||||
|
renderMissionArea = "0";
|
||||||
|
missionAreaFillColor = "255 0 0 20";
|
||||||
|
missionAreaFrameColor = "255 0 0 128";
|
||||||
|
allowBorderMove = "0";
|
||||||
|
borderMovePixelSize = "20";
|
||||||
|
borderMoveSpeed = "0.1";
|
||||||
|
consoleFrameColor = "255 0 0 255";
|
||||||
|
consoleFillColor = "0 0 0 0";
|
||||||
|
consoleSphereLevel = "1";
|
||||||
|
consoleCircleSegments = "32";
|
||||||
|
consoleLineWidth = "1";
|
||||||
|
GizmoProfile = "GlobalGizmoProfile";
|
||||||
|
|
||||||
|
new GuiWindowCollapseCtrl(NavEditorTreeWindow) {
|
||||||
|
internalName = "";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "GuiWindowProfile";
|
||||||
|
HorizSizing = "windowRelative";
|
||||||
|
VertSizing = "windowRelative";
|
||||||
|
Position = getWord($pref::Video::mode, 0) - 209
|
||||||
|
SPC getWord(EditorGuiToolbar.extent, 1) - 1;
|
||||||
|
Extent = "210 167";
|
||||||
|
MinExtent = "210 100";
|
||||||
|
canSave = "1";
|
||||||
|
isDecoy = "0";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
Margin = "0 0 0 0";
|
||||||
|
Padding = "0 0 0 0";
|
||||||
|
AnchorTop = "1";
|
||||||
|
AnchorBottom = "0";
|
||||||
|
AnchorLeft = "1";
|
||||||
|
AnchorRight = "0";
|
||||||
|
resizeWidth = "1";
|
||||||
|
resizeHeight = "1";
|
||||||
|
canMove = "1";
|
||||||
|
canClose = "0";
|
||||||
|
canMinimize = "0";
|
||||||
|
canMaximize = "0";
|
||||||
|
minSize = "50 50";
|
||||||
|
EdgeSnap = "1";
|
||||||
|
text = "Navigation";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
position = "115 2";
|
||||||
|
extent = "90 18";
|
||||||
|
text = "New NavMesh";
|
||||||
|
command = "Canvas.pushDialog(CreateNewNavMeshDlg);";
|
||||||
|
};
|
||||||
|
|
||||||
|
new GuiContainer(){
|
||||||
|
profile = GuiDefaultProfile;
|
||||||
|
Position = "5 25";
|
||||||
|
Extent = "200 120";
|
||||||
|
Docking = "Client";
|
||||||
|
Margin = "3 1 3 3 ";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "height";
|
||||||
|
isContainer = "1";
|
||||||
|
|
||||||
|
new GuiScrollCtrl() {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "GuiEditorScrollProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "height";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "200 118";
|
||||||
|
MinExtent = "8 8";
|
||||||
|
canSave = "1";
|
||||||
|
isDecoy = "0";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
Docking = "Client";
|
||||||
|
Margin = "0 0 0 0";
|
||||||
|
Padding = "0 0 0 0";
|
||||||
|
AnchorTop = "1";
|
||||||
|
AnchorBottom = "0";
|
||||||
|
AnchorLeft = "1";
|
||||||
|
AnchorRight = "0";
|
||||||
|
willFirstRespond = "1";
|
||||||
|
hScrollBar = "alwaysOff";
|
||||||
|
vScrollBar = "dynamic";
|
||||||
|
lockHorizScroll = "true";
|
||||||
|
lockVertScroll = "false";
|
||||||
|
constantThumbHeight = "0";
|
||||||
|
childMargin = "0 0";
|
||||||
|
mouseWheelScrollSpeed = "-1";
|
||||||
|
|
||||||
|
new GuiTreeViewCtrl(NavTreeView) {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "ToolsGuiTreeViewProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "1 1";
|
||||||
|
Extent = "193 21";
|
||||||
|
MinExtent = "8 8";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
hovertime = "1000";
|
||||||
|
tabSize = "16";
|
||||||
|
textOffset = "2";
|
||||||
|
fullRowSelect = "0";
|
||||||
|
itemHeight = "21";
|
||||||
|
destroyTreeOnSleep = "1";
|
||||||
|
MouseDragging = "0";
|
||||||
|
MultipleSelections = "0";
|
||||||
|
DeleteObjectAllowed = "1";
|
||||||
|
DragToItemAllowed = "0";
|
||||||
|
showRoot = "0";
|
||||||
|
internalNamesOnly = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiWindowCollapseCtrl(NavEditorOptionsWindow) {
|
||||||
|
internalName = "Window";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "GuiWindowProfile";
|
||||||
|
HorizSizing = "windowRelative";
|
||||||
|
VertSizing = "windowRelative";
|
||||||
|
Position = getWord($pref::Video::mode, 0) - 209
|
||||||
|
SPC getWord(EditorGuiToolbar.extent, 1) + getWord(NavEditorTreeWindow.extent, 1) - 2;
|
||||||
|
Extent = "210 530";
|
||||||
|
MinExtent = "210 300";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
Margin = "0 0 0 0";
|
||||||
|
Padding = "0 0 0 0";
|
||||||
|
AnchorTop = "0";
|
||||||
|
AnchorBottom = "0";
|
||||||
|
AnchorLeft = "0";
|
||||||
|
AnchorRight = "0";
|
||||||
|
resizeWidth = "1";
|
||||||
|
resizeHeight = "1";
|
||||||
|
canMove = "1";
|
||||||
|
canClose = "0";
|
||||||
|
canMinimize = "0";
|
||||||
|
canMaximize = "0";
|
||||||
|
minSize = "50 50";
|
||||||
|
EdgeSnap = "1";
|
||||||
|
text = "Properties";
|
||||||
|
|
||||||
|
new GuiContainer(){ //Actions
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "inspectorStyleRolloutDarkProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "4 24";
|
||||||
|
Extent = "202 85";
|
||||||
|
Docking = "Top";
|
||||||
|
Margin = "3 3 3 3";
|
||||||
|
internalName = "ActionsBox";
|
||||||
|
|
||||||
|
new GuiTextCtrl(){
|
||||||
|
Profile = "GuiDefaultProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "5 0";
|
||||||
|
Extent = "86 18";
|
||||||
|
text = "Actions";
|
||||||
|
};
|
||||||
|
new GuiStackControl()
|
||||||
|
{
|
||||||
|
internalName = "SelectActions";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "190 64";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "182 18";
|
||||||
|
text = "Build NavMesh";
|
||||||
|
command = "NavEditorGui.buildSelectedMeshes();";
|
||||||
|
};
|
||||||
|
new GuiControl() {
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
Extent = "182 20";
|
||||||
|
position = "0 20";
|
||||||
|
|
||||||
|
new GuiCheckboxCtrl() {
|
||||||
|
internalName = "BackgroundBuildButton";
|
||||||
|
text = "Background";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "75 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
variable = "NavEditorGui.backgroundBuild";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckboxCtrl() {
|
||||||
|
position = "75 0";
|
||||||
|
internalName = "SaveIntermediatesButton";
|
||||||
|
text = "Keep intermediates";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "105 20";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
variable = "NavEditorGui.saveIntermediates";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiCheckboxCtrl() {
|
||||||
|
internalName = "BuildSoundButton";
|
||||||
|
text = "Play sound when done";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "150 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
variable = "NavEditorGui.playSoundWhenDone";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiStackControl()
|
||||||
|
{
|
||||||
|
internalName = "LinkActions";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "190 64";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "182 18";
|
||||||
|
text = "Rebuild links";
|
||||||
|
command = "NavEditorGui.buildLinks();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiStackControl()
|
||||||
|
{
|
||||||
|
internalName = "CoverActions";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "190 64";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "182 18";
|
||||||
|
text = "Create Cover";
|
||||||
|
command = "NavEditorGui.createCoverPoints();";
|
||||||
|
};
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "182 18";
|
||||||
|
text = "Delete Cover";
|
||||||
|
command = "NavEditorGui.deleteCoverPoints();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiStackControl()
|
||||||
|
{
|
||||||
|
internalName = "TileActions";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "190 64";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "182 18";
|
||||||
|
text = "Rebuild tile";
|
||||||
|
command = "NavEditorGui.buildTile();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiStackControl()
|
||||||
|
{
|
||||||
|
internalName = "TestActions";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "190 64";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "180 18";
|
||||||
|
text = "Spawn";
|
||||||
|
command = "NavEditorGui.spawnPlayer();";
|
||||||
|
};
|
||||||
|
new GuiControl() {
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
Extent = "190 18";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "90 18";
|
||||||
|
text = "Delete";
|
||||||
|
command = "NavEditorGui.getPlayer().delete();";
|
||||||
|
};
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
position = "100 0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "90 18";
|
||||||
|
text = "Find cover";
|
||||||
|
command = "NavEditorGui.findCover();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiControl() {
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
Extent = "190 18";
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "90 18";
|
||||||
|
text = "Follow";
|
||||||
|
command = "NavEditorGui.followObject();";
|
||||||
|
};
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
position = "100 0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Extent = "90 18";
|
||||||
|
text = "Stop";
|
||||||
|
command = "NavEditorGui.getPlayer().stop();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiContainer(){
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "inspectorStyleRolloutDarkProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "4 112";
|
||||||
|
Extent = "202 31";
|
||||||
|
Docking = "Top";
|
||||||
|
Margin = "0 0 3 3";
|
||||||
|
|
||||||
|
new GuiTextCtrl(){
|
||||||
|
Profile = "GuiDefaultProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "5 0";
|
||||||
|
Extent = "121 18";
|
||||||
|
text = "Properties";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
new GuiScrollCtrl() {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "GuiEditorScrollProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "height";
|
||||||
|
Position = "4 129";
|
||||||
|
Extent = "202 357";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
Docking = "Client";
|
||||||
|
Margin = "-14 41 3 3";
|
||||||
|
Padding = "0 0 0 0";
|
||||||
|
AnchorTop = "0";
|
||||||
|
AnchorBottom = "0";
|
||||||
|
AnchorLeft = "0";
|
||||||
|
AnchorRight = "0";
|
||||||
|
willFirstRespond = "1";
|
||||||
|
hScrollBar = "alwaysOff";
|
||||||
|
vScrollBar = "dynamic";
|
||||||
|
lockHorizScroll = "true";
|
||||||
|
lockVertScroll = "false";
|
||||||
|
constantThumbHeight = "0";
|
||||||
|
childMargin = "0 0";
|
||||||
|
internalName = "PropertiesBox";
|
||||||
|
|
||||||
|
new GuiInspector(NavInspector) {
|
||||||
|
StackingType = "Vertical";
|
||||||
|
HorizStacking = "Left to Right";
|
||||||
|
VertStacking = "Top to Bottom";
|
||||||
|
Padding = "1";
|
||||||
|
name = "NavInspector";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "GuiTransparentProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "height";
|
||||||
|
Position = "1 1";
|
||||||
|
Extent = "178 16";
|
||||||
|
MinExtent = "16 16";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
dividerMargin = "5";
|
||||||
|
};
|
||||||
|
|
||||||
|
new GuiStackControl() {
|
||||||
|
internalName = "LinkProperties";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "186 64";
|
||||||
|
padding = "2 2 2 2";
|
||||||
|
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkWalkFlag";
|
||||||
|
class = "NavMeshLinkFlagButton";
|
||||||
|
text = " Walk";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "This link is just ordinary flat ground.";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkJumpFlag";
|
||||||
|
class = "NavMeshLinkFlagButton";
|
||||||
|
text = " Jump";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Does this link require a jump?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkDropFlag";
|
||||||
|
class = "NavMeshLinkFlagButton";
|
||||||
|
text = " Drop";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Does this link involve a significant drop?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkLedgeFlag";
|
||||||
|
class = "NavMeshLinkFlagButton";
|
||||||
|
text = " Ledge";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Should the character jump at the next ledge?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkClimbFlag";
|
||||||
|
class = "NavMeshLinkFlagButton";
|
||||||
|
text = " Climb";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Does this link involve climbing?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkTeleportFlag";
|
||||||
|
class = "NavMeshLinkFlagButton";
|
||||||
|
text = " Teleport";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Is this link a teleporter?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiStackControl() {
|
||||||
|
internalName = "TileProperties";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "186 64";
|
||||||
|
padding = "2 2 2 2";
|
||||||
|
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
text = " Display input geometry";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
variable = "$Nav::Editor::renderInput";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
text = " Display voxels";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
variable = "$Nav::Editor::renderVoxels";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiStackControl() {
|
||||||
|
internalName = "TestProperties";
|
||||||
|
position = "7 21";
|
||||||
|
extent = "186 64";
|
||||||
|
padding = "2 2 2 2";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Cover";
|
||||||
|
profile = "GuiTextProfile";
|
||||||
|
extent = "180 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
internalName = "CoverRadius";
|
||||||
|
text = "10";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
extent = "40 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Radius for cover-finding.";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
internalName = "CoverPosition";
|
||||||
|
text = "LocalClientConnection.getControlObject().getPosition();";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
extent = "140 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Position to find cover from.";
|
||||||
|
};
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Follow";
|
||||||
|
profile = "GuiTextProfile";
|
||||||
|
extent = "180 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
internalName = "FollowRadius";
|
||||||
|
text = "1";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
extent = "40 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Radius for following.";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
internalName = "FollowObject";
|
||||||
|
text = "LocalClientConnection.player";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
extent = "140 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Object to follow.";
|
||||||
|
};
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Movement";
|
||||||
|
profile = "GuiTextProfile";
|
||||||
|
extent = "180 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
visible = "1";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkWalkFlag";
|
||||||
|
class = "NavMeshTestFlagButton";
|
||||||
|
text = " Walk";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Can this character walk on ground?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkJumpFlag";
|
||||||
|
class = "NavMeshTestFlagButton";
|
||||||
|
text = " Jump";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Can this character jump?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkDropFlag";
|
||||||
|
class = "NavMeshTestFlagButton";
|
||||||
|
text = " Drop";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Can this character drop over edges?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkLedgeFlag";
|
||||||
|
class = "NavMeshTestFlagButton";
|
||||||
|
text = " Ledge";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Can this character jump from ledges?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkClimbFlag";
|
||||||
|
class = "NavMeshTestFlagButton";
|
||||||
|
text = " Climb";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Can this character climb?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiCheckBoxCtrl() {
|
||||||
|
internalName = "LinkTeleportFlag";
|
||||||
|
class = "NavMeshTestFlagButton";
|
||||||
|
text = " Teleport";
|
||||||
|
buttonType = "ToggleButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
extent = "159 15";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "0";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
toolTip = "Can this character teleport?";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiMLTextCtrl(NavFieldInfoControl) {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "0";
|
||||||
|
Profile = "GuiInspectorFieldInfoMLTextProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "top";
|
||||||
|
Position = "1 485";
|
||||||
|
Extent = "202 42";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
lineSpacing = "2";
|
||||||
|
allowColorChars = "0";
|
||||||
|
maxChars = "-1";
|
||||||
|
useURLMouseCursor = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- OBJECT WRITE END ---
|
||||||
506
Templates/Full/game/tools/navEditor/NavEditorSettingsTab.gui
Normal file
|
|
@ -0,0 +1,506 @@
|
||||||
|
//--- OBJECT WRITE BEGIN ---
|
||||||
|
%guiContent = new GuiTabPageCtrl(ENavEditorSettingsPage) {
|
||||||
|
fitBook = "1";
|
||||||
|
text = "Navigation Editor";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "0 0";
|
||||||
|
extent = "208 292";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "height";
|
||||||
|
profile = "GuiSolidDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
|
||||||
|
new GuiScrollCtrl() {
|
||||||
|
willFirstRespond = "1";
|
||||||
|
hScrollBar = "alwaysOff";
|
||||||
|
vScrollBar = "dynamic";
|
||||||
|
lockHorizScroll = "1";
|
||||||
|
lockVertScroll = "0";
|
||||||
|
constantThumbHeight = "0";
|
||||||
|
childMargin = "0 0";
|
||||||
|
mouseWheelScrollSpeed = "-1";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "0 0";
|
||||||
|
extent = "208 292";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "height";
|
||||||
|
profile = "GuiScrollProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiStackControl() {
|
||||||
|
stackingType = "Vertical";
|
||||||
|
horizStacking = "Left to Right";
|
||||||
|
vertStacking = "Top to Bottom";
|
||||||
|
padding = "0";
|
||||||
|
dynamicSize = "1";
|
||||||
|
dynamicNonStackExtent = "0";
|
||||||
|
dynamicPos = "0";
|
||||||
|
changeChildSizeToFit = "1";
|
||||||
|
changeChildPosition = "1";
|
||||||
|
position = "1 1";
|
||||||
|
extent = "206 124";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiRolloutCtrl() {
|
||||||
|
caption = "Test spawn";
|
||||||
|
margin = "0 3 0 0";
|
||||||
|
defaultHeight = "40";
|
||||||
|
expanded = "1";
|
||||||
|
clickCollapse = "1";
|
||||||
|
hideHeader = "0";
|
||||||
|
autoCollapseSiblings = "0";
|
||||||
|
position = "0 0";
|
||||||
|
extent = "206 62";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiRolloutProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiStackControl() {
|
||||||
|
stackingType = "Vertical";
|
||||||
|
horizStacking = "Left to Right";
|
||||||
|
vertStacking = "Top to Bottom";
|
||||||
|
padding = "3";
|
||||||
|
dynamicSize = "1";
|
||||||
|
dynamicNonStackExtent = "0";
|
||||||
|
dynamicPos = "0";
|
||||||
|
changeChildSizeToFit = "1";
|
||||||
|
changeChildPosition = "1";
|
||||||
|
position = "0 20";
|
||||||
|
extent = "206 39";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiControl() {
|
||||||
|
position = "0 0";
|
||||||
|
extent = "206 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Spawn class:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "5 1";
|
||||||
|
extent = "70 16";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiPopUpMenuCtrlEx() {
|
||||||
|
maxPopupHeight = "200";
|
||||||
|
sbUsesNAColor = "0";
|
||||||
|
reverseTextList = "0";
|
||||||
|
bitmapBounds = "16 16";
|
||||||
|
hotTrackCallback = "0";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "81 0";
|
||||||
|
extent = "121 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiPopUpMenuProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "SpawnClassOptions";
|
||||||
|
class = "ESettingsWindowPopup";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
editorSettingsRead = "NavEditorPlugin.readSettings();";
|
||||||
|
editorSettingsValue = "NavEditor/SpawnClass";
|
||||||
|
editorSettingsWrite = "NavEditorPlugin.writeSettings();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiControl() {
|
||||||
|
position = "0 21";
|
||||||
|
extent = "206 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Datablock:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "5 1";
|
||||||
|
extent = "70 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
historySize = "0";
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
text = "DefaultPlayerData";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "81 0";
|
||||||
|
extent = "121 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
class = "ESettingsWindowTextEdit";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
editorSettingsRead = "NavEditorPlugin.readSettings();";
|
||||||
|
editorSettingsValue = "NavEditor/SpawnDatablock";
|
||||||
|
editorSettingsWrite = "NavEditorPlugin.writeSettings();";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiRolloutCtrl() {
|
||||||
|
caption = "Colors";
|
||||||
|
margin = "0 3 0 0";
|
||||||
|
defaultHeight = "40";
|
||||||
|
expanded = "1";
|
||||||
|
clickCollapse = "1";
|
||||||
|
hideHeader = "0";
|
||||||
|
autoCollapseSiblings = "0";
|
||||||
|
position = "0 62";
|
||||||
|
extent = "206 62";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiRolloutProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiStackControl() {
|
||||||
|
stackingType = "Vertical";
|
||||||
|
horizStacking = "Left to Right";
|
||||||
|
vertStacking = "Top to Bottom";
|
||||||
|
padding = "3";
|
||||||
|
dynamicSize = "1";
|
||||||
|
dynamicNonStackExtent = "0";
|
||||||
|
dynamicPos = "0";
|
||||||
|
changeChildSizeToFit = "1";
|
||||||
|
changeChildPosition = "1";
|
||||||
|
position = "0 20";
|
||||||
|
extent = "206 39";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiControl() {
|
||||||
|
position = "0 0";
|
||||||
|
extent = "206 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
class = "ESettingsWindowColor";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
editorSettingsRead = "NavEditorPlugin.readSettings();";
|
||||||
|
editorSettingsValue = "NavEditor/HoverSplineColor";
|
||||||
|
editorSettingsWrite = "NavEditorPlugin.writeSettings();";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Hover Spline:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "0 1";
|
||||||
|
extent = "70 16";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
historySize = "0";
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "80 0";
|
||||||
|
extent = "104 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
internalName = "ColorEdit";
|
||||||
|
class = "ESettingsWindowColorEdit";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
};
|
||||||
|
new GuiSwatchButtonCtrl() {
|
||||||
|
color = "0 0 0 0";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
position = "188 2";
|
||||||
|
extent = "14 14";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "left";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
internalName = "ColorButton";
|
||||||
|
class = "ESettingsWindowColorButton";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
new GuiControl() {
|
||||||
|
position = "0 21";
|
||||||
|
extent = "206 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
class = "ESettingsWindowColor";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
editorSettingsRead = "NavEditorPlugin.readSettings();";
|
||||||
|
editorSettingsValue = "NavEditor/SelectedSplineColor";
|
||||||
|
editorSettingsWrite = "NavEditorPlugin.writeSettings();";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Sel. Spline:";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "0 1";
|
||||||
|
extent = "70 16";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextRightProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
};
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
historySize = "0";
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
maxLength = "1024";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "80 0";
|
||||||
|
extent = "104 18";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextEditProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
internalName = "ColorEdit";
|
||||||
|
class = "ESettingsWindowColorEdit";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
};
|
||||||
|
new GuiSwatchButtonCtrl() {
|
||||||
|
color = "0 0 0 0";
|
||||||
|
groupNum = "-1";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
position = "188 2";
|
||||||
|
extent = "14 14";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "left";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
internalName = "ColorButton";
|
||||||
|
class = "ESettingsWindowColorButton";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
//--- OBJECT WRITE END ---
|
||||||
144
Templates/Full/game/tools/navEditor/NavEditorToolbar.gui
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
//--- OBJECT WRITE BEGIN ---
|
||||||
|
%guiContent = new GuiControl(NavEditorToolbar,EditorGuiGroup) {
|
||||||
|
position = "306 0";
|
||||||
|
extent = "800 32";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "NavEditorToolbar";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
enabled = "1";
|
||||||
|
|
||||||
|
new GuiTextCtrl() {
|
||||||
|
text = "Navigation Editor";
|
||||||
|
maxLength = "255";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "1";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "6 6";
|
||||||
|
extent = "150 20";
|
||||||
|
minExtent = "8 8";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiTextProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiBitmapCtrl() {
|
||||||
|
bitmap = "core/art/gui/images/separator-h.png";
|
||||||
|
wrap = "0";
|
||||||
|
position = "90 3";
|
||||||
|
extent = "2 26";
|
||||||
|
minExtent = "1 1";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
new GuiButtonCtrl(NavEditorAboutBtn) {
|
||||||
|
text = "Console";
|
||||||
|
groupNum = "7";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
position = "100 6";
|
||||||
|
extent = "54 20";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "GuiButtonProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
command = "NavEditorConsoleDlg.setVisible(!NavEditorConsoleDlg.isVisible());";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
tooltip = "Show Console";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
canSave = "1";
|
||||||
|
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 = "GuiCheckBoxProfile";
|
||||||
|
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 = "GuiCheckBoxProfile";
|
||||||
|
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 = "GuiCheckBoxProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
variable = "$Nav::Editor::renderBVTree";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "0";
|
||||||
|
internalName = "BVTreeButton";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
//--- OBJECT WRITE END ---
|
||||||
BIN
Templates/Full/game/tools/navEditor/done.wav
Normal file
BIN
Templates/Full/game/tools/navEditor/images/nav-cover_d.png
Normal file
|
After Width: | Height: | Size: 525 B |
BIN
Templates/Full/game/tools/navEditor/images/nav-cover_h.png
Normal file
|
After Width: | Height: | Size: 633 B |
BIN
Templates/Full/game/tools/navEditor/images/nav-cover_n.png
Normal file
|
After Width: | Height: | Size: 307 B |
BIN
Templates/Full/game/tools/navEditor/images/nav-editor_d.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Templates/Full/game/tools/navEditor/images/nav-editor_h.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Templates/Full/game/tools/navEditor/images/nav-editor_n.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Templates/Full/game/tools/navEditor/images/nav-link_d.png
Normal file
|
After Width: | Height: | Size: 692 B |
BIN
Templates/Full/game/tools/navEditor/images/nav-link_h.png
Normal file
|
After Width: | Height: | Size: 894 B |
BIN
Templates/Full/game/tools/navEditor/images/nav-link_n.png
Normal file
|
After Width: | Height: | Size: 384 B |
285
Templates/Full/game/tools/navEditor/main.cs
Normal file
|
|
@ -0,0 +1,285 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// These values should align with enum PolyFlags in walkabout/nav.h
|
||||||
|
$Nav::WalkFlag = 1 << 0;
|
||||||
|
$Nav::SwimFlag = 1 << 1;
|
||||||
|
$Nav::JumpFlag = 1 << 2;
|
||||||
|
$Nav::LedgeFlag = 1 << 3;
|
||||||
|
$Nav::DropFlag = 1 << 4;
|
||||||
|
$Nav::ClimbFlag = 1 << 5;
|
||||||
|
$Nav::TeleportFlag = 1 << 6;
|
||||||
|
|
||||||
|
function initializeNavEditor()
|
||||||
|
{
|
||||||
|
echo(" % - Initializing Navigation Editor");
|
||||||
|
|
||||||
|
// Execute all relevant scripts and GUIs.
|
||||||
|
exec("./NavEditor.cs");
|
||||||
|
exec("./NavEditorGui.gui");
|
||||||
|
exec("./NavEditorToolbar.gui");
|
||||||
|
exec("./NavEditorConsoleDlg.gui");
|
||||||
|
exec("./CreateNewNavMeshDlg.gui");
|
||||||
|
|
||||||
|
// Add ourselves to EditorGui, where all the other tools reside
|
||||||
|
NavEditorGui.setVisible(false);
|
||||||
|
NavEditorToolbar.setVisible(false);
|
||||||
|
NavEditorOptionsWindow.setVisible(false);
|
||||||
|
NavEditorTreeWindow.setVisible(false);
|
||||||
|
NavEditorConsoleDlg.setVisible(false);
|
||||||
|
|
||||||
|
EditorGui.add(NavEditorGui);
|
||||||
|
EditorGui.add(NavEditorToolbar);
|
||||||
|
EditorGui.add(NavEditorOptionsWindow);
|
||||||
|
EditorGui.add(NavEditorTreeWindow);
|
||||||
|
EditorGui.add(NavEditorConsoleDlg);
|
||||||
|
|
||||||
|
new ScriptObject(NavEditorPlugin)
|
||||||
|
{
|
||||||
|
superClass = "EditorPlugin";
|
||||||
|
editorGui = NavEditorGui;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bind shortcuts for the nav editor.
|
||||||
|
%map = new ActionMap();
|
||||||
|
%map.bindCmd(keyboard, "1", "ENavEditorSelectModeBtn.performClick();", "");
|
||||||
|
%map.bindCmd(keyboard, "2", "ENavEditorLinkModeBtn.performClick();", "");
|
||||||
|
%map.bindCmd(keyboard, "3", "ENavEditorCoverModeBtn.performClick();", "");
|
||||||
|
%map.bindCmd(keyboard, "4", "ENavEditorTileModeBtn.performClick();", "");
|
||||||
|
%map.bindCmd(keyboard, "5", "ENavEditorTestModeBtn.performClick();", "");
|
||||||
|
%map.bindCmd(keyboard, "c", "NavEditorConsoleBtn.performClick();", "");
|
||||||
|
NavEditorPlugin.map = %map;
|
||||||
|
|
||||||
|
NavEditorPlugin.initSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyNavEditor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::onWorldEditorStartup(%this)
|
||||||
|
{
|
||||||
|
// Add ourselves to the window menu.
|
||||||
|
%accel = EditorGui.addToEditorsMenu("Navigation Editor", "", NavEditorPlugin);
|
||||||
|
|
||||||
|
// Add ourselves to the ToolsToolbar.
|
||||||
|
%tooltip = "Navigation Editor (" @ %accel @ ")";
|
||||||
|
EditorGui.addToToolsToolbar("NavEditorPlugin", "NavEditorPalette", expandFilename("tools/navEditor/images/nav-editor"), %tooltip);
|
||||||
|
|
||||||
|
GuiWindowCtrl::attach(NavEditorOptionsWindow, NavEditorTreeWindow);
|
||||||
|
|
||||||
|
// Add ourselves to the Editor Settings window.
|
||||||
|
exec("./NavEditorSettingsTab.gui");
|
||||||
|
ESettingsWindow.addTabPage(ENavEditorSettingsPage);
|
||||||
|
ENavEditorSettingsPage.init();
|
||||||
|
|
||||||
|
// Add items to World Editor Creator
|
||||||
|
EWCreatorWindow.beginGroup("Navigation");
|
||||||
|
|
||||||
|
EWCreatorWindow.registerMissionObject("CoverPoint", "Cover point");
|
||||||
|
|
||||||
|
EWCreatorWindow.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ENavEditorSettingsPage::init(%this)
|
||||||
|
{
|
||||||
|
// Initialises the settings controls in the settings dialog box.
|
||||||
|
%this-->SpawnClassOptions.clear();
|
||||||
|
%this-->SpawnClassOptions.add("AIPlayer");
|
||||||
|
%this-->SpawnClassOptions.setFirstSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::onActivated(%this)
|
||||||
|
{
|
||||||
|
%this.readSettings();
|
||||||
|
|
||||||
|
// Set a global variable so everyone knows we're editing!
|
||||||
|
$Nav::EditorOpen = true;
|
||||||
|
|
||||||
|
// Start off in Select mode.
|
||||||
|
ToolsPaletteArray->NavEditorSelectMode.performClick();
|
||||||
|
EditorGui.bringToFront(NavEditorGui);
|
||||||
|
|
||||||
|
NavEditorGui.setVisible(true);
|
||||||
|
NavEditorGui.makeFirstResponder(true);
|
||||||
|
NavEditorToolbar.setVisible(true);
|
||||||
|
|
||||||
|
NavEditorOptionsWindow.setVisible(true);
|
||||||
|
NavEditorTreeWindow.setVisible(true);
|
||||||
|
|
||||||
|
// Inspect the ServerNavMeshSet, which contains all the NavMesh objects
|
||||||
|
// in the mission.
|
||||||
|
if(!isObject(ServerNavMeshSet))
|
||||||
|
new SimSet(ServerNavMeshSet);
|
||||||
|
if(ServerNavMeshSet.getCount() == 0)
|
||||||
|
MessageBoxYesNo("No NavMesh", "There is no NavMesh in this level. Would you like to create one?" SPC
|
||||||
|
"If not, please use the Nav Editor to create a new NavMesh.",
|
||||||
|
"Canvas.pushDialog(CreateNewNavMeshDlg);");
|
||||||
|
NavTreeView.open(ServerNavMeshSet, true);
|
||||||
|
|
||||||
|
// Push our keybindings to the top. (See initializeNavEditor for where this
|
||||||
|
// map was created.)
|
||||||
|
%this.map.push();
|
||||||
|
|
||||||
|
// Store this on a dynamic field
|
||||||
|
// in order to restore whatever setting
|
||||||
|
// the user had before.
|
||||||
|
%this.prevGizmoAlignment = GlobalGizmoProfile.alignment;
|
||||||
|
|
||||||
|
// Always use Object alignment.
|
||||||
|
GlobalGizmoProfile.alignment = "Object";
|
||||||
|
|
||||||
|
// Set the status until some other editing mode adds useful information.
|
||||||
|
EditorGuiStatusBar.setInfo("Navigation editor.");
|
||||||
|
EditorGuiStatusBar.setSelection("");
|
||||||
|
|
||||||
|
// Allow the Gui to setup.
|
||||||
|
NavEditorGui.onEditorActivated();
|
||||||
|
|
||||||
|
Parent::onActivated(%this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::onDeactivated(%this)
|
||||||
|
{
|
||||||
|
%this.writeSettings();
|
||||||
|
|
||||||
|
$Nav::EditorOpen = false;
|
||||||
|
|
||||||
|
NavEditorGui.setVisible(false);
|
||||||
|
NavEditorToolbar.setVisible(false);
|
||||||
|
NavEditorOptionsWindow.setVisible(false);
|
||||||
|
NavEditorTreeWindow.setVisible(false);
|
||||||
|
%this.map.pop();
|
||||||
|
|
||||||
|
// Restore the previous Gizmo alignment settings.
|
||||||
|
GlobalGizmoProfile.alignment = %this.prevGizmoAlignment;
|
||||||
|
|
||||||
|
// Allow the Gui to cleanup.
|
||||||
|
NavEditorGui.onEditorDeactivated();
|
||||||
|
|
||||||
|
Parent::onDeactivated(%this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::onEditMenuSelect(%this, %editMenu)
|
||||||
|
{
|
||||||
|
%hasSelection = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::handleDelete(%this)
|
||||||
|
{
|
||||||
|
// Event happens when the user hits 'delete'.
|
||||||
|
NavEditorGui.deleteSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::handleEscape(%this)
|
||||||
|
{
|
||||||
|
return NavEditorGui.onEscapePressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::isDirty(%this)
|
||||||
|
{
|
||||||
|
return NavEditorGui.isDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::onSaveMission(%this, %missionFile)
|
||||||
|
{
|
||||||
|
if(NavEditorGui.isDirty)
|
||||||
|
{
|
||||||
|
MissionGroup.save(%missionFile);
|
||||||
|
NavEditorGui.isDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Settings
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function NavEditorPlugin::initSettings(%this)
|
||||||
|
{
|
||||||
|
EditorSettings.beginGroup("NavEditor", true);
|
||||||
|
|
||||||
|
EditorSettings.setDefaultValue("SpawnClass", "AIPlayer");
|
||||||
|
EditorSettings.setDefaultValue("SpawnDatablock", "DefaultPlayerData");
|
||||||
|
|
||||||
|
EditorSettings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::readSettings(%this)
|
||||||
|
{
|
||||||
|
EditorSettings.beginGroup("NavEditor", true);
|
||||||
|
|
||||||
|
// 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.spawnDatablock = EditorSettings.value("SpawnDatablock");
|
||||||
|
NavEditorGui.backgroundBuild = EditorSettings.value("BackgroundBuild");
|
||||||
|
NavEditorGui.saveIntermediates = EditorSettings.value("SaveIntermediates");
|
||||||
|
NavEditorGui.playSoundWhenDone = EditorSettings.value("PlaySoundWhenDone");
|
||||||
|
|
||||||
|
EditorSettings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorPlugin::writeSettings(%this)
|
||||||
|
{
|
||||||
|
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("SpawnDatablock", NavEditorGui.spawnDatablock);
|
||||||
|
EditorSettings.setValue("BackgroundBuild", NavEditorGui.backgroundBuild);
|
||||||
|
EditorSettings.setValue("SaveIntermediates", NavEditorGui.saveIntermediates);
|
||||||
|
EditorSettings.setValue("PlaySoundWhenDone", NavEditorGui.playSoundWhenDone);
|
||||||
|
|
||||||
|
EditorSettings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ESettingsWindowPopup::onWake(%this)
|
||||||
|
{
|
||||||
|
%this.setSelected(%this.findText(EditorSettings.value(%this.editorSettingsValue)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function ESettingsWindowPopup::onSelect(%this)
|
||||||
|
{
|
||||||
|
EditorSettings.setValue(%this.editorSettingsValue, %this.getText());
|
||||||
|
eval(%this.editorSettingsRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Demo
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function OnWalkaboutDemoLimit()
|
||||||
|
{
|
||||||
|
MessageBoxOK("Walkabout demo",
|
||||||
|
"This demo only allows two NavMeshes to be created. Sorry!");
|
||||||
|
}
|
||||||
|
|
||||||
|
function OnWalkaboutDemoSave()
|
||||||
|
{
|
||||||
|
MessageBoxOK("Walkabout demo",
|
||||||
|
"This demo doesn't allow you to save NavMeshes. Sorry!" SPC
|
||||||
|
"The rest of your mission will still be saved.");
|
||||||
|
}
|
||||||
360
Templates/Full/game/tools/navEditor/navEditor.cs
Normal file
|
|
@ -0,0 +1,360 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Daniel Buckmaster
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
$Nav::EditorOpen = false;
|
||||||
|
|
||||||
|
function NavEditorGui::onEditorActivated(%this)
|
||||||
|
{
|
||||||
|
if(%this.selectedObject)
|
||||||
|
%this.selectObject(%this.selectedObject);
|
||||||
|
%this.prepSelectionMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onEditorDeactivated(%this)
|
||||||
|
{
|
||||||
|
if(%this.getMesh())
|
||||||
|
%this.deselect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onModeSet(%this, %mode)
|
||||||
|
{
|
||||||
|
// Callback when the nav editor changes mode. Set the appropriate dynamic
|
||||||
|
// GUI contents in the properties/actions boxes.
|
||||||
|
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);
|
||||||
|
|
||||||
|
switch$(%mode)
|
||||||
|
{
|
||||||
|
case "SelectMode":
|
||||||
|
NavInspector.setVisible(true);
|
||||||
|
%actions->SelectActions.setVisible(true);
|
||||||
|
case "LinkMode":
|
||||||
|
%actions->LinkActions.setVisible(true);
|
||||||
|
%properties->LinkProperties.setVisible(true);
|
||||||
|
case "CoverMode":
|
||||||
|
//
|
||||||
|
%actions->CoverActions.setVisible(true);
|
||||||
|
case "TileMode":
|
||||||
|
%actions->TileActions.setVisible(true);
|
||||||
|
%properties->TileProperties.setVisible(true);
|
||||||
|
case "TestMode":
|
||||||
|
%actions->TestActions.setVisible(true);
|
||||||
|
%properties->TestProperties.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::paletteSync(%this, %mode)
|
||||||
|
{
|
||||||
|
// Synchronise the palette (small buttons on the left) with the actual mode
|
||||||
|
// the nav editor is in.
|
||||||
|
%evalShortcut = "ToolsPaletteArray-->" @ %mode @ ".setStateOn(1);";
|
||||||
|
eval(%evalShortcut);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onEscapePressed(%this)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::selectObject(%this, %obj)
|
||||||
|
{
|
||||||
|
NavTreeView.clearSelection();
|
||||||
|
if(isObject(%obj))
|
||||||
|
NavTreeView.selectItem(%obj);
|
||||||
|
%this.onObjectSelected(%obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onObjectSelected(%this, %obj)
|
||||||
|
{
|
||||||
|
if(isObject(%this.selectedObject))
|
||||||
|
%this.deselect();
|
||||||
|
%this.selectedObject = %obj;
|
||||||
|
if(isObject(%obj))
|
||||||
|
{
|
||||||
|
%this.selectMesh(%obj);
|
||||||
|
NavInspector.inspect(%obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::deleteMesh(%this)
|
||||||
|
{
|
||||||
|
if(isObject(%this.selectedObject))
|
||||||
|
{
|
||||||
|
%this.selectedObject.delete();
|
||||||
|
%this.selectObject(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::deleteSelected(%this)
|
||||||
|
{
|
||||||
|
switch$(%this.getMode())
|
||||||
|
{
|
||||||
|
case "SelectMode":
|
||||||
|
// Try to delete the selected NavMesh.
|
||||||
|
if(isObject(NavEditorGui.selectedObject))
|
||||||
|
MessageBoxYesNo("Warning",
|
||||||
|
"Are you sure you want to delete" SPC NavEditorGui.selectedObject.getName(),
|
||||||
|
"NavEditorGui.deleteMesh();");
|
||||||
|
case "TestMode":
|
||||||
|
%this.getPlayer().delete();
|
||||||
|
%this.onPlayerDeselected();
|
||||||
|
case "LinkMode":
|
||||||
|
%this.deleteLink();
|
||||||
|
%this.isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::buildSelectedMeshes(%this)
|
||||||
|
{
|
||||||
|
if(isObject(%this.getMesh()))
|
||||||
|
{
|
||||||
|
%this.getMesh().build(NavEditorGui.backgroundBuild, NavEditorGui.saveIntermediates);
|
||||||
|
%this.isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::buildLinks(%this)
|
||||||
|
{
|
||||||
|
if(isObject(%this.getMesh()))
|
||||||
|
{
|
||||||
|
%this.getMesh().buildLinks();
|
||||||
|
%this.isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLinkData(%control, %flags)
|
||||||
|
{
|
||||||
|
%control->LinkWalkFlag.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->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 getLinkFlags(%control)
|
||||||
|
{
|
||||||
|
return (%control->LinkWalkFlag.isStateOn() ? $Nav::WalkFlag : 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 disableLinkData(%control)
|
||||||
|
{
|
||||||
|
%control->LinkWalkFlag.setActive(false);
|
||||||
|
%control->LinkJumpFlag.setActive(false);
|
||||||
|
%control->LinkDropFlag.setActive(false);
|
||||||
|
%control->LinkLedgeFlag.setActive(false);
|
||||||
|
%control->LinkClimbFlag.setActive(false);
|
||||||
|
%control->LinkTeleportFlag.setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onLinkSelected(%this, %flags)
|
||||||
|
{
|
||||||
|
updateLinkData(NavEditorOptionsWindow-->LinkProperties, %flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onPlayerSelected(%this, %flags)
|
||||||
|
{
|
||||||
|
updateLinkData(NavEditorOptionsWindow-->TestProperties, %flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::updateLinkFlags(%this)
|
||||||
|
{
|
||||||
|
if(isObject(%this.getMesh()))
|
||||||
|
{
|
||||||
|
%properties = NavEditorOptionsWindow-->LinkProperties;
|
||||||
|
%this.setLinkFlags(getLinkFlags(%properties));
|
||||||
|
%this.isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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::onLinkDeselected(%this)
|
||||||
|
{
|
||||||
|
disableLinkData(NavEditorOptionsWindow-->LinkProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::onPlayerDeselected(%this)
|
||||||
|
{
|
||||||
|
disableLinkData(NavEditorOptionsWindow-->TestProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::createCoverPoints(%this)
|
||||||
|
{
|
||||||
|
if(isObject(%this.getMesh()))
|
||||||
|
{
|
||||||
|
%this.getMesh().createCoverPoints();
|
||||||
|
%this.isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::deleteCoverPoints(%this)
|
||||||
|
{
|
||||||
|
if(isObject(%this.getMesh()))
|
||||||
|
{
|
||||||
|
%this.getMesh().deleteCoverPoints();
|
||||||
|
%this.isDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::findCover(%this)
|
||||||
|
{
|
||||||
|
if(%this.getMode() $= "TestMode" && isObject(%this.getPlayer()))
|
||||||
|
{
|
||||||
|
%pos = LocalClientConnection.getControlObject().getPosition();
|
||||||
|
%text = NavEditorOptionsWindow-->TestProperties->CoverPosition.getText();
|
||||||
|
if(%text !$= "")
|
||||||
|
%pos = eval(%text);
|
||||||
|
%this.getPlayer().findCover(%pos, NavEditorOptionsWindow-->TestProperties->CoverRadius.getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::followObject(%this)
|
||||||
|
{
|
||||||
|
if(%this.getMode() $= "TestMode" && isObject(%this.getPlayer()))
|
||||||
|
{
|
||||||
|
%obj = LocalClientConnection.player;
|
||||||
|
%text = NavEditorOptionsWindow-->TestProperties->FollowObject.getText();
|
||||||
|
if(%text !$= "")
|
||||||
|
{
|
||||||
|
eval("%obj = " @ %text);
|
||||||
|
if(!isObject(%obj))
|
||||||
|
MessageBoxOk("Error", "Cannot find object" SPC %text);
|
||||||
|
}
|
||||||
|
if(isObject(%obj))
|
||||||
|
%this.getPlayer().followObject(%obj, NavEditorOptionsWindow-->TestProperties->FollowRadius.getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavInspector::inspect(%this, %obj)
|
||||||
|
{
|
||||||
|
%name = "";
|
||||||
|
if(isObject(%obj))
|
||||||
|
%name = %obj.getName();
|
||||||
|
else
|
||||||
|
NavFieldInfoControl.setText("");
|
||||||
|
|
||||||
|
Parent::inspect(%this, %obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavInspector::onInspectorFieldModified(%this, %object, %fieldName, %arrayIndex, %oldValue, %newValue)
|
||||||
|
{
|
||||||
|
// Same work to do as for the regular WorldEditor Inspector.
|
||||||
|
Inspector::onInspectorFieldModified(%this, %object, %fieldName, %arrayIndex, %oldValue, %newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavInspector::onFieldSelected(%this, %fieldName, %fieldTypeStr, %fieldDoc)
|
||||||
|
{
|
||||||
|
NavFieldInfoControl.setText("<font:ArialBold:14>" @ %fieldName @ "<font:ArialItalic:14> (" @ %fieldTypeStr @ ") " NL "<font:Arial:14>" @ %fieldDoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavTreeView::onInspect(%this, %obj)
|
||||||
|
{
|
||||||
|
NavInspector.inspect(%obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavTreeView::onSelect(%this, %obj)
|
||||||
|
{
|
||||||
|
NavInspector.inspect(%obj);
|
||||||
|
NavEditorGui.onObjectSelected(%obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavEditorGui::prepSelectionMode(%this)
|
||||||
|
{
|
||||||
|
%this.setMode("SelectMode");
|
||||||
|
ToolsPaletteArray-->NavEditorSelectMode.setStateOn(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function ENavEditorPaletteButton::onClick(%this)
|
||||||
|
{
|
||||||
|
// When clicking on a pelette button, add its description to the bottom of
|
||||||
|
// the editor window.
|
||||||
|
EditorGuiStatusBar.setInfo(%this.DetailedDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function NavMeshLinkFlagButton::onClick(%this)
|
||||||
|
{
|
||||||
|
NavEditorGui.updateLinkFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NavMeshTestFlagButton::onClick(%this)
|
||||||
|
{
|
||||||
|
NavEditorGui.updateTestFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
singleton GuiControlProfile(NavEditorProfile)
|
||||||
|
{
|
||||||
|
canKeyFocus = true;
|
||||||
|
opaque = true;
|
||||||
|
fillColor = "192 192 192 192";
|
||||||
|
category = "Editor";
|
||||||
|
};
|
||||||
|
|
||||||
|
singleton GuiControlProfile(GuiSimpleBorderProfile)
|
||||||
|
{
|
||||||
|
opaque = false;
|
||||||
|
border = 1;
|
||||||
|
category = "Editor";
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
%paletteId = new GuiControl(NavEditorPalette,EditorGuiGroup) {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "1";
|
||||||
|
Profile = "GuiDefaultProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "1024 768";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
hovertime = "1000";
|
||||||
|
|
||||||
|
new GuiBitmapButtonCtrl(ENavEditorSelectModeBtn) {
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
class = ENavEditorPaletteButton;
|
||||||
|
internalName = "NavEditorSelectMode";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "25 19";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
Command = "NavEditorGui.prepSelectionMode();";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
ToolTip = "View NavMesh (1).";
|
||||||
|
DetailedDesc = "";
|
||||||
|
hovertime = "1000";
|
||||||
|
bitmap = "tools/gui/images/menubar/visibility-toggle";
|
||||||
|
buttonType = "RadioButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
};
|
||||||
|
new GuiBitmapButtonCtrl(ENavEditorLinkModeBtn) {
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
class = ENavEditorPaletteButton;
|
||||||
|
internalName = "NavEditorLinkMode";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "25 19";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
Command = "NavEditorGui.setMode(\"LinkMode\");";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
ToolTip = "Create off-mesh links (2).";
|
||||||
|
DetailedDesc = "Click to select/add. Shift-click to add multiple end points.";
|
||||||
|
hovertime = "1000";
|
||||||
|
bitmap = "tools/navEditor/images/nav-link";
|
||||||
|
buttonType = "RadioButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
};
|
||||||
|
new GuiBitmapButtonCtrl(ENavEditorCoverModeBtn) {
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
class = ENavEditorPaletteButton;
|
||||||
|
internalName = "NavEditorCoverMode";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "25 19";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
Command = "NavEditorGui.setMode(\"CoverMode\");";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
ToolTip = "Edit cover (3).";
|
||||||
|
DetailedDesc = "";
|
||||||
|
hovertime = "1000";
|
||||||
|
bitmap = "tools/navEditor/images/nav-cover";
|
||||||
|
buttonType = "RadioButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
};
|
||||||
|
new GuiBitmapButtonCtrl(ENavEditorTileModeBtn) {
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
class = ENavEditorPaletteButton;
|
||||||
|
internalName = "NavEditorTileMode";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "25 19";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
Command = "NavEditorGui.setMode(\"TileMode\");";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
ToolTip = "View tiles (4).";
|
||||||
|
DetailedDesc = "Click to select.";
|
||||||
|
hovertime = "1000";
|
||||||
|
bitmap = "tools/gui/images/menubar/select-bounds";
|
||||||
|
buttonType = "RadioButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
};
|
||||||
|
new GuiBitmapButtonCtrl(ENavEditorTestModeBtn) {
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
class = ENavEditorPaletteButton;
|
||||||
|
internalName = "NavEditorTestMode";
|
||||||
|
Enabled = "1";
|
||||||
|
isContainer = "0";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "25 19";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "1";
|
||||||
|
Visible = "1";
|
||||||
|
Command = "NavEditorGui.setMode(\"TestMode\");";
|
||||||
|
tooltipprofile = "GuiToolTipProfile";
|
||||||
|
ToolTip = "Test pathfinding (5).";
|
||||||
|
DetailedDesc = "Click to select/move character, CTRL-click to spawn, SHIFT-click to deselect.";
|
||||||
|
hovertime = "1000";
|
||||||
|
bitmap = "tools/worldEditor/images/toolbar/3rd-person-camera";
|
||||||
|
buttonType = "RadioButton";
|
||||||
|
useMouseEvents = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
HorizSizing = "right";
|
HorizSizing = "right";
|
||||||
VertSizing = "bottom";
|
VertSizing = "bottom";
|
||||||
Position = "0 31";
|
Position = "0 31";
|
||||||
Extent = (29 + 4) * 14 + 12 SPC "33";
|
Extent = "0 33";
|
||||||
MinExtent = "8 2";
|
MinExtent = "8 2";
|
||||||
canSave = "1";
|
canSave = "1";
|
||||||
Visible = "1";
|
Visible = "1";
|
||||||
|
|
|
||||||
|
|
@ -384,6 +384,7 @@ function EditorGui::addToToolsToolbar( %this, %pluginName, %internalName, %bitma
|
||||||
useMouseEvents = "0";
|
useMouseEvents = "0";
|
||||||
};
|
};
|
||||||
ToolsToolbarArray.add(%button);
|
ToolsToolbarArray.add(%button);
|
||||||
|
EWToolsToolbar.setExtent((25 + 8) * (%count + 1) + 12 SPC "33");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,6 @@ function EWCreatorWindow::init( %this )
|
||||||
%this.registerMissionObject( "SFXSpace", "Sound Space" );
|
%this.registerMissionObject( "SFXSpace", "Sound Space" );
|
||||||
%this.registerMissionObject( "OcclusionVolume", "Occlusion Volume" );
|
%this.registerMissionObject( "OcclusionVolume", "Occlusion Volume" );
|
||||||
%this.registerMissionObject( "AccumulationVolume", "Accumulation Volume" );
|
%this.registerMissionObject( "AccumulationVolume", "Accumulation Volume" );
|
||||||
%this.registerMissionObject("NavMesh", "Navigation mesh");
|
|
||||||
%this.registerMissionObject("NavPath", "Path");
|
|
||||||
|
|
||||||
%this.endGroup();
|
%this.endGroup();
|
||||||
|
|
||||||
|
|
@ -788,4 +786,4 @@ function genericCreateObject( %class )
|
||||||
|
|
||||||
// In case the caller wants it.
|
// In case the caller wants it.
|
||||||
return %obj;
|
return %obj;
|
||||||
}
|
}
|
||||||
|
|
|
||||||