diff --git a/Engine/source/CMakeLists.txt b/Engine/source/CMakeLists.txt index 35d9d81d7..34991cce7 100644 --- a/Engine/source/CMakeLists.txt +++ b/Engine/source/CMakeLists.txt @@ -58,7 +58,7 @@ torqueAddSourceDirectories("platform" "platform/threads" "platform/async" torqueAddSourceDirectories("platform/nativeDialogs") # Handle T3D -torqueAddSourceDirectories( "T3D" "T3D/assets" "T3D/decal" "T3D/examples" "T3D/fps" "T3D/fx" +torqueAddSourceDirectories( "T3D" "T3D/AI" "T3D/assets" "T3D/decal" "T3D/examples" "T3D/fps" "T3D/fx" "T3D/gameBase" "T3D/gameBase/std" "T3D/lighting" "T3D/physics" diff --git a/Engine/source/T3D/AI/AIAimTarget.cpp b/Engine/source/T3D/AI/AIAimTarget.cpp new file mode 100644 index 000000000..35c7d927e --- /dev/null +++ b/Engine/source/T3D/AI/AIAimTarget.cpp @@ -0,0 +1,226 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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 "AIAimTarget.h" +#include "AIController.h" + +static U32 sAILoSMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType; + +F32 AIAimTarget::getTargetDistance(SceneObject* target, bool _checkEnabled) +{ + if (!target) + { + target = mObj.getPointer(); + if (!target) + return F32_MAX; + } + + if (_checkEnabled) + { + if (target->getTypeMask() & ShapeBaseObjectType) + { + ShapeBase* shapeBaseCheck = static_cast(target); + if (shapeBaseCheck) + if (shapeBaseCheck->getDamageState() != ShapeBase::Enabled) return false; + } + else + return F32_MAX; + } + + return (getPosition() - target->getPosition()).len(); +} + +bool AIAimTarget::checkInLos(SceneObject* target, bool _useMuzzle, bool _checkEnabled) +{ + ShapeBase* sbo = dynamic_cast(getCtrl()->getAIInfo()->mObj.getPointer()); + if (!target) + { + target = dynamic_cast(mObj.getPointer()); + if (!target) + return false; + } + if (_checkEnabled) + { + if (target->getTypeMask() & ShapeBaseObjectType) + { + ShapeBase* shapeBaseCheck = static_cast(target); + if (shapeBaseCheck) + if (shapeBaseCheck->getDamageState() != ShapeBase::Enabled) return false; + } + else + return false; + } + + RayInfo ri; + + sbo->disableCollision(); + + S32 mountCount = target->getMountedObjectCount(); + for (S32 i = 0; i < mountCount; i++) + { + target->getMountedObject(i)->disableCollision(); + } + + Point3F checkPoint; + if (_useMuzzle) + sbo->getMuzzlePoint(0, &checkPoint); + else + { + MatrixF eyeMat; + sbo->getEyeTransform(&eyeMat); + eyeMat.getColumn(3, &checkPoint); + } + + bool hit = !gServerContainer.castRay(checkPoint, target->getBoxCenter(), sAILoSMask, &ri); + sbo->enableCollision(); + + for (S32 i = 0; i < mountCount; i++) + { + target->getMountedObject(i)->enableCollision(); + } + return hit; +} + +bool AIAimTarget::checkInFoV(SceneObject* target, F32 camFov, bool _checkEnabled) +{ + ShapeBase* sbo = dynamic_cast(getCtrl()->getAIInfo()->mObj.getPointer()); + if (!target) + { + target = dynamic_cast(mObj.getPointer()); + if (!target) + return false; + } + if (_checkEnabled) + { + if (target->getTypeMask() & ShapeBaseObjectType) + { + ShapeBase* shapeBaseCheck = static_cast(target); + if (shapeBaseCheck) + if (shapeBaseCheck->getDamageState() != ShapeBase::Enabled) return false; + } + else + return false; + } + + MatrixF cam = sbo->getTransform(); + Point3F camPos; + VectorF camDir; + + cam.getColumn(3, &camPos); + cam.getColumn(1, &camDir); + + camFov = mDegToRad(camFov) / 2; + + Point3F shapePos = target->getBoxCenter(); + VectorF shapeDir = shapePos - camPos; + // Test to see if it's within our viewcone, this test doesn't + // actually match the viewport very well, should consider + // projection and box test. + shapeDir.normalize(); + F32 dot = mDot(shapeDir, camDir); + return (dot > mCos(camFov)); +} + +DefineEngineMethod(AIController, setAimLocation, void, (Point3F target), , + "@brief Tells the AIPlayer to aim at the location provided.\n\n" + + "@param target An \"x y z\" position in the game world to target.\n\n" + + "@see getAimLocation()\n") +{ + object->setAim(target); +} + +DefineEngineMethod(AIController, getAimLocation, Point3F, (), , + "@brief Returns the point the AIPlayer is aiming at.\n\n" + + "This will reflect the position set by setAimLocation(), " + "or the position of the object that the bot is now aiming at. " + "If the bot is not aiming at anything, this value will " + "change to whatever point the bot's current line-of-sight intercepts." + + "@return World space coordinates of the object AI is aiming at. Formatted as \"X Y Z\".\n\n" + + "@see setAimLocation()\n" + "@see setAimObject()\n") +{ + return object->getAim()->getPosition(); +} + +DefineEngineMethod(AIController, setAimObject, void, (const char* objName, Point3F offset), (Point3F::Zero), "( GameBase obj, [Point3F offset] )" + "Sets the bot's target object. Optionally set an offset from target location." + "@hide") +{ + // Find the target + SceneObject* targetObject; + if (Sim::findObject(objName, targetObject)) + { + + object->setAim(targetObject, 0.0f, offset); + } + else + object->setAim(0, 0.0f, offset); +} + +DefineEngineMethod(AIController, clearAim, void, (), , "clears the bot's target.") +{ + object->clearAim(); +} + +DefineEngineMethod(AIController, getAimObject, S32, (), , + "@brief Gets the object the AIPlayer is targeting.\n\n" + + "@return Returns -1 if no object is being aimed at, " + "or the SimObjectID of the object the AIPlayer is aiming at.\n\n" + + "@see setAimObject()\n") +{ + SceneObject* obj = dynamic_cast(object->getAim()->mObj.getPointer()); + return obj ? obj->getId() : -1; +} + + +DefineEngineMethod(AIController, getTargetDistance, F32, (SceneObject* obj, bool checkEnabled), (nullAsType(), false), + "@brief The distance to a given target.\n" + "@obj Object to check. (If blank, it will check the current target).\n" + "@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n") +{ + return object->getAim()->getTargetDistance(obj, checkEnabled); +} + +DefineEngineMethod(AIController, checkInLos, bool, (SceneObject* obj, bool useMuzzle, bool checkEnabled), (nullAsType(), false, false), + "@brief Check whether an object is in line of sight.\n" + "@obj Object to check. (If blank, it will check the current target).\n" + "@useMuzzle Use muzzle position. Otherwise use eye position. (defaults to false).\n" + "@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n") +{ + return object->getAim()->checkInLos(obj, useMuzzle, checkEnabled); +} + +DefineEngineMethod(AIController, checkInFoV, bool, (SceneObject* obj, F32 fov, bool checkEnabled), (nullAsType(), 45.0f, false), + "@brief Check whether an object is within a specified veiw cone.\n" + "@obj Object to check. (If blank, it will check the current target).\n" + "@fov view angle in degrees.(Defaults to 45)\n" + "@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n") +{ + return object->getAim()->checkInFoV(obj, fov, checkEnabled); +} diff --git a/Engine/source/T3D/AI/AIAimTarget.h b/Engine/source/T3D/AI/AIAimTarget.h new file mode 100644 index 000000000..4c609af27 --- /dev/null +++ b/Engine/source/T3D/AI/AIAimTarget.h @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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 _AIAIMTARGET_H_ +#define _AIAIMTARGET_H_ + +#include "AIInfo.h" +struct AIAimTarget : public AIInfo +{ + typedef AIInfo Parent; + Point3F mAimOffset; + bool mTargetInLOS; // Is target object visible? + Point3F getPosition() { return ((mObj.isValid()) ? mObj->getPosition() : mPosition) + mAimOffset; } + bool checkInLos(SceneObject* target = NULL, bool _useMuzzle = false, bool _checkEnabled = false); + bool checkInFoV(SceneObject* target = NULL, F32 camFov = 45.0f, bool _checkEnabled = false); + F32 getTargetDistance(SceneObject* target, bool _checkEnabled); + AIAimTarget() = delete; + AIAimTarget(AIController* controller) : Parent(controller) { mTargetInLOS = false; }; + AIAimTarget(AIController* controller, SimObjectPtr objIn, F32 radIn) : Parent(controller, objIn, radIn) { mTargetInLOS = false; }; + AIAimTarget(AIController* controller, Point3F pointIn, F32 radIn) : Parent(controller, pointIn, radIn) { mTargetInLOS = false; }; +}; + +#endif diff --git a/Engine/source/T3D/AI/AIController.cpp b/Engine/source/T3D/AI/AIController.cpp new file mode 100644 index 000000000..e54b173bb --- /dev/null +++ b/Engine/source/T3D/AI/AIController.cpp @@ -0,0 +1,916 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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 "AIController.h" +#include "T3D/player.h" +#include "T3D/rigidShape.h" +#include "T3D/vehicles/wheeledVehicle.h" +#include "T3D/vehicles/flyingVehicle.h" + + +IMPLEMENT_CONOBJECT(AIController); + +//----------------------------------------------------------------------------- +void AIController::throwCallback(const char* name) +{ + //Con::warnf("throwCallback: %s", name); + Con::executef(mControllerData, name, getIdString()); //controller data callbacks + + GameBase* gbo = dynamic_cast(getAIInfo()->mObj.getPointer()); + if (!gbo) return; + Con::executef(gbo->getDataBlock(), name, getAIInfo()->mObj->getIdString()); //legacy support for object db callbacks +} + +void AIController::initPersistFields() +{ + addProtectedField("ControllerData", TYPEID< AIControllerData >(), Offset(mControllerData, AIController), + &setControllerDataProperty, &defaultProtectedGetFn, + "Script datablock used for game objects."); + addFieldV("MoveSpeed", TypeRangedF32, Offset(mMovement.mMoveSpeed, AIController), &CommonValidators::PositiveFloat, + "@brief default move sepeed."); +} + +bool AIController::setControllerDataProperty(void* obj, const char* index, const char* db) +{ + if (db == NULL || !db[0]) + { + Con::errorf("AIController::setControllerDataProperty - Can't unset ControllerData on AIController objects"); + return false; + } + + AIController* object = static_cast(obj); + AIControllerData* data; + if (Sim::findObject(db, data)) + { + object->mControllerData = data; + return true; + } + Con::errorf("AIController::setControllerDataProperty - Could not find ControllerData \"%s\"", db); + return false; +} + +void AIController::setGoal(AIInfo* targ) +{ + if (mGoal) { delete(mGoal); mGoal = NULL; } + + if (targ->mObj.isValid()) + { + delete(mGoal); + mGoal = new AIGoal(this, targ->mObj, targ->mRadius); + } + else if (targ->mPosSet) + { + delete(mGoal); + mGoal = new AIGoal(this, targ->mPosition, targ->mRadius); + } +} + +void AIController::setGoal(Point3F loc, F32 rad) +{ + if (mGoal) delete(mGoal); + mGoal = new AIGoal(this, loc, rad); +} + +void AIController::setGoal(SimObjectPtr objIn, F32 rad) +{ + if (mGoal) delete(mGoal); + mGoal = new AIGoal(this, objIn, rad); +} + +void AIController::setAim(Point3F loc, F32 rad, Point3F offset) +{ + if (mAimTarget) delete(mAimTarget); + mAimTarget = new AIAimTarget(this, loc, rad); + mAimTarget->mAimOffset = offset; +} + +void AIController::setAim(SimObjectPtr objIn, F32 rad, Point3F offset) +{ + if (mAimTarget) delete(mAimTarget); + mAimTarget = new AIAimTarget(this, objIn, rad); + mAimTarget->mAimOffset = offset; +} + +bool AIController::getAIMove(Move* movePtr) +{ + *movePtr = NullMove; + ShapeBase* sbo = dynamic_cast(getAIInfo()->mObj.getPointer()); + if (!sbo) return false; + + // Use the eye as the current position. + MatrixF eye; + sbo->getEyeTransform(&eye); + Point3F location = eye.getPosition(); + Point3F rotation = sbo->getTransform().toEuler(); + + // 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, + // which is not very accurate. + if (getAim() && getAim()->mObj) + { + GameBase* gbo = dynamic_cast(getAIInfo()->mObj.getPointer()); + if (getAim()->checkInLos(gbo)) + { + if (!getAim()->mTargetInLOS) + { + throwCallback("onTargetEnterLOS"); + getAim()->mTargetInLOS = true; + } + } + else if (getAim()->mTargetInLOS) + { + throwCallback("onTargetExitLOS"); + getAim()->mTargetInLOS = false; + } + } + + if (sbo->getDamageState() == ShapeBase::Enabled && getGoal()) + { +#ifdef TORQUE_NAVIGATION_ENABLED + if (mMovement.mMoveState != ModeStop) + getNav()->updateNavMesh(); + + if (getNav()->mPathData.path.isNull()) + { + if (getGoal()->getDist() > mControllerData->mFollowTolerance) + { + if (getGoal()->mObj.isValid()) + getNav()->followObject(getGoal()->mObj, mControllerData->mFollowTolerance); + else if (getGoal()->mPosSet) + getNav()->setPathDestination(getGoal()->getPosition(true)); + } + } + else + { + if (getGoal()->getDist() > mControllerData->mFollowTolerance) + { + SceneObject* obj = getAIInfo()->mObj->getObjectMount(); + if (!obj) + { + obj = getAIInfo()->mObj; + } + RayInfo info; + if (obj->getContainer()->castRay(obj->getPosition(), obj->getPosition() - Point3F(0, 0, mControllerData->mHeightTolerance), StaticShapeObjectType, &info)) + { + getNav()->repath(); + } + getGoal()->mInRange = false; + } + if (getGoal()->getDist() < mControllerData->mFollowTolerance ) + { + getNav()->clearPath(); + mMovement.mMoveState = ModeStop; + + if (!getGoal()->mInRange) + { + getGoal()->mInRange = true; + throwCallback("onTargetInRange"); + } + else getGoal()->mInRange = false; + } + else + { + if (getGoal()->getDist() < mControllerData->mAttackRadius ) + { + if (!getGoal()->mInFiringRange) + { + getGoal()->mInFiringRange = true; + throwCallback("onTargetInFiringRange"); + } + } + else getGoal()->mInFiringRange = false; + } + } +#else + if (getGoal()->getDist() > mControllerData->mFollowTolerance) + { + if (getGoal()->mObj.isValid()) + getNav()->followObject(getGoal()->mObj, mControllerData->mFollowTolerance); + else if (getGoal()->mPosSet) + getNav()->setPathDestination(getGoal()->getPosition(true)); + + getGoal()->mInRange = false; + } + if (getGoal()->getDist() < mControllerData->mFollowTolerance) + { + mMovement.mMoveState = ModeStop; + + if (!getGoal()->mInRange) + { + getGoal()->mInRange = true; + throwCallback("onTargetInRange"); + } + else getGoal()->mInRange = false; + } + else + { + if (getGoal()->getDist() < mControllerData->mAttackRadius) + { + if (!getGoal()->mInFiringRange) + { + getGoal()->mInFiringRange = true; + throwCallback("onTargetInFiringRange"); + } + } + else getGoal()->mInFiringRange = false; + } +#endif // TORQUE_NAVIGATION_ENABLED + } + // Orient towards the aim point, aim object, or towards + // our destination. + if (getAim() || mMovement.mMoveState != ModeStop) + { + // Update the aim position if we're aiming for an object or explicit position + if (getAim()) + mMovement.mAimLocation = getAim()->getPosition(); + else + mMovement.mAimLocation = getNav()->getMoveDestination(); + + mControllerData->resolveYawPtr(this, location, movePtr); + mControllerData->resolvePitchPtr(this, location, movePtr); + mControllerData->resolveRollPtr(this, location, movePtr); + + if (mMovement.mMoveState != AIController::ModeStop) + { + F32 xDiff = getNav()->getMoveDestination().x - location.x; + F32 yDiff = getNav()->getMoveDestination().y - location.y; + if (mFabs(xDiff) < mControllerData->mMoveTolerance && mFabs(yDiff) < mControllerData->mMoveTolerance) + { + getNav()->onReachDestination(); + } + else + { + mControllerData->resolveSpeedPtr(this, location, movePtr); + mControllerData->resolveStuckPtr(this); + } + } + } + + mControllerData->resolveTriggerStatePtr(this, movePtr); + + getAIInfo()->mLastPos = getAIInfo()->getPosition(); + return true; +} + +void AIController::clearCover() +{ + // Notify cover that we are no longer on our way. + if (getCover() && !getCover()->mCoverPoint.isNull()) + getCover()->mCoverPoint->setOccupied(false); + SAFE_DELETE(mCover); +} + +void AIController::Movement::stopMove() +{ + mMoveState = ModeStop; +#ifdef TORQUE_NAVIGATION_ENABLED + getCtrl()->getNav()->clearPath(); + getCtrl()->clearCover(); + getCtrl()->getNav()->clearFollow(); +#endif +} +void AIController::Movement::onStuck() +{ + mMoveState = AIController::ModeStuck; + getCtrl()->throwCallback("onMoveStuck"); +#ifdef TORQUE_NAVIGATION_ENABLED + if (!getCtrl()->getNav()->getPath().isNull()) + getCtrl()->getNav()->repath(); +#endif +} + +DefineEngineMethod(AIController, setMoveSpeed, void, (F32 speed), , + "@brief Sets the move speed for an AI object.\n\n" + + "@param speed A speed multiplier between 0.0 and 1.0. " + "This is multiplied by the AIController controlled object's base movement rates (as defined in " + "its PlayerData datablock)\n\n" + + "@see getMoveDestination()\n") +{ + object->mMovement.setMoveSpeed(speed); +} + +DefineEngineMethod(AIController, getMoveSpeed, F32, (), , + "@brief Gets the move speed of an AI object.\n\n" + + "@return A speed multiplier between 0.0 and 1.0.\n\n" + + "@see setMoveSpeed()\n") +{ + return object->mMovement.getMoveSpeed(); +} + +DefineEngineMethod(AIController, stop, void, (), , + "@brief Tells the AIController controlled object to stop moving.\n\n") +{ + object->mMovement.stopMove(); +} + + +/** + * Set the state of a movement trigger. + * + * @param slot The trigger slot to set + * @param isSet set/unset the trigger + */ +void AIController::TriggerState::setMoveTrigger(U32 slot, const bool isSet) +{ + if (slot >= MaxTriggerKeys) + { + Con::errorf("Attempting to set an invalid trigger slot (%i)", slot); + } + else + { + mMoveTriggers[slot] = isSet; // set the trigger + mControllerRef->getAIInfo()->mObj->setMaskBits(ShapeBase::NoWarpMask); // force the client to updateMove + } +} + +/** + * Get the state of a movement trigger. + * + * @param slot The trigger slot to query + * @return True if the trigger is set, false if it is not set + */ +bool AIController::TriggerState::getMoveTrigger(U32 slot) const +{ + if (slot >= MaxTriggerKeys) + { + Con::errorf("Attempting to get an invalid trigger slot (%i)", slot); + return false; + } + else + { + return mMoveTriggers[slot]; + } +} + +/** + * Clear the trigger state for all movement triggers. + */ +void AIController::TriggerState::clearMoveTriggers() +{ + for (U32 i = 0; i < MaxTriggerKeys; i++) + setMoveTrigger(i, false); +} + +//----------------------------------------------------------------------------- + +IMPLEMENT_CO_DATABLOCK_V1(AIControllerData); +void AIControllerData::resolveYaw(AIController* obj, Point3F location, Move* move) +{ + F32 xDiff = obj->mMovement.mAimLocation.x - location.x; + F32 yDiff = obj->mMovement.mAimLocation.y - location.y; + Point3F rotation = obj->getAIInfo()->mObj->getTransform().toEuler(); + + if (!mIsZero(xDiff) || !mIsZero(yDiff)) + { + // First do Yaw + // use the cur yaw between -Pi and Pi + F32 curYaw = rotation.z; + while (curYaw > M_2PI_F) + curYaw -= M_2PI_F; + while (curYaw < -M_2PI_F) + curYaw += M_2PI_F; + + // find the yaw offset + F32 newYaw = mAtan2(xDiff, yDiff); + F32 yawDiff = newYaw - curYaw; + + // make it between 0 and 2PI + if (yawDiff < 0.0f) + yawDiff += M_2PI_F; + else if (yawDiff >= M_2PI_F) + yawDiff -= M_2PI_F; + + // now make sure we take the short way around the circle + if (yawDiff > M_PI_F) + yawDiff -= M_2PI_F; + else if (yawDiff < -M_PI_F) + yawDiff += M_2PI_F; + + move->yaw = yawDiff; + } +} + + +void AIControllerData::resolveRoll(AIController* obj, Point3F location, Move* movePtr) +{ +} + +void AIControllerData::resolveSpeed(AIController* obj, Point3F location, Move* movePtr) +{ + F32 xDiff = obj->getNav()->getMoveDestination().x - location.x; + F32 yDiff = obj->getNav()->getMoveDestination().y - location.y; + Point3F rotation = obj->getAIInfo()->mObj->getTransform().toEuler(); + + // Build move direction in world space + if (mIsZero(xDiff)) + movePtr->y = (location.y > obj->getNav()->getMoveDestination().y) ? -1.0f : 1.0f; + else + { + if (mIsZero(yDiff)) + movePtr->x = (location.x > obj->getNav()->getMoveDestination().x) ? -1.0f : 1.0f; + else + { + if (mFabs(xDiff) > mFabs(yDiff)) + { + F32 value = mFabs(yDiff / xDiff); + movePtr->y = (location.y > obj->getNav()->getMoveDestination().y) ? -value : value; + movePtr->x = (location.x > obj->getNav()->getMoveDestination().x) ? -1.0f : 1.0f; + } + else + { + F32 value = mFabs(xDiff / yDiff); + movePtr->x = (location.x > obj->getNav()->getMoveDestination().x) ? -value : value; + movePtr->y = (location.y > obj->getNav()->getMoveDestination().y) ? -1.0f : 1.0f; + } + } + } + // Rotate the move into object space (this really only needs + // a 2D matrix) + Point3F newMove; + MatrixF moveMatrix; + moveMatrix.set(EulerF(0.0f, 0.0f, -(rotation.z + movePtr->yaw))); + moveMatrix.mulV(Point3F(movePtr->x, movePtr->y, 0.0f), &newMove); + movePtr->x = newMove.x; + movePtr->y = newMove.y; + + // Set movement speed. We'll slow down once we get close + // to try and stop on the spot... + if (obj->mMovement.mMoveSlowdown) + { + F32 speed = obj->mMovement.mMoveSpeed; + F32 dist = mSqrt(xDiff * xDiff + yDiff * yDiff); + F32 maxDist = mMoveTolerance * 2; + if (dist < maxDist) + speed *= dist / maxDist; + movePtr->x *= speed; + movePtr->y *= speed; + } + else + { + movePtr->x *= obj->mMovement.mMoveSpeed; + movePtr->y *= obj->mMovement.mMoveSpeed; + } +} + +void AIControllerData::resolveTriggerState(AIController* obj, Move* movePtr) +{ + //check for scripted overides + for (U32 slot = 0; slot < MaxTriggerKeys; slot++) + { + movePtr->trigger[slot] = obj->mTriggerState.mMoveTriggers[slot]; + } +} + +void AIControllerData::resolveStuck(AIController* obj) +{ + if (obj->mMovement.mMoveState < AIController::ModeSlowing) return; + if (!obj->getGoal()) return; + ShapeBase* sbo = dynamic_cast(obj->getAIInfo()->mObj.getPointer()); + // Don't check for ai stuckness if animation during + // an anim-clip effect override. + if (sbo->getDamageState() == ShapeBase::Enabled && !(sbo->anim_clip_flags & ShapeBase::ANIM_OVERRIDDEN) && !sbo->isAnimationLocked()) + { + // We should check to see if we are stuck... + F32 locationDelta = (obj->getAIInfo()->getPosition() - obj->getAIInfo()->mLastPos).len(); + if (locationDelta < mMoveStuckTolerance) + { + if (obj->mMovement.mMoveStuckTestCountdown > 0) + --obj->mMovement.mMoveStuckTestCountdown; + else + { + // If we are slowing down, then it's likely that our location delta will be less than + // our move stuck tolerance. Because we can be both slowing and stuck + // we should TRY to check if we've moved. This could use better detection. + if (obj->mMovement.mMoveState != AIController::ModeSlowing || locationDelta == 0) + { + obj->mMovement.onStuck(); + obj->mMovement.mMoveStuckTestCountdown = obj->mControllerData->mMoveStuckTestDelay; + } + } + } + } +} + +AIControllerData::AIControllerData() +{ + mMoveTolerance = 0.25f; + mAttackRadius = 2.0f; + mMoveStuckTolerance = 0.01f; + mMoveStuckTestDelay = 30; + mHeightTolerance = 0.001f; + mFollowTolerance = 1.0f; + +#ifdef TORQUE_NAVIGATION_ENABLED + mLinkTypes = LinkData(AllFlags); + mNavSize = AINavigation::Regular; + mFlocking.mChance = 90; + mFlocking.mMin = 1.0f; + mFlocking.mMax = 3.0f; + mFlocking.mSideStep = 0.01f; +#endif + resolveYawPtr.bind(this, &AIControllerData::resolveYaw); + resolvePitchPtr.bind(this, &AIControllerData::resolvePitch); + resolveRollPtr.bind(this, &AIControllerData::resolveRoll); + resolveSpeedPtr.bind(this, &AIControllerData::resolveSpeed); + resolveTriggerStatePtr.bind(this, &AIControllerData::resolveTriggerState); + resolveStuckPtr.bind(this, &AIControllerData::resolveStuck); +} + +AIControllerData::AIControllerData(const AIControllerData& other, bool temp_clone) : SimDataBlock(other, temp_clone) +{ + mMoveTolerance = other.mMoveTolerance; + mAttackRadius = other.mAttackRadius; + mMoveStuckTolerance = other.mMoveStuckTolerance; + mMoveStuckTestDelay = other.mMoveStuckTestDelay; + mHeightTolerance = other.mHeightTolerance; + mFollowTolerance = other.mFollowTolerance; + +#ifdef TORQUE_NAVIGATION_ENABLED + mLinkTypes = other.mLinkTypes; + mNavSize = other.mNavSize; + mFlocking.mChance = other.mFlocking.mChance; + mFlocking.mMin = other.mFlocking.mMin; + mFlocking.mMax = other.mFlocking.mMax; + mFlocking.mSideStep = other.mFlocking.mSideStep; +#endif + + resolveYawPtr.bind(this, &AIControllerData::resolveYaw); + resolvePitchPtr.bind(this, &AIControllerData::resolvePitch); + resolveRollPtr.bind(this, &AIControllerData::resolveRoll); + resolveSpeedPtr.bind(this, &AIControllerData::resolveSpeed); + resolveTriggerStatePtr.bind(this, &AIControllerData::resolveTriggerState); + resolveStuckPtr.bind(this, &AIControllerData::resolveStuck); +} + +void AIControllerData::initPersistFields() +{ + docsURL; + addGroup("AI"); + + addFieldV("moveTolerance", TypeRangedF32, Offset(mMoveTolerance, AIControllerData), &CommonValidators::PositiveFloat, + "@brief Distance from destination before stopping.\n\n" + "When the AIController controlled object is moving to a given destination it will move to within " + "this distance of the destination and then stop. By providing this tolerance " + "it helps the AIController controlled object from never reaching its destination due to minor obstacles, " + "rounding errors on its position calculation, etc. By default it is set to 0.25.\n"); + + addFieldV("followTolerance", TypeRangedF32, Offset(mFollowTolerance, AIControllerData), &CommonValidators::PositiveFloat, + "@brief Distance from destination before stopping.\n\n" + "When the AIController controlled object is moving to a given destination it will move to within " + "this distance of the destination and then stop. By providing this tolerance " + "it helps the AIController controlled object from never reaching its destination due to minor obstacles, " + "rounding errors on its position calculation, etc. By default it is set to 0.25.\n"); + + addFieldV("AttackRadius", TypeRangedF32, Offset(mAttackRadius, AIControllerData), &CommonValidators::PositiveFloat, + "@brief Distance considered in firing range for callback purposes."); + + addFieldV("moveStuckTolerance", TypeRangedF32, Offset(mMoveStuckTolerance, AIControllerData), &CommonValidators::PositiveFloat, + "@brief Distance tolerance on stuck check.\n\n" + "When the AIController controlled object controlled object is moving to a given destination, if it ever moves less than " + "this tolerance during a single tick, the AIController controlled object is considered stuck. At this point " + "the onMoveStuck() callback is called on the datablock.\n"); + + addFieldV("HeightTolerance", TypeRangedF32, Offset(mHeightTolerance, AIControllerData), &CommonValidators::PositiveFloat, + "@brief Distance from destination before stopping.\n\n" + "When the AIController controlled object is moving to a given destination it will move to within " + "this distance of the destination and then stop. By providing this tolerance " + "it helps the AIController controlled object from never reaching its destination due to minor obstacles, " + "rounding errors on its position calculation, etc. By default it is set to 0.25.\n"); + + addFieldV("moveStuckTestDelay", TypeRangedS32, Offset(mMoveStuckTestDelay, AIControllerData), &CommonValidators::PositiveInt, + "@brief The number of ticks to wait before testing if the AIController controlled object is stuck.\n\n" + "When the AIController controlled object is asked to move, this property is the number of ticks to wait " + "before the AIController controlled object starts to check if it is stuck. This delay allows the AIController controlled object " + "to accelerate to full speed without its initial slow start being considered as stuck.\n" + "@note Set to zero to have the stuck test start immediately.\n"); + endGroup("AI"); + +#ifdef TORQUE_NAVIGATION_ENABLED + addGroup("Pathfinding"); + addFieldV("FlockChance", TypeRangedS32, Offset(mFlocking.mChance, AIControllerData), &CommonValidators::S32Percent, + "@brief chance of flocking."); + addFieldV("FlockMin", TypeRangedF32, Offset(mFlocking.mMin, AIControllerData), &CommonValidators::PositiveFloat, + "@brief min flocking separation distance."); + addFieldV("FlockMax", TypeRangedF32, Offset(mFlocking.mMax, AIControllerData), &CommonValidators::PositiveFloat, + "@brief max flocking clustering distance."); + addFieldV("FlockSideStep", TypeRangedF32, Offset(mFlocking.mSideStep, AIControllerData), &CommonValidators::PositiveFloat, + "@brief Distance from destination before we stop moving out of the way."); + + addField("allowWalk", TypeBool, Offset(mLinkTypes.walk, AIControllerData), + "Allow the character to walk on dry land."); + addField("allowJump", TypeBool, Offset(mLinkTypes.jump, AIControllerData), + "Allow the character to use jump links."); + addField("allowDrop", TypeBool, Offset(mLinkTypes.drop, AIControllerData), + "Allow the character to use drop links."); + addField("allowSwim", TypeBool, Offset(mLinkTypes.swim, AIControllerData), + "Allow the character to move in water."); + addField("allowLedge", TypeBool, Offset(mLinkTypes.ledge, AIControllerData), + "Allow the character to jump ledges."); + addField("allowClimb", TypeBool, Offset(mLinkTypes.climb, AIControllerData), + "Allow the character to use climb links."); + addField("allowTeleport", TypeBool, Offset(mLinkTypes.teleport, AIControllerData), + "Allow the character to use teleporters."); + + endGroup("Pathfinding"); +#endif // TORQUE_NAVIGATION_ENABLED + + Parent::initPersistFields(); +} + +void AIControllerData::packData(BitStream* stream) +{ + Parent::packData(stream); + stream->write(mMoveTolerance); + stream->write(mAttackRadius); + stream->write(mMoveStuckTolerance); + stream->write(mMoveStuckTestDelay); + stream->write(mHeightTolerance); + stream->write(mFollowTolerance); + +#ifdef TORQUE_NAVIGATION_ENABLED + //enums + stream->write(mLinkTypes.getFlags()); + stream->write((U32)mNavSize); + // end enums + stream->write(mFlocking.mChance); + stream->write(mFlocking.mMin); + stream->write(mFlocking.mMax); + stream->write(mFlocking.mSideStep); +#endif // TORQUE_NAVIGATION_ENABLED +}; + +void AIControllerData::unpackData(BitStream* stream) +{ + Parent::unpackData(stream); + + stream->read(&mMoveTolerance); + stream->read(&mAttackRadius); + stream->read(&mMoveStuckTolerance); + stream->read(&mMoveStuckTestDelay); + stream->read(&mHeightTolerance); + stream->read(&mFollowTolerance); + +#ifdef TORQUE_NAVIGATION_ENABLED + //enums + U16 linkFlags; + stream->read(&linkFlags); + mLinkTypes = LinkData(linkFlags); + U32 navSize; + stream->read(&navSize); + mNavSize = (AINavigation::NavSize)(navSize); + // end enums + stream->read(&(mFlocking.mChance)); + stream->read(&(mFlocking.mMin)); + stream->read(&(mFlocking.mMax)); + stream->read(&(mFlocking.mSideStep)); +#endif // TORQUE_NAVIGATION_ENABLED +}; +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +IMPLEMENT_CO_DATABLOCK_V1(AIPlayerControllerData); +void AIPlayerControllerData::resolvePitch(AIController* obj, Point3F location, Move* movePtr) +{ + Player* po = dynamic_cast(obj->getAIInfo()->mObj.getPointer()); + if (!po) return;//not a player + + if (obj->getAim() || obj->mMovement.mMoveState != AIController::ModeStop) + { + // Next do pitch. + if (!obj->getAim()) + { + // Level out if were just looking at our next way point. + Point3F headRotation = po->getHeadRotation(); + movePtr->pitch = -headRotation.x; + } + else + { + F32 xDiff = obj->mMovement.mAimLocation.x - location.x; + F32 yDiff = obj->mMovement.mAimLocation.y - location.y; + // This should be adjusted to run from the + // eye point to the object's center position. Though this + // works well enough for now. + F32 vertDist = obj->mMovement.mAimLocation.z - location.z; + F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff); + F32 newPitch = mAtan2(horzDist, vertDist) - (M_PI_F / 2.0f); + if (mFabs(newPitch) > 0.01f) + { + Point3F headRotation = po->getHeadRotation(); + movePtr->pitch = newPitch - headRotation.x; + } + } + } + else + { + // Level out if we're not doing anything else + Point3F headRotation = po->getHeadRotation(); + movePtr->pitch = -headRotation.x; + } +} + +void AIPlayerControllerData::resolveTriggerState(AIController* obj, Move* movePtr) +{ + Parent::resolveTriggerState(obj, movePtr); +#ifdef TORQUE_NAVIGATION_ENABLED + if (obj->getNav()->mJump == AINavigation::Now) + { + movePtr->trigger[2] = true; + obj->getNav()->mJump = AINavigation::None; + } + else if (obj->getNav()->mJump == AINavigation::Ledge) + { + // If we're not touching the ground, jump! + RayInfo info; + if (!obj->getAIInfo()->mObj->getContainer()->castRay(obj->getAIInfo()->getPosition(), obj->getAIInfo()->getPosition() - Point3F(0, 0, 0.4f), StaticShapeObjectType, &info)) + { + movePtr->trigger[2] = true; + obj->getNav()->mJump = AINavigation::None; + } + } +#endif // TORQUE_NAVIGATION_ENABLED +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +IMPLEMENT_CO_DATABLOCK_V1(AIWheeledVehicleControllerData); + +void AIWheeledVehicleControllerData::resolveYaw(AIController* obj, Point3F location, Move* movePtr) +{ + if (obj->mMovement.mMoveState < AIController::ModeSlowing) return; + WheeledVehicle* wvo = dynamic_cast(obj->getAIInfo()->mObj.getPointer()); + if (!wvo) + { + //cover the case of a connection controling an object in turn controlling another + if (obj->getAIInfo()->mObj->getObjectMount()) + wvo = dynamic_cast(obj->getAIInfo()->mObj->getObjectMount()); + } + if (!wvo) return;//not a WheeledVehicle + + F32 lastYaw = wvo->getSteering().x; + + Point3F right = wvo->getTransform().getRightVector(); + right.normalize(); + Point3F aimLoc = obj->mMovement.mAimLocation; + + // Get the AI to Target vector and normalize it. + Point3F toTarg = (location + wvo->getVelocity() * TickSec) - aimLoc; + toTarg.normalize(); + + F32 dotYaw = -mDot(right, toTarg); + movePtr->yaw = -lastYaw; + + VehicleData* vd = (VehicleData*)(wvo->getDataBlock()); + F32 maxSteeringAngle = vd->maxSteeringAngle; + + if (mFabs(dotYaw) > maxSteeringAngle*1.5f) + dotYaw *= -1.0f; + + if (dotYaw > maxSteeringAngle) dotYaw = maxSteeringAngle; + if (dotYaw < -maxSteeringAngle) dotYaw = -maxSteeringAngle; + + if (mFabs(dotYaw) > 0.05f) + movePtr->yaw = dotYaw - lastYaw; +}; + +void AIWheeledVehicleControllerData::resolveSpeed(AIController* obj, Point3F location, Move* movePtr) +{ + if (obj->mMovement.mMoveState < AIController::ModeSlowing) return; + WheeledVehicle* wvo = dynamic_cast(obj->getAIInfo()->mObj.getPointer()); + if (!wvo) + { + //cover the case of a connection controling an object in turn controlling another + if (obj->getAIInfo()->mObj->getObjectMount()) + wvo = dynamic_cast(obj->getAIInfo()->mObj->getObjectMount()); + } + if (!wvo) return;//not a WheeledVehicle + + Parent::resolveSpeed(obj, location, movePtr); + + VehicleData* db = static_cast(wvo->getDataBlock()); + movePtr->x = 0; + movePtr->y *= mMax((db->maxSteeringAngle-mFabs(movePtr->yaw) / db->maxSteeringAngle),0.75f); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +IMPLEMENT_CO_DATABLOCK_V1(AIFlyingVehicleControllerData); + +void AIFlyingVehicleControllerData::initPersistFields() +{ + docsURL; + addGroup("AI"); + + addFieldV("FlightFloor", TypeRangedF32, Offset(mFlightFloor, AIFlyingVehicleControllerData), &CommonValidators::F32Range, + "@brief Min height we can target."); + + addFieldV("FlightCeiling", TypeRangedF32, Offset(mFlightCeiling, AIFlyingVehicleControllerData), &CommonValidators::F32Range, + "@brief Max height we can target."); + + endGroup("AI"); + + Parent::initPersistFields(); +} + +AIFlyingVehicleControllerData::AIFlyingVehicleControllerData(const AIFlyingVehicleControllerData& other, bool temp_clone) : AIControllerData(other, temp_clone) +{ + mFlightCeiling = other.mFlightCeiling; + mFlightFloor = other.mFlightFloor; + resolveYawPtr.bind(this, &AIFlyingVehicleControllerData::resolveYaw); + resolvePitchPtr.bind(this, &AIFlyingVehicleControllerData::resolvePitch); + resolveSpeedPtr.bind(this, &AIFlyingVehicleControllerData::resolveSpeed); +} + +void AIFlyingVehicleControllerData::resolveYaw(AIController* obj, Point3F location, Move* movePtr) +{ + if (obj->mMovement.mMoveState < AIController::ModeSlowing) return; + FlyingVehicle* fvo = dynamic_cast(obj->getAIInfo()->mObj.getPointer()); + if (!fvo) + { + //cover the case of a connection controling an object in turn controlling another + if (obj->getAIInfo()->mObj->getObjectMount()) + fvo = dynamic_cast(obj->getAIInfo()->mObj->getObjectMount()); + } + if (!fvo) return;//not a FlyingVehicle + + Point3F right = fvo->getTransform().getRightVector(); + right.normalize(); + + // Get the Target to AI vector and normalize it. + Point3F aimLoc = obj->mMovement.mAimLocation; + aimLoc.z = mClampF(aimLoc.z, mFlightFloor, mFlightCeiling); + Point3F toTarg = (location + fvo->getVelocity() * TickSec) - aimLoc; + toTarg.normalize(); + + movePtr->yaw = 0; + F32 dotYaw = -mDot(right, toTarg); + if (mFabs(dotYaw) > 0.05f) + movePtr->yaw = dotYaw; +}; + +void AIFlyingVehicleControllerData::resolvePitch(AIController* obj, Point3F location, Move* movePtr) +{ + if (obj->mMovement.mMoveState < AIController::ModeSlowing) return; + FlyingVehicle* fvo = dynamic_cast(obj->getAIInfo()->mObj.getPointer()); + if (!fvo) + { + //cover the case of a connection controling an object in turn controlling another + if (obj->getAIInfo()->mObj->getObjectMount()) + fvo = dynamic_cast(obj->getAIInfo()->mObj->getObjectMount()); + } + if (!fvo) return;//not a FlyingVehicle + + Point3F up = fvo->getTransform().getUpVector(); + up.normalize(); + + + // Get the Target to AI vector and normalize it. + Point3F aimLoc = obj->mMovement.mAimLocation; + aimLoc.z = mClampF(aimLoc.z, mFlightFloor, mFlightCeiling); + Point3F toTarg = (location + fvo->getVelocity() * TickSec) - aimLoc; + toTarg.normalize(); + + movePtr->pitch = 0.0f; + F32 dotPitch = mDot(up, toTarg); + if (mFabs(dotPitch) > 0.05f) + movePtr->pitch = dotPitch * M_2PI_F; + +} + +void AIFlyingVehicleControllerData::resolveSpeed(AIController* obj, Point3F location, Move* movePtr) +{ + if (obj->mMovement.mMoveState < AIController::ModeSlowing) return; + FlyingVehicle* fvo = dynamic_cast(obj->getAIInfo()->mObj.getPointer()); + if (!fvo) + { + //cover the case of a connection controling an object in turn controlling another + if (obj->getAIInfo()->mObj->getObjectMount()) + fvo = dynamic_cast(obj->getAIInfo()->mObj->getObjectMount()); + } + if (!fvo) return;//not a FlyingVehicle + + movePtr->x = 0; + movePtr->y = obj->mMovement.mMoveSpeed; +} diff --git a/Engine/source/T3D/AI/AIController.h b/Engine/source/T3D/AI/AIController.h new file mode 100644 index 000000000..18d95e210 --- /dev/null +++ b/Engine/source/T3D/AI/AIController.h @@ -0,0 +1,247 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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 _AICONTROLLER_H_ +#define _AICONTROLLER_H_ +#include "navigation/coverPoint.h" +#include "AIInfo.h" +#include "AIGoal.h" +#include "AIAimTarget.h" +#include "AICover.h" +#include "AINavigation.h" +class AIControllerData; + +//----------------------------------------------------------------------------- +class AIController : public SimObject { + + typedef SimObject Parent; + +public: + AIControllerData* mControllerData; +protected: + static bool setControllerDataProperty(void* object, const char* index, const char* data); +public: + enum MoveState { + ModeStop, // AI has stopped moving. + ModeStuck, // AI is stuck, but wants to move. + ModeSlowing, // AI is slowing down as it reaches it's destination. + ModeMove, // AI is currently moving. + ModeReverse // AI is reversing + }; + +private: + AIInfo*mAIInfo; +public: + void setAIInfo(SimObjectPtr objIn, F32 rad = 0.0f) { delete(mAIInfo); mAIInfo = new AIInfo(this, objIn, rad); } + AIInfo* getAIInfo() { return mAIInfo; } +private: + AIGoal* mGoal; +public: + void setGoal(AIInfo* targ); + void setGoal(Point3F loc, F32 rad = 0.0f); + void setGoal(SimObjectPtr objIn, F32 rad = 0.0f); + AIGoal* getGoal() { return mGoal; } + void clearGoal() { SAFE_DELETE(mGoal); } +private: + AIAimTarget* mAimTarget; +public: + void setAim(Point3F loc, F32 rad = 0.0f, Point3F offset = Point3F(0.0f, 0.0f, 0.0f)); + void setAim(SimObjectPtr objIn, F32 rad = 0.0f, Point3F offset = Point3F(0.0f, 0.0f, 0.0f)); + AIAimTarget* getAim() { return mAimTarget; } + void clearAim() { SAFE_DELETE(mAimTarget); } +private: + AICover* mCover; +public: + void setCover(Point3F loc, F32 rad = 0.0f) { delete(mCover); mCover = new AICover(this, loc, rad); } + void setCover(SimObjectPtr objIn, F32 rad = 0.0f) { delete(mCover); mCover = new AICover(this, objIn, rad); } + AICover* getCover() { return mCover; } + bool findCover(const Point3F& from, F32 radius); + void clearCover(); + + // Utility Methods + void throwCallback(const char* name); + AINavigation* mNav; + AINavigation* getNav() { return mNav; }; + struct Movement + { + AIController* mControllerRef; + AIController* getCtrl() { return mControllerRef; }; + MoveState mMoveState; + F32 mMoveSpeed = 1.0; + void setMoveSpeed(F32 speed) { mMoveSpeed = speed; }; + F32 getMoveSpeed() { return mMoveSpeed; }; + bool mMoveSlowdown; // Slowdown as we near the destination + Point3F mLastLocation; // For stuck check + S32 mMoveStuckTestCountdown; // The current countdown until at AI starts to check if it is stuck + Point3F mAimLocation; + // move triggers + bool mMoveTriggers[MaxTriggerKeys]; + void stopMove(); + void onStuck(); + } mMovement; + + struct TriggerState + { + AIController* mControllerRef; + AIController* getCtrl() { return mControllerRef; }; + bool mMoveTriggers[MaxTriggerKeys]; + // Trigger sets/gets + void setMoveTrigger(U32 slot, const bool isSet = true); + bool getMoveTrigger(U32 slot) const; + void clearMoveTriggers(); + } mTriggerState; + bool getAIMove(Move* move); + + static void initPersistFields(); + AIController() + { + for (S32 i = 0; i < MaxTriggerKeys; i++) + mTriggerState.mMoveTriggers[i] = false; + + mMovement.mControllerRef = this; + mTriggerState.mControllerRef = this; + mControllerData = NULL; + mAIInfo = new AIInfo(this); + mNav = new AINavigation(this); + mGoal = NULL; + mAimTarget = NULL; + mCover = NULL; + mMovement.mMoveState = ModeStop; + }; + ~AIController() + { + SAFE_DELETE(mAIInfo); + SAFE_DELETE(mNav); + clearGoal(); + clearAim(); + clearCover(); + } + DECLARE_CONOBJECT(AIController); +}; + +//----------------------------------------------------------------------------- +class AIControllerData : public SimDataBlock { + + typedef SimDataBlock Parent; + +public: + + AIControllerData(); + AIControllerData(const AIControllerData&, bool = false); + ~AIControllerData() {}; + void packData(BitStream* stream) override; + void unpackData(BitStream* stream) override; + static void initPersistFields(); + DECLARE_CONOBJECT(AIControllerData); + + F32 mMoveTolerance; // Distance from destination point before we stop + F32 mFollowTolerance; // Distance from destination object before we stop + F32 mAttackRadius; // Distance to trigger weaponry calcs + S32 mMoveStuckTestDelay; // The number of ticks to wait before checking if the AI is stuck + F32 mMoveStuckTolerance; // Distance tolerance on stuck check + F32 mHeightTolerance; // how high above the navmesh are we before we stop trying to repath +#ifdef TORQUE_NAVIGATION_ENABLED + struct Flocking { + U32 mChance; // chance of flocking + F32 mMin; // min flocking separation distance + F32 mMax; // max flocking clustering distance + F32 mSideStep; // Distance from destination before we stop moving out of the way + } mFlocking; + + /// Types of link we can use. + LinkData mLinkTypes; + AINavigation::NavSize mNavSize; +#endif + Delegate resolveYawPtr; + void resolveYaw(AIController* obj, Point3F location, Move* movePtr); + + Delegate resolvePitchPtr; + void resolvePitch(AIController* obj, Point3F location, Move* movePtr) {}; + + Delegate resolveRollPtr; + void resolveRoll(AIController* obj, Point3F location, Move* movePtr); + + Delegate resolveSpeedPtr; + void resolveSpeed(AIController* obj, Point3F location, Move* movePtr); + + Delegate resolveTriggerStatePtr; + void resolveTriggerState(AIController* obj, Move* movePtr); + + Delegate resolveStuckPtr; + void resolveStuck(AIController* obj); +}; + +class AIPlayerControllerData : public AIControllerData +{ + typedef AIControllerData Parent; + +public: + AIPlayerControllerData() + { + resolvePitchPtr.bind(this, &AIPlayerControllerData::resolvePitch); + resolveTriggerStatePtr.bind(this, &AIPlayerControllerData::resolveTriggerState); + } + void resolvePitch(AIController* obj, Point3F location, Move* movePtr); + void resolveTriggerState(AIController* obj, Move* movePtr); + DECLARE_CONOBJECT(AIPlayerControllerData); +}; + +class AIWheeledVehicleControllerData : public AIControllerData +{ + typedef AIControllerData Parent; + +public: + AIWheeledVehicleControllerData() + { + resolveYawPtr.bind(this, &AIWheeledVehicleControllerData::resolveYaw); + resolveSpeedPtr.bind(this, &AIWheeledVehicleControllerData::resolveSpeed); + mHeightTolerance = 2.0f; + } + void resolveYaw(AIController* obj, Point3F location, Move* movePtr); + void resolveSpeed(AIController* obj, Point3F location, Move* movePtr); + DECLARE_CONOBJECT(AIWheeledVehicleControllerData); +}; + +class AIFlyingVehicleControllerData : public AIControllerData +{ + typedef AIControllerData Parent; + + F32 mFlightFloor; + F32 mFlightCeiling; +public: + AIFlyingVehicleControllerData() + { + resolveYawPtr.bind(this, &AIFlyingVehicleControllerData::resolveYaw); + resolvePitchPtr.bind(this, &AIFlyingVehicleControllerData::resolvePitch); + resolveSpeedPtr.bind(this, &AIFlyingVehicleControllerData::resolveSpeed); + mHeightTolerance = 200.0f; + mFlightCeiling = 200.0f; + mFlightFloor = 1.0; + } + AIFlyingVehicleControllerData(const AIFlyingVehicleControllerData&, bool = false); + static void initPersistFields(); + void resolveYaw(AIController* obj, Point3F location, Move* movePtr); + void resolveSpeed(AIController* obj, Point3F location, Move* movePtr); + void resolvePitch(AIController* obj, Point3F location, Move* movePtr); + + DECLARE_CONOBJECT(AIFlyingVehicleControllerData); +}; +#endif //_AICONTROLLER_H_ diff --git a/Engine/source/T3D/AI/AICover.cpp b/Engine/source/T3D/AI/AICover.cpp new file mode 100644 index 000000000..97cf82a39 --- /dev/null +++ b/Engine/source/T3D/AI/AICover.cpp @@ -0,0 +1,108 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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 "AICover.h" +#include "AIController.h" + +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(obj); + if (!p || p->isOccupied()) + return; + CoverSearch* s = static_cast(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 AIController::findCover(const Point3F& from, F32 radius) +{ + if (radius <= 0) + return false; + + // Create a search state. + CoverSearch s; + s.loc = getAIInfo()->getPosition(); + s.dist = radius; + // Direction we seek cover FROM. + s.from = from; + + // Find cover points. + Box3F box(radius * 2.0f); + box.setCenter(getAIInfo()->getPosition()); + getAIInfo()->mObj->getContainer()->findObjects(box, MarkerObjectType, findCoverCallback, &s); + + // Go to cover! + if (s.point) + { + // Calling setPathDestination clears cover... + bool foundPath = getNav()->setPathDestination(s.point->getPosition()); + setCover(s.point); + s.point->setOccupied(true); + return foundPath; + } + return false; +} + + +DefineEngineMethod(AIController, 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()->mCoverPoint.getObject(); + return cover ? cover->getId() : -1; + } + else + { + return -1; + } +} diff --git a/Engine/source/T3D/AI/AICover.h b/Engine/source/T3D/AI/AICover.h new file mode 100644 index 000000000..e18863bcf --- /dev/null +++ b/Engine/source/T3D/AI/AICover.h @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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 _AICOVER_H_ +#define _AICOVER_H_ + +#include "AIInfo.h" +#include "navigation/coverPoint.h" + + + +struct AICover : public AIInfo +{ + typedef AIInfo Parent; + /// Pointer to a cover point. + SimObjectPtr mCoverPoint; + AICover() = delete; + AICover(AIController* controller) : Parent(controller) {}; + AICover(AIController* controller, SimObjectPtr objIn, F32 radIn) : Parent(controller, objIn, radIn) { mCoverPoint = dynamic_cast(objIn.getPointer());}; + AICover(AIController* controller, Point3F pointIn, F32 radIn) : Parent(controller, pointIn, radIn) {}; +}; + +#endif diff --git a/Engine/source/T3D/AI/AIGoal.cpp b/Engine/source/T3D/AI/AIGoal.cpp new file mode 100644 index 000000000..e94fdd8ee --- /dev/null +++ b/Engine/source/T3D/AI/AIGoal.cpp @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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 "AIGoal.h" +#include "AIController.h" diff --git a/Engine/source/T3D/AI/AIGoal.h b/Engine/source/T3D/AI/AIGoal.h new file mode 100644 index 000000000..e8a22b873 --- /dev/null +++ b/Engine/source/T3D/AI/AIGoal.h @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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 _AIGOAL_H_ +#define _AIGOAL_H_ + +#include "AIInfo.h" + +struct AIGoal : public AIInfo +{ + typedef AIInfo Parent; + bool mInRange, mInFiringRange; + AIGoal() = delete; + AIGoal(AIController* controller) : Parent(controller) { mInRange = mInFiringRange = false; }; + AIGoal(AIController* controller, SimObjectPtr objIn, F32 radIn) : Parent(controller, objIn, radIn) { mInRange = mInFiringRange = false; }; + AIGoal(AIController* controller, Point3F pointIn, F32 radIn) : Parent(controller, pointIn, radIn) { mInRange = mInFiringRange = false; }; +}; +#endif diff --git a/Engine/source/T3D/AI/AIInfo.cpp b/Engine/source/T3D/AI/AIInfo.cpp new file mode 100644 index 000000000..f4a02e47f --- /dev/null +++ b/Engine/source/T3D/AI/AIInfo.cpp @@ -0,0 +1,81 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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 "AIInfo.h" +#include "AIController.h" + +AIInfo::AIInfo(AIController* controller) +{ + mControllerRef = controller; + mObj = NULL; + mPosition = mLastPos = Point3F(0.0f, 0.0f, 0.0f); + mRadius = 0.0f; + mPosSet = false; +}; + +AIInfo::AIInfo(AIController* controller, SimObjectPtr objIn, F32 radIn) +{ + mControllerRef = controller; + mObj = objIn; + mPosition = mLastPos = objIn->getPosition(); + mRadius = radIn; + mPosSet = false; + if (radIn == 0.0f) + mRadius = mMax(objIn->getObjBox().len_x(), objIn->getObjBox().len_y()) * 0.5; +}; + +AIInfo::AIInfo(AIController* controller, Point3F pointIn, F32 radIn) +{ + mControllerRef = controller; + mObj = NULL; + mPosition = mLastPos = pointIn; + mRadius = radIn; + mPosSet = true; +}; + +Point3F AIInfo::getPosition(bool doCastray) +{ + Point3F pos = (mObj.isValid()) ? mObj->getPosition() : mPosition; + if (doCastray) + { + RayInfo info; + if (gServerContainer.castRay(pos, pos - Point3F(0, 0, getCtrl()->mControllerData->mHeightTolerance), StaticShapeObjectType, &info)) + { + pos = info.point; + } + } + + return pos; +} + +F32 AIInfo::getDist() +{ + AIInfo* controlObj = getCtrl()->getAIInfo(); + Point3F targPos = getPosition(); + + if (mFabs(targPos.z - controlObj->getPosition().z) < getCtrl()->mControllerData->mHeightTolerance) + targPos.z = controlObj->getPosition().z; + + F32 ret = VectorF(controlObj->getPosition() - targPos).len(); + ret -= controlObj->mRadius + mRadius; + return ret; +} diff --git a/Engine/source/T3D/AI/AIInfo.h b/Engine/source/T3D/AI/AIInfo.h new file mode 100644 index 000000000..8aede0cae --- /dev/null +++ b/Engine/source/T3D/AI/AIInfo.h @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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 _AIINFO_H_ +#define _AIINFO_H_ + +#ifndef _SCENEOBJECT_H_ +#include "scene/sceneObject.h" +#endif + +class AIController; +struct AIInfo +{ + AIController* mControllerRef; + AIController* getCtrl() { return mControllerRef; }; + void setCtrl(AIController* controller) { mControllerRef = controller; }; + SimObjectPtr mObj; + Point3F mPosition, mLastPos; + bool mPosSet; + F32 mRadius; + Point3F getPosition(bool doCastray = false); + F32 getDist(); + AIInfo() = delete; + AIInfo(AIController* controller); + AIInfo(AIController* controller, SimObjectPtr objIn, F32 radIn = 0.0f); + AIInfo(AIController* controller,Point3F pointIn, F32 radIn = 0.0f); +}; +#endif diff --git a/Engine/source/T3D/AI/AINavigation.cpp b/Engine/source/T3D/AI/AINavigation.cpp new file mode 100644 index 000000000..258939f06 --- /dev/null +++ b/Engine/source/T3D/AI/AINavigation.cpp @@ -0,0 +1,574 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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 "AINavigation.h" +#include "AIController.h" +#include "T3D/shapeBase.h" + +static U32 sAILoSMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType | AIObjectType; + +AINavigation::AINavigation(AIController* controller) +{ + mControllerRef = controller; +#ifdef TORQUE_NAVIGATION_ENABLED + mJump = None; + mNavSize = Regular; +#endif +} + +AINavigation::~AINavigation() +{ +#ifdef TORQUE_NAVIGATION_ENABLED + clearPath(); + clearFollow(); +#endif +} + +void AINavigation::setMoveDestination(const Point3F& location, bool slowdown) +{ + mMoveDestination = location; + getCtrl()->mMovement.mMoveState = AIController::ModeMove; + getCtrl()->mMovement.mMoveSlowdown = slowdown; + getCtrl()->mMovement.mMoveStuckTestCountdown = getCtrl()->mControllerData->mMoveStuckTestDelay; +} + +bool AINavigation::setPathDestination(const Point3F& pos, bool replace) +{ +#ifdef TORQUE_NAVIGATION_ENABLED + if (replace) + getCtrl()->setGoal(pos, getCtrl()->mControllerData->mMoveTolerance); + + if (!mNavMesh) + updateNavMesh(); + + // If we can't find a mesh, just move regularly. + if (!mNavMesh) + { + //setMoveDestination(pos); + getCtrl()->throwCallback("onPathFailed"); + return false; + } + + // Create a new path. + NavPath* path = new NavPath(); + + path->mMesh = mNavMesh; + path->mFrom = getCtrl()->getAIInfo()->getPosition(true); + path->mTo = getCtrl()->getGoal()->getPosition(true); + path->mFromSet = path->mToSet = true; + path->mAlwaysRender = true; + path->mLinkTypes = getCtrl()->mControllerData->mLinkTypes; + path->mXray = true; + // Paths plan automatically upon being registered. + if (!path->registerObject()) + { + delete path; + return false; + } + + if (path->success()) + { + // Clear any current path we might have. + clearPath(); + getCtrl()->clearCover(); + // Store new path. + mPathData.path = path; + mPathData.owned = true; + // Skip node 0, which we are currently standing on. + moveToNode(1); + getCtrl()->throwCallback("onPathSuccess"); + return true; + } + else + { + // Just move normally if we can't path. + //setMoveDestination(pos, true); + //return; + getCtrl()->throwCallback("onPathFailed"); + path->deleteObject(); + return false; + } +#else + setMoveDestination(pos, false); + return true; +#endif +} + +Point3F AINavigation::getPathDestination() const +{ +#ifdef TORQUE_NAVIGATION_ENABLED + if (!mPathData.path.isNull()) + return mPathData.path->mTo; + return Point3F(0, 0, 0); +#else + return getMoveDestination(); +#endif +} +void AINavigation::onReachDestination() +{ + +#ifdef TORQUE_NAVIGATION_ENABLED + if (!getPath().isNull()) + { + if (mPathData.index == getPath()->size() - 1) + { + // Handle looping paths. + if (getPath()->mIsLooping) + moveToNode(0); + // Otherwise end path. + else + { + clearPath(); + getCtrl()->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 + { + getCtrl()->throwCallback("onReachDestination"); + getCtrl()->mMovement.mMoveState = AIController::ModeStop; + } +} + +void AINavigation::followObject() +{ + if (getCtrl()->getGoal()->getDist() < getCtrl()->mControllerData->mMoveTolerance) + return; + + if (setPathDestination(getCtrl()->getGoal()->getPosition(true))) + { +#ifdef TORQUE_NAVIGATION_ENABLED + getCtrl()->clearCover(); +#endif + } +} + +void AINavigation::followObject(SceneObject* obj, F32 radius) +{ + getCtrl()->setGoal(obj, radius); + followObject(); +} + +void AINavigation::clearFollow() +{ + getCtrl()->clearGoal(); +} + +DefineEngineMethod(AIController, setMoveDestination, void, (Point3F goal, bool slowDown), (true), + "@brief Tells the AI to move to the location provided\n\n" + + "@param goal Coordinates in world space representing location to move to.\n" + "@param slowDown A boolean value. If set to true, the bot will slow down " + "when it gets within 5-meters of its move destination. If false, the bot " + "will stop abruptly when it reaches the move destination. By default, this is true.\n\n" + + "@note Upon reaching a move destination, the bot will clear its move destination and " + "calls to getMoveDestination will return \"0 0 0\"." + + "@see getMoveDestination()\n") +{ + object->getNav()->setMoveDestination(goal, slowDown); +} + + +DefineEngineMethod(AIController, getMoveDestination, Point3F, (), , + "@brief Get the AIPlayer's current destination.\n\n" + + "@return Returns a point containing the \"x y z\" position " + "of the AIPlayer's current move destination. If no move destination " + "has yet been set, this returns \"0 0 0\"." + + "@see setMoveDestination()\n") +{ + return object->getNav()->getMoveDestination(); +} + +DefineEngineMethod(AIController, 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->getNav()->setPathDestination(goal, true); +} + + +DefineEngineMethod(AIController, 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->getNav()->getPathDestination(); +} + +DefineEngineMethod(AIController, 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; +#ifdef TORQUE_NAVIGATION_ENABLED + object->getNav()->clearPath(); + object->clearCover(); +#endif + object->getNav()->clearFollow(); + + if (Sim::findObject(obj, follow)) + object->getNav()->followObject(follow, radius); +} + +#ifdef TORQUE_NAVIGATION_ENABLED +NavMesh* AINavigation::findNavMesh() const +{ + GameBase* gbo = dynamic_cast(mControllerRef->getAIInfo()->mObj.getPointer()); + // 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(set->at(i)); + if (m->getWorldBox().isContained(gbo->getWorldBox())) + { + // Check that mesh size is appropriate. + if (gbo->isMounted()) + { + 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; +} + +void AINavigation::updateNavMesh() +{ + GameBase* gbo = dynamic_cast(mControllerRef->getAIInfo()->mObj.getPointer()); + NavMesh* old = mNavMesh; + if (mNavMesh.isNull()) + mNavMesh = findNavMesh(); + else + { + if (!mNavMesh->getWorldBox().isContained(gbo->getWorldBox())) + mNavMesh = findNavMesh(); + } + // See if we need to update our path. + if (mNavMesh != old && !mPathData.path.isNull()) + { + setPathDestination(mPathData.path->mTo); + } +} + +void AINavigation::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; +} + +void AINavigation::repath() +{ + // Ineffectual if we don't have a path, or are using someone else's. + if (mPathData.path.isNull() || !mPathData.owned) + return; + + if (mRandI(0, 100) < getCtrl()->mControllerData->mFlocking.mChance && flock()) + { + mPathData.path->mTo = mMoveDestination; + } + else + { + // If we're following, get their position. + mPathData.path->mTo = getCtrl()->getGoal()->getPosition(true); + } + + // Update from position and replan. + mPathData.path->mFrom = getCtrl()->getAIInfo()->getPosition(true); + mPathData.path->plan(); + + // Move to first node (skip start pos). + moveToNode(1); +} + + +void AINavigation::followNavPath(NavPath* path) +{ + // Get rid of our current path. + clearPath(); + getCtrl()->clearCover(); + + // Follow new path. + mPathData.path = path; + mPathData.owned = false; + // Start from 0 since we might not already be there. + moveToNode(0); +} + +void AINavigation::clearPath() +{ + // Only delete if we own the path. + if (!mPathData.path.isNull() && mPathData.owned) + mPathData.path->deleteObject(); + // Reset path data. + mPathData = PathData(); +} + +bool AINavigation::flock() +{ + AIControllerData::Flocking flockingData = getCtrl()->mControllerData->mFlocking; + SimObjectPtr obj = getCtrl()->getAIInfo()->mObj; + + obj->disableCollision(); + Point3F pos = obj->getBoxCenter(); + Point3F searchArea = Point3F(flockingData.mMin / 2, flockingData.mMax / 2, getCtrl()->getAIInfo()->mObj->getObjBox().maxExtents.z / 2); + + F32 maxFlocksq = flockingData.mMax * flockingData.mMax; + bool flocking = false; + U32 found = 0; + if (getCtrl()->getGoal()) + { + Point3F dest = mMoveDestination; + + if (getCtrl()->mMovement.mMoveState == AIController::ModeStuck) + { + Point3F shuffle = Point3F(mRandF() - 0.5, mRandF() - 0.5, 0); + shuffle.normalize(); + dest += shuffle * flockingData.mMin; + } + + dest.z = pos.z; + if ((pos - dest).len() > flockingData.mSideStep) + { + //find closest object + SimpleQueryList sql; + Box3F queryBox = Box3F(pos - searchArea, pos + searchArea); + obj->getContainer()->findObjects(queryBox, AIObjectType, SimpleQueryList::insertionCallback, &sql); + sql.mList.remove(obj); + + Point3F avoidanceOffset = Point3F::Zero; + + //avoid objects in the way + RayInfo info; + if (obj->getContainer()->castRay(pos, dest + Point3F(0, 0, obj->getObjBox().len_z() / 2), sAILoSMask, &info)) + { + Point3F blockerOffset = (info.point - dest); + blockerOffset.z = 0; + avoidanceOffset += blockerOffset; + } + + //avoid bots that are too close + for (U32 i = 0; i < sql.mList.size(); i++) + { + ShapeBase* other = dynamic_cast(sql.mList[i]); + Point3F objectCenter = other->getBoxCenter(); + + F32 sumRad = flockingData.mMin + other->getAIController()->mControllerData->mFlocking.mMin; + F32 separation = getCtrl()->getAIInfo()->mRadius + other->getAIController()->getAIInfo()->mRadius; + sumRad += separation; + + Point3F offset = (pos - objectCenter); + F32 offsetLensq = offset.lenSquared(); //square roots are expensive, so use squared val compares + if ((flockingData.mMin > 0) && (offsetLensq < (sumRad * sumRad))) + { + other->disableCollision(); + if (!obj->getContainer()->castRay(pos, other->getBoxCenter(), sAILoSMask, &info)) + { + found++; + offset.normalizeSafe(); + offset *= sumRad + separation; + avoidanceOffset += offset; //accumulate total group, move away from that + } + other->enableCollision(); + } + } + //if we don't have to worry about bumping into one another (nothing found lower than minFLock), see about grouping up + if (found == 0) + { + for (U32 i = 0; i < sql.mList.size(); i++) + { + ShapeBase* other = static_cast(sql.mList[i]); + Point3F objectCenter = other->getBoxCenter(); + + F32 sumRad = flockingData.mMin + other->getAIController()->mControllerData->mFlocking.mMin; + F32 separation = getCtrl()->getAIInfo()->mRadius + other->getAIController()->getAIInfo()->mRadius; + sumRad += separation; + + Point3F offset = (pos - objectCenter); + if ((flockingData.mMin > 0) && ((sumRad * sumRad) < (maxFlocksq))) + { + other->disableCollision(); + if (!obj->getContainer()->castRay(pos, other->getBoxCenter(), sAILoSMask, &info)) + { + found++; + offset.normalizeSafe(); + offset *= sumRad + separation; + avoidanceOffset -= offset; // subtract total group, move toward it + } + other->enableCollision(); + } + } + } + if (found > 0) + { + avoidanceOffset.z = 0; + avoidanceOffset.x = (mRandF() * avoidanceOffset.x) * 0.5 + avoidanceOffset.x * 0.75; + avoidanceOffset.y = (mRandF() * avoidanceOffset.y) * 0.5 + avoidanceOffset.y * 0.75; + if (avoidanceOffset.lenSquared() < (maxFlocksq)) + { + dest += avoidanceOffset; + } + + //if we're not jumping... + if (mJump == None) + { + dest.z = obj->getPosition().z; + //make sure we don't run off a cliff + Point3F zlen(0, 0, getCtrl()->mControllerData->mHeightTolerance); + if (obj->getContainer()->castRay(dest + zlen, dest - zlen, TerrainObjectType | StaticShapeObjectType | StaticObjectType, &info)) + { + if ((mMoveDestination - dest).len() > getCtrl()->mControllerData->mMoveTolerance) + { + mMoveDestination = dest; + flocking = true; + } + } + } + } + } + } + obj->enableCollision(); + return flocking; +} + + +DefineEngineMethod(AIController, 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->getNav()->followNavPath(path); +} + + +DefineEngineMethod(AIController, 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->getNav()->repath(); +} + +DefineEngineMethod(AIController, 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->getNav()->getNavMesh(); + return mesh ? mesh->getId() : -1; +} + +DefineEngineMethod(AIController, getNavMesh, S32, (), , + "@brief Return the NavMesh this AIPlayer is using to navigate.\n\n") +{ + NavMesh* m = object->getNav()->getNavMesh(); + return m ? m->getId() : 0; +} + +DefineEngineMethod(AIController, setNavSize, void, (const char* size), , + "@brief Set the size of NavMesh this character uses. One of \"Small\", \"Regular\" or \"Large\".") +{ + if (!String::compare(size, "Small")) + object->getNav()->setNavSize(AINavigation::Small); + else if (!String::compare(size, "Regular")) + object->getNav()->setNavSize(AINavigation::Regular); + else if (!String::compare(size, "Large")) + object->getNav()->setNavSize(AINavigation::Large); + else + Con::errorf("AIPlayer::setNavSize: no such size '%s'.", size); +} + +DefineEngineMethod(AIController, getNavSize, const char*, (), , + "@brief Return the size of NavMesh this character uses for pathfinding.") +{ + switch (object->getNav()->getNavSize()) + { + case AINavigation::Small: + return "Small"; + case AINavigation::Regular: + return "Regular"; + case AINavigation::Large: + return "Large"; + } + return ""; +} +#endif diff --git a/Engine/source/T3D/AI/AINavigation.h b/Engine/source/T3D/AI/AINavigation.h new file mode 100644 index 000000000..4d4f1b966 --- /dev/null +++ b/Engine/source/T3D/AI/AINavigation.h @@ -0,0 +1,105 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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 _AINAVIGATION_H_ +#define _AINAVIGATION_H_ + +#include "AIInfo.h" + +#include "navigation/navPath.h" +#include "navigation/navMesh.h" + +class AIController; +struct AINavigation +{ + AIController* mControllerRef; + AIController* getCtrl() { return mControllerRef; }; + + AINavigation() = delete; + AINavigation(AIController* controller); + ~AINavigation(); + Point3F mMoveDestination; + void setMoveDestination(const Point3F& location, bool slowdown); + Point3F getMoveDestination() const { return mMoveDestination; }; + bool setPathDestination(const Point3F& pos, bool replace = false); + Point3F getPathDestination() const; + + void onReachDestination(); + + void followObject(); + void followObject(SceneObject* obj, F32 radius); + void clearFollow(); + +#ifdef TORQUE_NAVIGATION_ENABLED + /// Stores information about a path. + struct PathData { + /// Pointer to path object. + SimObjectPtr 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; + } + }; + + /// Should we jump? + enum JumpStates { + None, ///< No, don't jump. + Now, ///< Jump immediately. + Ledge, ///< Jump when we walk off a ledge. + }; + + enum NavSize { + Small, + Regular, + Large + } mNavSize; + void setNavSize(NavSize size) { mNavSize = size; updateNavMesh(); } + NavSize getNavSize() const { return mNavSize; } + + /// NavMesh we pathfind on. + SimObjectPtr mNavMesh; + NavMesh* findNavMesh() const; + void updateNavMesh(); + NavMesh* getNavMesh() const { return mNavMesh; } + PathData mPathData; + JumpStates mJump; + + /// Clear out the current path. + void clearPath(); + void repath(); + + /// Get the current path we're following. + SimObjectPtr getPath() { return mPathData.path; }; + void followNavPath(NavPath* path); + + /// Move to the specified node in the current path. + void moveToNode(S32 node); + bool flock(); +#endif +}; + +#endif diff --git a/Engine/source/T3D/SubScene.cpp b/Engine/source/T3D/SubScene.cpp index ecab32ff0..2b773bfd6 100644 --- a/Engine/source/T3D/SubScene.cpp +++ b/Engine/source/T3D/SubScene.cpp @@ -24,7 +24,7 @@ IMPLEMENT_CALLBACK(SubScene, onUnloaded, void, (), (), "@brief Called when a subScene has been unloaded and has game mode implications.\n\n"); SubScene::SubScene() : - mLevelAssetId(StringTable->EmptyString()), + mSubSceneAssetId(StringTable->EmptyString()), mGameModesNames(StringTable->EmptyString()), mScopeDistance(-1), mLoaded(false), @@ -67,7 +67,7 @@ void SubScene::initPersistFields() { addGroup("SubScene"); addField("isGlobalLayer", TypeBool, Offset(mGlobalLayer, SubScene), ""); - INITPERSISTFIELD_LEVELASSET(Level, SubScene, "The level asset to load."); + INITPERSISTFIELD_SUBSCENEASSET(SubScene, SubScene, "The subscene asset to load."); addField("tickPeriodMS", TypeS32, Offset(mTickPeriodMS, SubScene), "evaluation rate (ms)"); addField("gameModes", TypeGameModeList, Offset(mGameModesNames, SubScene), "The game modes that this subscene is associated with."); endGroup("SubScene"); @@ -265,13 +265,13 @@ void SubScene::processTick(const Move* move) void SubScene::_onFileChanged(const Torque::Path& path) { - if(mLevelAsset.isNull() || Torque::Path(mLevelAsset->getLevelPath()) != path) + if(mSubSceneAsset.isNull() || Torque::Path(mSubSceneAsset->getLevelPath()) != path) return; if (mSaving) return; - AssertFatal(path == mLevelAsset->getLevelPath(), "Prefab::_onFileChanged - path does not match filename."); + AssertFatal(path == mSubSceneAsset->getLevelPath(), "SubScene::_onFileChanged - path does not match filename."); _closeFile(false); _loadFile(false); @@ -307,9 +307,9 @@ void SubScene::_closeFile(bool removeFileNotify) _removeContents(SimGroupIterator(this)); - if (removeFileNotify && mLevelAsset.notNull() && mLevelAsset->getLevelPath() != StringTable->EmptyString()) + if (removeFileNotify && mSubSceneAsset.notNull() && mSubSceneAsset->getLevelPath() != StringTable->EmptyString()) { - Torque::FS::RemoveChangeNotification(mLevelAsset->getLevelPath(), this, &SubScene::_onFileChanged); + Torque::FS::RemoveChangeNotification(mSubSceneAsset->getLevelPath(), this, &SubScene::_onFileChanged); } mGameModesList.clear(); @@ -319,18 +319,18 @@ void SubScene::_loadFile(bool addFileNotify) { AssertFatal(isServerObject(), "Trying to load a SubScene file on the client is bad!"); - if(mLevelAsset.isNull() || mLevelAsset->getLevelPath() == StringTable->EmptyString()) + if(mSubSceneAsset.isNull() || mSubSceneAsset->getLevelPath() == StringTable->EmptyString()) return; - String evalCmd = String::ToString("exec(\"%s\");", mLevelAsset->getLevelPath()); + String evalCmd = String::ToString("exec(\"%s\");", mSubSceneAsset->getLevelPath()); String instantGroup = Con::getVariable("InstantGroup"); Con::setIntVariable("InstantGroup", this->getId()); - Con::evaluate((const char*)evalCmd.c_str(), false, mLevelAsset->getLevelPath()); + Con::evaluate((const char*)evalCmd.c_str(), false, mSubSceneAsset->getLevelPath()); Con::setVariable("InstantGroup", instantGroup.c_str()); if (addFileNotify) - Torque::FS::AddChangeNotification(mLevelAsset->getLevelPath(), this, &SubScene::_onFileChanged); + Torque::FS::AddChangeNotification(mSubSceneAsset->getLevelPath(), this, &SubScene::_onFileChanged); } void SubScene::load() @@ -432,7 +432,7 @@ bool SubScene::save() if (size() == 0 || !isLoaded()) return false; - if (mLevelAsset.isNull()) + if (mSubSceneAsset.isNull()) return false; if (mSaving) @@ -446,7 +446,7 @@ bool SubScene::save() PersistenceManager prMger; - StringTableEntry levelPath = mLevelAsset->getLevelPath(); + StringTableEntry levelPath = mSubSceneAsset->getLevelPath(); FileStream fs; fs.open(levelPath, Torque::FS::File::Write); @@ -460,7 +460,7 @@ bool SubScene::save() { if ((*itr)->isMethod("onSaving")) { - Con::executef((*itr), "onSaving", mLevelAssetId); + Con::executef((*itr), "onSaving", mSubSceneAssetId); } if (childObj->getGroup() == this) @@ -481,14 +481,14 @@ bool SubScene::save() bool saveSuccess = false; //Get the level asset - if (mLevelAsset.isNull()) + if (mSubSceneAsset.isNull()) return saveSuccess; //update the gamemode list as well - mLevelAsset->setDataField(StringTable->insert("gameModesNames"), NULL, StringTable->insert(mGameModesNames)); + mSubSceneAsset->setDataField(StringTable->insert("gameModesNames"), NULL, StringTable->insert(mGameModesNames)); //Finally, save - saveSuccess = mLevelAsset->saveAsset(); + saveSuccess = mSubSceneAsset->saveAsset(); mSaving = false; diff --git a/Engine/source/T3D/SubScene.h b/Engine/source/T3D/SubScene.h index e73133057..cfc3606ad 100644 --- a/Engine/source/T3D/SubScene.h +++ b/Engine/source/T3D/SubScene.h @@ -5,8 +5,8 @@ #ifndef SCENE_GROUP_H #include "SceneGroup.h" #endif -#ifndef LEVEL_ASSET_H -#include "assets/LevelAsset.h" +#ifndef SUBSCENE_ASSET_H +#include "assets/SubSceneAsset.h" #endif class GameMode; @@ -21,13 +21,13 @@ public: NextFreeMask = Parent::NextFreeMask << 0 }; - void onLevelChanged() {} + void onSubSceneChanged() {} protected: static bool smTransformChildren; private: - DECLARE_LEVELASSET(SubScene, Level, onLevelChanged); + DECLARE_SUBSCENEASSET(SubScene, SubScene, onSubSceneChanged); StringTableEntry mGameModesNames; Vector mGameModesList; @@ -61,7 +61,7 @@ public: static void initPersistFields(); static void consoleInit(); - StringTableEntry getTypeHint() const override { return (getLevelAsset()) ? getLevelAsset()->getAssetName() : StringTable->EmptyString(); } + StringTableEntry getTypeHint() const override { return (getSubSceneAsset()) ? getSubSceneAsset()->getAssetName() : StringTable->EmptyString(); } // SimObject bool onAdd() override; @@ -122,6 +122,6 @@ public: DECLARE_CALLBACK(void, onLoaded, ()); DECLARE_CALLBACK(void, onUnloaded, ()); - DECLARE_ASSET_SETGET(SubScene, Level); + DECLARE_ASSET_SETGET(SubScene, SubScene); }; #endif diff --git a/Engine/source/T3D/assets/CppAsset.cpp b/Engine/source/T3D/assets/CppAsset.cpp index b51ae1025..6d900e1ef 100644 --- a/Engine/source/T3D/assets/CppAsset.cpp +++ b/Engine/source/T3D/assets/CppAsset.cpp @@ -178,3 +178,17 @@ void CppAsset::onAssetRefresh(void) mHeaderPath = getOwned() ? expandAssetFilePath(mHeaderFile) : mHeaderPath; } + +DefineEngineMethod(CppAsset, getCodePath, const char*, (), , + "Gets the code file filepath of this asset.\n" + "@return File path of the code file.") +{ + return object->getCppFilePath(); +} + +DefineEngineMethod(CppAsset, getHeaderPath, const char*, (), , + "Gets the header file filepath of this asset.\n" + "@return File path of the header file.") +{ + return object->getHeaderFilePath(); +} diff --git a/Engine/source/T3D/assets/CppAsset.h b/Engine/source/T3D/assets/CppAsset.h index 40ad8ebfc..c7d99e81e 100644 --- a/Engine/source/T3D/assets/CppAsset.h +++ b/Engine/source/T3D/assets/CppAsset.h @@ -66,6 +66,9 @@ public: void setHeaderFile(const char* pHeaderFile); inline StringTableEntry getHeaderFile(void) const { return mHeaderFile; }; + inline StringTableEntry getCppFilePath(void) const { return mCodePath; }; + inline StringTableEntry getHeaderFilePath(void) const { return mHeaderPath; }; + protected: void initializeAsset(void) override; void onAssetRefresh(void) override; @@ -73,9 +76,6 @@ protected: static bool setCppFile(void *obj, const char *index, const char *data) { static_cast(obj)->setCppFile(data); return false; } static const char* getCppFile(void* obj, const char* data) { return static_cast(obj)->getCppFile(); } - inline StringTableEntry getCppFilePath(void) const { return mCodePath; }; - inline StringTableEntry getHeaderFilePath(void) const { return mHeaderPath; }; - static bool setHeaderFile(void *obj, const char *index, const char *data) { static_cast(obj)->setHeaderFile(data); return false; } static const char* getHeaderFile(void* obj, const char* data) { return static_cast(obj)->getHeaderFile(); } }; diff --git a/Engine/source/T3D/assets/LevelAsset.cpp b/Engine/source/T3D/assets/LevelAsset.cpp index c4f954305..067a71121 100644 --- a/Engine/source/T3D/assets/LevelAsset.cpp +++ b/Engine/source/T3D/assets/LevelAsset.cpp @@ -101,7 +101,7 @@ ConsoleSetType(TypeLevelAssetId) } //----------------------------------------------------------------------------- -LevelAsset::LevelAsset() : AssetBase(), mIsSubLevel(false) +LevelAsset::LevelAsset() : AssetBase() { mLevelName = StringTable->EmptyString(); mLevelFile = StringTable->EmptyString(); @@ -117,7 +117,6 @@ LevelAsset::LevelAsset() : AssetBase(), mIsSubLevel(false) mNavmeshPath = StringTable->EmptyString(); mGameModesNames = StringTable->EmptyString(); - mMainLevelAsset = StringTable->EmptyString(); mEditorFile = StringTable->EmptyString(); mBakedSceneFile = StringTable->EmptyString(); @@ -158,7 +157,6 @@ void LevelAsset::initPersistFields() addProtectedField("BakedSceneFile", TypeAssetLooseFilePath, Offset(mBakedSceneFile, LevelAsset), &setBakedSceneFile, &getBakedSceneFile, "Path to the level file with the objects generated as part of the baking process"); - addField("isSubScene", TypeBool, Offset(mIsSubLevel, LevelAsset), "Is this a sublevel to another Scene"); addField("gameModesNames", TypeString, Offset(mGameModesNames, LevelAsset), "Name of the Game Mode to be used with this level"); } @@ -481,15 +479,8 @@ GuiControl* GuiInspectorTypeLevelAssetPtr::constructEditControl() // Create "Open in Editor" button mEditButton = new GuiBitmapButtonCtrl(); - String setSubSceneValue = "$createLevelAssetIsSubScene = \"\";"; - if(dynamic_cast(mInspector->getInspectObject()) != NULL) - { - setSubSceneValue = "$createLevelAssetIsSubScene = true;"; - } - - dSprintf(szBuffer, sizeof(szBuffer), "$createAndAssignField = %s; %s AssetBrowser.setupCreateNewAsset(\"LevelAsset\", AssetBrowser.selectedModule, \"createAndAssignLevelAsset\");", - getIdString(), - setSubSceneValue.c_str()); + dSprintf(szBuffer, sizeof(szBuffer), "$createAndAssignField = %s; AssetBrowser.setupCreateNewAsset(\"LevelAsset\", AssetBrowser.selectedModule, \"createAndAssignLevelAsset\");", + getIdString()); mEditButton->setField("Command", szBuffer); char bitmapName[512] = "ToolsModule:iconAdd_image"; diff --git a/Engine/source/T3D/assets/LevelAsset.h b/Engine/source/T3D/assets/LevelAsset.h index 8b02495ed..39339a41e 100644 --- a/Engine/source/T3D/assets/LevelAsset.h +++ b/Engine/source/T3D/assets/LevelAsset.h @@ -66,9 +66,6 @@ class LevelAsset : public AssetBase StringTableEntry mEditorFile; StringTableEntry mBakedSceneFile; - bool mIsSubLevel; - StringTableEntry mMainLevelAsset; - StringTableEntry mGameModesNames; Vector mAssetDependencies; diff --git a/Engine/source/T3D/assets/ShapeAsset.h b/Engine/source/T3D/assets/ShapeAsset.h index afa39ca57..2d186346d 100644 --- a/Engine/source/T3D/assets/ShapeAsset.h +++ b/Engine/source/T3D/assets/ShapeAsset.h @@ -370,7 +370,7 @@ public: \ #pragma region Arrayed Asset Macros -#define DECLARE_SHAPEASSET_ARRAY(className,name,max) public: \ +#define DECLARE_SHAPEASSET_ARRAY(className,name,max,changeFunc) public: \ static const U32 sm##name##Count = max;\ Resourcem##name[max];\ StringTableEntry m##name##Name[max]; \ @@ -384,6 +384,10 @@ public: \ \ bool _set##name(StringTableEntry _in, const U32& index)\ {\ + if (m##name##Asset[index].notNull())\ + {\ + m##name##Asset[index]->getChangedSignal().remove(this, &className::changeFunc);\ + }\ if(m##name##AssetId[index] != _in || m##name##Name[index] != _in)\ {\ if(index >= sm##name##Count || index < 0)\ @@ -430,6 +434,8 @@ public: \ if (get##name(index) != StringTable->EmptyString() && m##name##Asset[index].notNull())\ {\ m##name[index] = m##name##Asset[index]->getShapeResource();\ + \ + m##name##Asset[index]->getChangedSignal().notify(this, &className::changeFunc);\ }\ else\ {\ diff --git a/Engine/source/T3D/assets/SubSceneAsset.cpp b/Engine/source/T3D/assets/SubSceneAsset.cpp new file mode 100644 index 000000000..a55af9cad --- /dev/null +++ b/Engine/source/T3D/assets/SubSceneAsset.cpp @@ -0,0 +1,166 @@ +#include "SubSceneAsset.h" + +#include "T3D/SubScene.h" +IMPLEMENT_CONOBJECT(SubSceneAsset); + + +ConsoleType(SubSceneAssetPtr, TypeSubSceneAssetPtr, const char*, "") + +//----------------------------------------------------------------------------- + +ConsoleGetType(TypeSubSceneAssetPtr) +{ + // Fetch asset Id. + return *((const char**)(dptr)); +} + +//----------------------------------------------------------------------------- + +ConsoleSetType(TypeSubSceneAssetPtr) +{ + // Was a single argument specified? + if (argc == 1) + { + // Yes, so fetch field value. + *((const char**)dptr) = StringTable->insert(argv[0]); + + return; + } + + // Warn. + Con::warnf("(TypeSubSceneAssetPtr) - Cannot set multiple args to a single asset."); +} + +//----------------------------------------------------------------------------- +ConsoleType(assetIdString, TypeSubSceneAssetId, const char*, "") + +ConsoleGetType(TypeSubSceneAssetId) +{ + // Fetch asset Id. + return *((const char**)(dptr)); +} + +ConsoleSetType(TypeSubSceneAssetId) +{ + // Was a single argument specified? + if (argc == 1) + { + *((const char**)dptr) = StringTable->insert(argv[0]); + + return; + } + + // Warn. + Con::warnf("(TypeSubSceneAssetId) - Cannot set multiple args to a single asset."); +} + +SubSceneAsset::SubSceneAsset() : LevelAsset() +{ +} + +SubSceneAsset::~SubSceneAsset() +{ +} + +void SubSceneAsset::initPersistFields() +{ + docsURL; + Parent::initPersistFields(); +} + + +//----------------------------------------------------------------------------- +// GuiInspectorTypeAssetId +//----------------------------------------------------------------------------- + +IMPLEMENT_CONOBJECT(GuiInspectorTypeSubSceneAssetPtr); + +ConsoleDocClass(GuiInspectorTypeSubSceneAssetPtr, + "@brief Inspector field type for Shapes\n\n" + "Editor use only.\n\n" + "@internal" +); + +void GuiInspectorTypeSubSceneAssetPtr::consoleInit() +{ + Parent::consoleInit(); + + ConsoleBaseType::getType(TypeSubSceneAssetPtr)->setInspectorFieldType("GuiInspectorTypeSubSceneAssetPtr"); +} + +GuiControl* GuiInspectorTypeSubSceneAssetPtr::constructEditControl() +{ + // Create base filename edit controls + GuiControl* retCtrl = Parent::constructEditControl(); + if (retCtrl == NULL) + return retCtrl; + + // Change filespec + char szBuffer[512]; + dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"SubSceneAsset\", \"AssetBrowser.changeAsset\", %s, \"\");", + getIdString()); + mBrowseButton->setField("Command", szBuffer); + + setDataField(StringTable->insert("targetObject"), NULL, mInspector->getInspectObject()->getIdString()); + + // Create "Open in Editor" button + mEditButton = new GuiBitmapButtonCtrl(); + + dSprintf(szBuffer, sizeof(szBuffer), "$createAndAssignField = %s; AssetBrowser.setupCreateNewAsset(\"SubSceneAsset\", AssetBrowser.selectedModule);", + getIdString()); + mEditButton->setField("Command", szBuffer); + + char bitmapName[512] = "ToolsModule:iconAdd_image"; + mEditButton->setBitmap(StringTable->insert(bitmapName)); + + mEditButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile"); + mEditButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile"); + mEditButton->setDataField(StringTable->insert("hovertime"), NULL, "1000"); + mEditButton->setDataField(StringTable->insert("tooltip"), NULL, "Test play this sound"); + + mEditButton->registerObject(); + addObject(mEditButton); + + return retCtrl; +} + +bool GuiInspectorTypeSubSceneAssetPtr::updateRects() +{ + S32 dividerPos, dividerMargin; + mInspector->getDivider(dividerPos, dividerMargin); + Point2I fieldExtent = getExtent(); + Point2I fieldPos = getPosition(); + + mCaptionRect.set(0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y); + mEditCtrlRect.set(fieldExtent.x - dividerPos + dividerMargin, 1, dividerPos - dividerMargin - 34, fieldExtent.y); + + bool resized = mEdit->resize(mEditCtrlRect.point, mEditCtrlRect.extent); + if (mBrowseButton != NULL) + { + mBrowseRect.set(fieldExtent.x - 32, 2, 14, fieldExtent.y - 4); + resized |= mBrowseButton->resize(mBrowseRect.point, mBrowseRect.extent); + } + + if (mEditButton != NULL) + { + RectI shapeEdRect(fieldExtent.x - 16, 2, 14, fieldExtent.y - 4); + resized |= mEditButton->resize(shapeEdRect.point, shapeEdRect.extent); + } + + return resized; +} + +IMPLEMENT_CONOBJECT(GuiInspectorTypeSubSceneAssetId); + +ConsoleDocClass(GuiInspectorTypeSubSceneAssetId, + "@brief Inspector field type for SubScene\n\n" + "Editor use only.\n\n" + "@internal" +); + +void GuiInspectorTypeSubSceneAssetId::consoleInit() +{ + Parent::consoleInit(); + + ConsoleBaseType::getType(TypeSubSceneAssetId)->setInspectorFieldType("GuiInspectorTypeSubSceneAssetId"); +} diff --git a/Engine/source/T3D/assets/SubSceneAsset.h b/Engine/source/T3D/assets/SubSceneAsset.h new file mode 100644 index 000000000..444c4c23a --- /dev/null +++ b/Engine/source/T3D/assets/SubSceneAsset.h @@ -0,0 +1,113 @@ +#pragma once +#ifndef SUBSCENE_ASSET_H +#define SUBSCENE_ASSET_H + +#ifndef LEVEL_ASSET_H +#include "LevelAsset.h" +#endif + +#ifndef _ASSET_DEFINITION_H_ +#include "assets/assetDefinition.h" +#endif + +#ifndef _GUI_INSPECTOR_TYPES_H_ +#include "gui/editor/guiInspectorTypes.h" +#endif + +class SubSceneAsset : public LevelAsset +{ + typedef LevelAsset Parent; + +public: + SubSceneAsset(); + virtual ~SubSceneAsset(); + + /// Engine. + static void initPersistFields(); + + /// Declare Console Object. + DECLARE_CONOBJECT(SubSceneAsset); +}; + +#ifdef TORQUE_TOOLS +class GuiInspectorTypeSubSceneAssetPtr : public GuiInspectorTypeFileName +{ + typedef GuiInspectorTypeFileName Parent; +public: + + GuiBitmapButtonCtrl* mEditButton; + + DECLARE_CONOBJECT(GuiInspectorTypeSubSceneAssetPtr); + static void consoleInit(); + + GuiControl* constructEditControl() override; + bool updateRects() override; +}; + +class GuiInspectorTypeSubSceneAssetId : public GuiInspectorTypeSubSceneAssetPtr +{ + typedef GuiInspectorTypeSubSceneAssetPtr Parent; +public: + + DECLARE_CONOBJECT(GuiInspectorTypeSubSceneAssetId); + static void consoleInit(); +}; +#endif + +DefineConsoleType(TypeSubSceneAssetPtr, SubSceneAsset) +DefineConsoleType(TypeSubSceneAssetId, String) + +#pragma region Singular Asset Macros + +//Singular assets +/// +/// Declares an SubScene asset +/// This establishes the assetId, asset and legacy filepath fields, along with supplemental getter and setter functions +/// +#define DECLARE_SUBSCENEASSET(className, name, changeFunc) public: \ + StringTableEntry m##name##AssetId;\ + AssetPtr m##name##Asset;\ +public: \ + const AssetPtr & get##name##Asset() const { return m##name##Asset; }\ + void set##name##Asset(const AssetPtr &_in) { m##name##Asset = _in;}\ + \ + bool _set##name(StringTableEntry _in)\ + {\ + if(m##name##AssetId != _in)\ + {\ + if (m##name##Asset.notNull())\ + {\ + m##name##Asset->getChangedSignal().remove(this, &className::changeFunc);\ + }\ + if (_in == NULL || _in == StringTable->EmptyString())\ + {\ + m##name##AssetId = StringTable->EmptyString();\ + m##name##Asset = NULL;\ + return true;\ + }\ + if (AssetDatabase.isDeclaredAsset(_in))\ + {\ + m##name##AssetId = _in;\ + m##name##Asset = _in;\ + return true;\ + }\ + }\ + \ + if(get##name() == StringTable->EmptyString())\ + return true;\ + \ + return false;\ + }\ + \ + const StringTableEntry get##name() const\ + {\ + return m##name##AssetId;\ + }\ + bool name##Valid() {return (get##name() != StringTable->EmptyString() && m##name##Asset->getStatus() == AssetBase::Ok); } + +#define INITPERSISTFIELD_SUBSCENEASSET(name, consoleClass, docs) \ + addProtectedField(assetText(name, Asset), TypeSubSceneAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.)); + +#pragma endregion + +#endif // SUBSCENE_ASSET_H diff --git a/Engine/source/T3D/camera.cpp b/Engine/source/T3D/camera.cpp index 41056f833..3e2408583 100644 --- a/Engine/source/T3D/camera.cpp +++ b/Engine/source/T3D/camera.cpp @@ -345,7 +345,7 @@ bool Camera::onNewDataBlock( GameBaseData *dptr, bool reload ) if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) ) return false; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/debris.cpp b/Engine/source/T3D/debris.cpp index 7c05e3ec5..78a1e53cc 100644 --- a/Engine/source/T3D/debris.cpp +++ b/Engine/source/T3D/debris.cpp @@ -601,7 +601,7 @@ bool Debris::onNewDataBlock( GameBaseData *dptr, bool reload ) if (mDataBlock->isTempClone()) return true; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/debris.h b/Engine/source/T3D/debris.h index a0ff99520..1d1116031 100644 --- a/Engine/source/T3D/debris.h +++ b/Engine/source/T3D/debris.h @@ -111,7 +111,10 @@ public: void onPerformSubstitutions() override; bool allowSubstitutions() const override { return true; } - void onShapeChanged() {} + void onShapeChanged() + { + reloadOnLocalClient(); + } }; //************************************************************************** diff --git a/Engine/source/T3D/fps/guiHealthBarHud.cpp b/Engine/source/T3D/fps/guiHealthBarHud.cpp index 602d242b1..79b420e3a 100644 --- a/Engine/source/T3D/fps/guiHealthBarHud.cpp +++ b/Engine/source/T3D/fps/guiHealthBarHud.cpp @@ -147,6 +147,11 @@ void GuiHealthBarHud::onRender(Point2I offset, const RectI &updateRect) if (!conn) return; ShapeBase* control = dynamic_cast(conn->getControlObject()); + + //cover the case of a connection controling an object in turn controlling another + if (control && control->getControlObject()) + control = control->getControlObject(); + if (!control || !(control->getTypeMask() & (PlayerObjectType | VehicleObjectType))) return; diff --git a/Engine/source/T3D/fps/guiHealthTextHud.cpp b/Engine/source/T3D/fps/guiHealthTextHud.cpp index 1c202906c..faa798253 100644 --- a/Engine/source/T3D/fps/guiHealthTextHud.cpp +++ b/Engine/source/T3D/fps/guiHealthTextHud.cpp @@ -148,7 +148,12 @@ void GuiHealthTextHud::onRender(Point2I offset, const RectI &updateRect) GameConnection* conn = GameConnection::getConnectionToServer(); if (!conn) return; - ShapeBase* control = dynamic_cast(conn->getControlObject()); + ShapeBase* control = dynamic_cast(conn->getControlObject()); + + //cover the case of a connection controling an object in turn controlling another + if (control && control->getControlObject()) + control = control->getControlObject(); + if (!control || !(control->getTypeMask() & (PlayerObjectType | VehicleObjectType))) return; diff --git a/Engine/source/T3D/fx/explosion.cpp b/Engine/source/T3D/fx/explosion.cpp index f10543198..02676be26 100644 --- a/Engine/source/T3D/fx/explosion.cpp +++ b/Engine/source/T3D/fx/explosion.cpp @@ -1127,7 +1127,7 @@ bool Explosion::onNewDataBlock( GameBaseData *dptr, bool reload ) if (mDataBlock->isTempClone()) return true; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/fx/explosion.h b/Engine/source/T3D/fx/explosion.h index 447b7747d..0ea4c63d7 100644 --- a/Engine/source/T3D/fx/explosion.h +++ b/Engine/source/T3D/fx/explosion.h @@ -143,7 +143,10 @@ public: ExplosionData* cloneAndPerformSubstitutions(const SimObject*, S32 index=0); bool allowSubstitutions() const override { return true; } - void onShapeChanged() {} + void onShapeChanged() + { + reloadOnLocalClient(); + } }; diff --git a/Engine/source/T3D/fx/groundCover.cpp b/Engine/source/T3D/fx/groundCover.cpp index 65c4b810d..3f4343184 100644 --- a/Engine/source/T3D/fx/groundCover.cpp +++ b/Engine/source/T3D/fx/groundCover.cpp @@ -852,8 +852,11 @@ void GroundCover::unpackUpdate( NetConnection *connection, BitStream *stream ) // It's sloppy, but it works for now. _freeCells(); - if ( isProperlyAdded() ) + if (isProperlyAdded()) + { _initMaterial(); + _initShapes(); + } } } diff --git a/Engine/source/T3D/fx/groundCover.h b/Engine/source/T3D/fx/groundCover.h index b2ef23e05..af5d02858 100644 --- a/Engine/source/T3D/fx/groundCover.h +++ b/Engine/source/T3D/fx/groundCover.h @@ -341,7 +341,7 @@ protected: RectF mBillboardRects[MAX_COVERTYPES]; /// The cover shape filenames. - DECLARE_SHAPEASSET_ARRAY(GroundCover, Shape, MAX_COVERTYPES); + DECLARE_SHAPEASSET_ARRAY(GroundCover, Shape, MAX_COVERTYPES, onShapeChanged); DECLARE_ASSET_ARRAY_NET_SETGET(GroundCover, Shape, -1); /// The cover shape instances. @@ -409,6 +409,12 @@ protected: S32 randSeed ); void _debugRender( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ); + + void onShapeChanged() + { + _initShapes(); + setMaskBits(U32(-1)); + } }; #endif // _GROUNDCOVER_H_ diff --git a/Engine/source/T3D/fx/lightning.cpp b/Engine/source/T3D/fx/lightning.cpp index 10447fa6f..44c94b1a8 100644 --- a/Engine/source/T3D/fx/lightning.cpp +++ b/Engine/source/T3D/fx/lightning.cpp @@ -474,7 +474,7 @@ bool Lightning::onNewDataBlock( GameBaseData *dptr, bool reload ) if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) ) return false; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/fx/particleEmitter.cpp b/Engine/source/T3D/fx/particleEmitter.cpp index 77a9972d5..e6559b612 100644 --- a/Engine/source/T3D/fx/particleEmitter.cpp +++ b/Engine/source/T3D/fx/particleEmitter.cpp @@ -1134,7 +1134,7 @@ bool ParticleEmitter::onNewDataBlock( GameBaseData *dptr, bool reload ) return true; } - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/fx/particleEmitterNode.cpp b/Engine/source/T3D/fx/particleEmitterNode.cpp index 26e8a71b4..5197872a2 100644 --- a/Engine/source/T3D/fx/particleEmitterNode.cpp +++ b/Engine/source/T3D/fx/particleEmitterNode.cpp @@ -254,7 +254,7 @@ bool ParticleEmitterNode::onNewDataBlock( GameBaseData *dptr, bool reload ) return false; // Todo: Uncomment if this is a "leaf" class - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/fx/precipitation.cpp b/Engine/source/T3D/fx/precipitation.cpp index 9953b2228..6ac3c75c9 100644 --- a/Engine/source/T3D/fx/precipitation.cpp +++ b/Engine/source/T3D/fx/precipitation.cpp @@ -598,7 +598,7 @@ bool Precipitation::onNewDataBlock( GameBaseData *dptr, bool reload ) initMaterials(); } - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/fx/ribbonNode.cpp b/Engine/source/T3D/fx/ribbonNode.cpp index adc846017..fb8af2db6 100644 --- a/Engine/source/T3D/fx/ribbonNode.cpp +++ b/Engine/source/T3D/fx/ribbonNode.cpp @@ -159,7 +159,7 @@ bool RibbonNode::onNewDataBlock( GameBaseData *dptr, bool reload ) return false; // Todo: Uncomment if this is a "leaf" class - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/fx/splash.cpp b/Engine/source/T3D/fx/splash.cpp index df115d78b..d9be0cddb 100644 --- a/Engine/source/T3D/fx/splash.cpp +++ b/Engine/source/T3D/fx/splash.cpp @@ -440,7 +440,7 @@ bool Splash::onNewDataBlock( GameBaseData *dptr, bool reload ) if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload)) return false; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/gameBase/gameBase.cpp b/Engine/source/T3D/gameBase/gameBase.cpp index 8775f94b3..f16dafc06 100644 --- a/Engine/source/T3D/gameBase/gameBase.cpp +++ b/Engine/source/T3D/gameBase/gameBase.cpp @@ -95,7 +95,7 @@ IMPLEMENT_CALLBACK( GameBaseData, onAdd, void, ( GameBase* obj ), ( obj ), "}\n\n" "@endtsexample\n" ); -IMPLEMENT_CALLBACK( GameBaseData, onNewDataBlock, void, ( GameBase* obj ), ( obj ), +IMPLEMENT_CALLBACK( GameBaseData, onNewDataBlock, void, ( GameBase* obj, bool reload), ( obj, reload), "@brief Called when the object has a new datablock assigned.\n\n" "@param obj the GameBase object\n\n" "@see onAdd for an example\n" ); @@ -512,12 +512,12 @@ void GameBase::scriptOnAdd() mDataBlock->onAdd_callback( this ); } -void GameBase::scriptOnNewDataBlock() +void GameBase::scriptOnNewDataBlock(bool reload) { // Script onNewDataBlock() must be called by the leaf class // after everything is loaded. if (mDataBlock && !isGhost()) - mDataBlock->onNewDataBlock_callback( this ); + mDataBlock->onNewDataBlock_callback( this, reload); } void GameBase::scriptOnRemove() diff --git a/Engine/source/T3D/gameBase/gameBase.h b/Engine/source/T3D/gameBase/gameBase.h index 7c175f71e..c18b30196 100644 --- a/Engine/source/T3D/gameBase/gameBase.h +++ b/Engine/source/T3D/gameBase/gameBase.h @@ -115,7 +115,7 @@ public: /// @{ DECLARE_CALLBACK( void, onAdd, ( GameBase* obj ) ); DECLARE_CALLBACK( void, onRemove, ( GameBase* obj ) ); - DECLARE_CALLBACK( void, onNewDataBlock, ( GameBase* obj ) ); + DECLARE_CALLBACK( void, onNewDataBlock, ( GameBase* obj, bool reload) ); DECLARE_CALLBACK( void, onMount, ( SceneObject* obj, SceneObject* mountObj, S32 node ) ); DECLARE_CALLBACK( void, onUnmount, ( SceneObject* obj, SceneObject* mountObj, S32 node ) ); /// @} @@ -299,7 +299,7 @@ public: /// Executes the 'onNewDataBlock' script function for this object. /// /// @note This must be called after everything is loaded. - void scriptOnNewDataBlock(); + void scriptOnNewDataBlock(bool reload = false); /// Executes the 'onRemove' script function for this object. /// @note This must be called while the object is still valid diff --git a/Engine/source/T3D/gameFunctions.cpp b/Engine/source/T3D/gameFunctions.cpp index c40e2f081..24487c5ec 100644 --- a/Engine/source/T3D/gameFunctions.cpp +++ b/Engine/source/T3D/gameFunctions.cpp @@ -669,6 +669,7 @@ static void RegisterGameFunctions() Con::setIntVariable("$TypeMasks::PathShapeObjectType", PathShapeObjectType); // PATHSHAPE END Con::setIntVariable("$TypeMasks::TurretObjectType", TurretObjectType); + Con::setIntVariable("$TypeMasks::AIObjectType", AIObjectType); Con::addVariable("Ease::InOut", TypeS32, &gEaseInOut, "InOut ease for curve movement.\n" diff --git a/Engine/source/T3D/item.cpp b/Engine/source/T3D/item.cpp index 6c5395452..3681774da 100644 --- a/Engine/source/T3D/item.cpp +++ b/Engine/source/T3D/item.cpp @@ -422,7 +422,7 @@ bool Item::onNewDataBlock( GameBaseData *dptr, bool reload ) return false; if (!mSubclassItemHandlesScene) - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); if ( isProperlyAdded() ) _updatePhysics(); diff --git a/Engine/source/T3D/missionMarker.cpp b/Engine/source/T3D/missionMarker.cpp index 5fac601ce..a18523ef7 100644 --- a/Engine/source/T3D/missionMarker.cpp +++ b/Engine/source/T3D/missionMarker.cpp @@ -142,7 +142,7 @@ bool MissionMarker::onNewDataBlock( GameBaseData *dptr, bool reload ) mDataBlock = dynamic_cast( dptr ); if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) ) return(false); - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return(true); } diff --git a/Engine/source/T3D/objectTypes.h b/Engine/source/T3D/objectTypes.h index c6b05df74..47fb2edee 100644 --- a/Engine/source/T3D/objectTypes.h +++ b/Engine/source/T3D/objectTypes.h @@ -174,7 +174,7 @@ enum SceneObjectTypes /// @see TurretShape TurretObjectType = BIT(29), N_A_31 = BIT(30), - N_A_32 = BIT(31), + AIObjectType = BIT(31), /// @} }; diff --git a/Engine/source/T3D/pathCamera.cpp b/Engine/source/T3D/pathCamera.cpp index 3a4ccd578..bb14db972 100644 --- a/Engine/source/T3D/pathCamera.cpp +++ b/Engine/source/T3D/pathCamera.cpp @@ -181,7 +181,7 @@ bool PathCamera::onNewDataBlock( GameBaseData *dptr, bool reload ) if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) ) return false; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/pathShape.cpp b/Engine/source/T3D/pathShape.cpp index 846e7bf18..1a903e555 100644 --- a/Engine/source/T3D/pathShape.cpp +++ b/Engine/source/T3D/pathShape.cpp @@ -134,7 +134,7 @@ bool PathShape::onNewDataBlock(GameBaseData* dptr, bool reload) if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload)) return false; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/physics/physicsDebris.h b/Engine/source/T3D/physics/physicsDebris.h index 2626300e9..9b9ae6861 100644 --- a/Engine/source/T3D/physics/physicsDebris.h +++ b/Engine/source/T3D/physics/physicsDebris.h @@ -97,7 +97,10 @@ public: void packData( BitStream *stream ) override; void unpackData( BitStream *stream ) override; - void onShapeChanged() {} + void onShapeChanged() + { + reloadOnLocalClient(); + } DECLARE_CONOBJECT( PhysicsDebrisData ); diff --git a/Engine/source/T3D/physics/physicsShape.h b/Engine/source/T3D/physics/physicsShape.h index 144580c31..466e39ebf 100644 --- a/Engine/source/T3D/physics/physicsShape.h +++ b/Engine/source/T3D/physics/physicsShape.h @@ -135,7 +135,10 @@ public: SimObjectRef< ExplosionData > explosion; SimObjectRef< PhysicsShapeData > destroyedShape; - void onShapeChanged() {} + void onShapeChanged() + { + reloadOnLocalClient(); + } }; typedef PhysicsShapeData::SimType PhysicsSimType; diff --git a/Engine/source/T3D/player.cpp b/Engine/source/T3D/player.cpp index 801df58df..c736ff022 100644 --- a/Engine/source/T3D/player.cpp +++ b/Engine/source/T3D/player.cpp @@ -460,7 +460,7 @@ PlayerData::PlayerData() jumpTowardsNormal = true; physicsPlayerType = StringTable->EmptyString(); - + mControlMap = StringTable->EmptyString(); dMemset( actionList, 0, sizeof(actionList) ); } @@ -739,7 +739,9 @@ void PlayerData::initPersistFields() endGroup( "Camera" ); addGroup( "Movement" ); - + addField("controlMap", TypeString, Offset(mControlMap, PlayerData), + "@brief movemap used by these types of objects.\n\n"); + addFieldV( "maxStepHeight", TypeRangedF32, Offset(maxStepHeight, PlayerData), &CommonValidators::PositiveFloat, "@brief Maximum height the player can step up.\n\n" "The player will automatically step onto changes in ground height less " @@ -1640,7 +1642,6 @@ Player::Player() mLastAbsoluteYaw = 0.0f; mLastAbsolutePitch = 0.0f; mLastAbsoluteRoll = 0.0f; - afx_init(); } @@ -1738,7 +1739,6 @@ bool Player::onAdd() world ); mPhysicsRep->setTransform( getTransform() ); } - return true; } @@ -1923,7 +1923,7 @@ bool Player::onNewDataBlock( GameBaseData *dptr, bool reload ) onScaleChanged(); resetWorldBox(); - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } @@ -2255,12 +2255,6 @@ void Player::advanceTime(F32 dt) } } } - -bool Player::getAIMove(Move* move) -{ - return false; -} - void Player::setState(ActionState state, U32 recoverTicks) { if (state != mState) { diff --git a/Engine/source/T3D/player.h b/Engine/source/T3D/player.h index b80b3f0e5..f1f10e29a 100644 --- a/Engine/source/T3D/player.h +++ b/Engine/source/T3D/player.h @@ -50,6 +50,12 @@ class Player; class OpenVRTrackedObject; #endif +#ifdef TORQUE_NAVIGATION_ENABLED +#include "navigation/navPath.h" +#include "navigation/navMesh.h" +#include "navigation/coverPoint.h" +#endif // TORQUE_NAVIGATION_ENABLED + //---------------------------------------------------------------------------- struct PlayerData: public ShapeBaseData { @@ -76,7 +82,7 @@ struct PlayerData: public ShapeBaseData { /// that we don't create a TSThread on the player if we don't /// need to. - DECLARE_SHAPEASSET_ARRAY(PlayerData, ShapeFP, ShapeBase::MaxMountedImages); ///< Used to render with mounted images in first person [optional] + DECLARE_SHAPEASSET_ARRAY(PlayerData, ShapeFP, ShapeBase::MaxMountedImages, onShapeChanged); ///< Used to render with mounted images in first person [optional] DECLARE_ASSET_ARRAY_SETGET(PlayerData, ShapeFP); StringTableEntry imageAnimPrefixFP; ///< Passed along to mounted images to modify @@ -346,7 +352,7 @@ struct PlayerData: public ShapeBaseData { // Jump off surfaces at their normal rather than straight up bool jumpTowardsNormal; - + StringTableEntry mControlMap; // For use if/when mPhysicsPlayer is created StringTableEntry physicsPlayerType; @@ -366,6 +372,11 @@ struct PlayerData: public ShapeBaseData { void packData(BitStream* stream) override; void unpackData(BitStream* stream) override; + void onShapeChanged() + { + reloadOnLocalClient(); + } + /// @name Callbacks /// @{ DECLARE_CALLBACK( void, onPoseChange, ( Player* obj, const char* oldPose, const char* newPose ) ); @@ -753,8 +764,6 @@ public: Point3F getMomentum() const override; void setMomentum(const Point3F &momentum) override; bool displaceObject(const Point3F& displaceVector) override; - virtual bool getAIMove(Move*); - bool checkDismountPosition(const MatrixF& oldPos, const MatrixF& newPos); ///< Is it safe to dismount here? // diff --git a/Engine/source/T3D/projectile.cpp b/Engine/source/T3D/projectile.cpp index 56f8af638..58c6f3aa6 100644 --- a/Engine/source/T3D/projectile.cpp +++ b/Engine/source/T3D/projectile.cpp @@ -56,6 +56,7 @@ #include "T3D/decal/decalData.h" #include "T3D/lightDescription.h" #include "console/engineAPI.h" +#include "T3D/rigidShape.h" IMPLEMENT_CO_DATABLOCK_V1(ProjectileData); @@ -163,6 +164,7 @@ ProjectileData::ProjectileData() scale.set( 1.0f, 1.0f, 1.0f ); isBallistic = false; + mExplodeOnTmeout = false; velInheritFactor = 1.0f; muzzleVelocity = 50; @@ -203,6 +205,7 @@ ProjectileData::ProjectileData(const ProjectileData& other, bool temp_clone) : G muzzleVelocity = other.muzzleVelocity; impactForce = other.impactForce; isBallistic = other.isBallistic; + mExplodeOnTmeout = other.mExplodeOnTmeout; bounceElasticity = other.bounceElasticity; bounceFriction = other.bounceFriction; gravityMod = other.gravityMod; @@ -285,6 +288,8 @@ void ProjectileData::initPersistFields() addProtectedFieldV("fadeDelay", TypeRangedS32, Offset(fadeDelay, ProjectileData), &setFadeDelay, &getScaledValue, &CommonValidators::NaturalNumber, "@brief Amount of time, in milliseconds, before the projectile begins to fade out.\n\n" "This value must be smaller than the projectile's lifetime to have an affect."); + addField("explodeOnTmeout", TypeBool, Offset(mExplodeOnTmeout, ProjectileData), + "@brief Detetmines if the projectile should explode on timeout"); addField("isBallistic", TypeBool, Offset(isBallistic, ProjectileData), "@brief Detetmines if the projectile should be affected by gravity and whether or not " "it bounces before exploding.\n\n"); @@ -455,13 +460,14 @@ void ProjectileData::packData(BitStream* stream) stream->write(armingDelay); stream->write(fadeDelay); + stream->writeFlag(mExplodeOnTmeout); if(stream->writeFlag(isBallistic)) { stream->write(gravityMod); stream->write(bounceElasticity); stream->write(bounceFriction); } - + } void ProjectileData::unpackData(BitStream* stream) @@ -514,6 +520,7 @@ void ProjectileData::unpackData(BitStream* stream) stream->read(&armingDelay); stream->read(&fadeDelay); + mExplodeOnTmeout = stream->readFlag(); isBallistic = stream->readFlag(); if(isBallistic) { @@ -611,6 +618,7 @@ Projectile::Projectile() mProjectileShape( NULL ), mActivateThread( NULL ), mMaintainThread( NULL ), + mHasHit(false), mHasExploded( false ), mFadeValue( 1.0f ) { @@ -1128,10 +1136,18 @@ void Projectile::processTick( const Move *move ) void Projectile::simulate( F32 dt ) { - if ( isServerObject() && mCurrTick >= mDataBlock->lifetime ) + if ( isServerObject() ) { - deleteObject(); - return; + if (mCurrTick >= (mDataBlock->lifetime - TickMs)) + { + if (mDataBlock->mExplodeOnTmeout) + explode(mCurrPosition, Point3F::UnitZ, VehicleObjectType); + } + if (mCurrTick >= mDataBlock->lifetime || (mHasHit && mCurrTick < mDataBlock->armingDelay)) + { + deleteObject(); + return; + } } if ( mHasExploded ) @@ -1167,9 +1183,16 @@ void Projectile::simulate( F32 dt ) if ( mPhysicsWorld ) hit = mPhysicsWorld->castRay( oldPosition, newPosition, &rInfo, Point3F( newPosition - oldPosition) * mDataBlock->impactForce ); - else + else + { hit = getContainer()->castRay(oldPosition, newPosition, dynamicCollisionMask | staticCollisionMask, &rInfo); - + if (hit && rInfo.object->getTypeMask() & VehicleObjectType) + { + RigidShape* aRigid = dynamic_cast(rInfo.object); + if (aRigid) + aRigid->applyImpulse(rInfo.point, Point3F(newPosition - oldPosition) * mDataBlock->impactForce); + } + } if ( hit ) { // make sure the client knows to bounce @@ -1237,6 +1260,8 @@ void Projectile::simulate( F32 dt ) else { mCurrVelocity = Point3F::Zero; + newPosition = oldPosition = rInfo.point + rInfo.normal * 0.05f; + mHasHit = true; } } diff --git a/Engine/source/T3D/projectile.h b/Engine/source/T3D/projectile.h index 671c3f98f..2ca827ea7 100644 --- a/Engine/source/T3D/projectile.h +++ b/Engine/source/T3D/projectile.h @@ -87,9 +87,9 @@ public: /// Force imparted on a hit object. F32 impactForce; + bool mExplodeOnTmeout; /// Should it arc? bool isBallistic; - /// How HIGH should it bounce (parallel to normal), [0,1] F32 bounceElasticity; /// How much momentum should be lost when it bounces (perpendicular to normal), [0,1] @@ -154,7 +154,10 @@ public: ProjectileData(const ProjectileData&, bool = false); bool allowSubstitutions() const override { return true; } - void onShapeChanged() {} + void onShapeChanged() + { + reloadOnLocalClient(); + } }; @@ -274,7 +277,7 @@ protected: LightInfo *mLight; LightState mLightState; - + bool mHasHit; bool mHasExploded; ///< Prevent rendering, lighting, and duplicate explosions. F32 mFadeValue; ///< set in processTick, interpolation between fadeDelay and lifetime ///< in data block diff --git a/Engine/source/T3D/proximityMine.cpp b/Engine/source/T3D/proximityMine.cpp index 8ce924ea1..fd02fc091 100644 --- a/Engine/source/T3D/proximityMine.cpp +++ b/Engine/source/T3D/proximityMine.cpp @@ -350,7 +350,7 @@ bool ProximityMine::onNewDataBlock( GameBaseData* dptr, bool reload ) if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) ) return false; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/rigidShape.cpp b/Engine/source/T3D/rigidShape.cpp index e216e7473..8a453b065 100644 --- a/Engine/source/T3D/rigidShape.cpp +++ b/Engine/source/T3D/rigidShape.cpp @@ -906,7 +906,7 @@ bool RigidShape::onNewDataBlock(GameBaseData* dptr, bool reload) else mRigid.setObjectInertia(mObjBox.maxExtents - mObjBox.minExtents); - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/shapeBase.cpp b/Engine/source/T3D/shapeBase.cpp index 968e8fb9b..92f5f4da6 100644 --- a/Engine/source/T3D/shapeBase.cpp +++ b/Engine/source/T3D/shapeBase.cpp @@ -69,6 +69,7 @@ #include "core/stream/fileStream.h" #include "T3D/accumulationVolume.h" #include "console/persistenceManager.h" +#include "AI/AIController.h" IMPLEMENT_CO_DATABLOCK_V1(ShapeBaseData); @@ -172,6 +173,8 @@ ShapeBaseData::ShapeBaseData() density( 1.0f ), maxEnergy( 0.0f ), maxDamage( 1.0f ), + mCollisionMul(0.0f), + mImpactMul(0.0f), repairRate( 0.0033f ), disabledLevel( 1.0f ), destroyedLevel( 1.0f ), @@ -195,7 +198,8 @@ ShapeBaseData::ShapeBaseData() useEyePoint( false ), isInvincible( false ), renderWhenDestroyed( true ), - inheritEnergyFromMount( false ) + inheritEnergyFromMount( false ), + mAIControllData(NULL) { INIT_ASSET(Shape); INIT_ASSET(DebrisShape); @@ -229,6 +233,8 @@ ShapeBaseData::ShapeBaseData(const ShapeBaseData& other, bool temp_clone) : Game density = other.density; maxEnergy = other.maxEnergy; maxDamage = other.maxDamage; + mCollisionMul = other.mCollisionMul; + mImpactMul = other.mImpactMul; repairRate = other.repairRate; disabledLevel = other.disabledLevel; destroyedLevel = other.destroyedLevel; @@ -345,7 +351,7 @@ bool ShapeBaseData::preload(bool server, String &errorStr) S32 i; U32 assetStatus = ShapeAsset::getAssetErrCode(mShapeAsset); - if (assetStatus == AssetBase::Ok|| assetStatus == AssetBase::UsingFallback) + if (assetStatus == AssetBase::Ok || assetStatus == AssetBase::UsingFallback) { if (!server && !mShape->preloadMaterialList(mShape.getPath()) && NetConnection::filesWereDownloaded()) shapeError = true; @@ -544,6 +550,10 @@ void ShapeBaseData::initPersistFields() addField("silentBBoxValidation", TypeBool, Offset(silent_bbox_check, ShapeBaseData)); INITPERSISTFIELD_SHAPEASSET(DebrisShape, ShapeBaseData, "The shape asset to use for auto-generated breakups via blowup(). @note may not be functional."); endGroup( "Shapes" ); + addGroup("Movement"); + addField("aiControllerData", TYPEID< AIControllerData >(), Offset(mAIControllData, ShapeBaseData), + "@brief ai controller used by these types of objects.\n\n"); + endGroup("Movement"); addGroup("Particle Effects"); addField( "explosion", TYPEID< ExplosionData >(), Offset(explosion, ShapeBaseData), @@ -585,6 +595,10 @@ void ShapeBaseData::initPersistFields() addField( "isInvincible", TypeBool, Offset(isInvincible, ShapeBaseData), "Invincible flag; when invincible, the object cannot be damaged or " "repaired." ); + addFieldV("collisionMul", TypeRangedF32, Offset(mCollisionMul, ShapeBaseData), &CommonValidators::PositiveFloat, + "collision damage multiplier"); + addFieldV("impactMul", TypeRangedF32, Offset(mImpactMul, ShapeBaseData), &CommonValidators::PositiveFloat, + "impact damage multiplier"); endGroup( "Damage/Energy" ); addGroup( "Camera", "The settings used by the shape when it is the camera." ); @@ -904,7 +918,17 @@ void ShapeBaseData::unpackData(BitStream* stream) silent_bbox_check = stream->readFlag(); } +// +// +void ShapeBaseData::onShapeChanged() +{ + reloadOnLocalClient(); +} +void ShapeBaseData::onDebrisChanged() +{ + reloadOnLocalClient(); +} //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -981,7 +1005,8 @@ ShapeBase::ShapeBase() mCameraFov( 90.0f ), mIsControlled( false ), mLastRenderFrame( 0 ), - mLastRenderDistance( 0.0f ) + mLastRenderDistance( 0.0f ), + mAIController(NULL) { mTypeMask |= ShapeBaseObjectType | LightObjectType; @@ -1032,6 +1057,7 @@ ShapeBase::~ShapeBase() cur->next = sFreeTimeoutList; sFreeTimeoutList = cur; } + if (mAIController) mAIController->deleteObject(); } void ShapeBase::initPersistFields() @@ -5449,3 +5475,44 @@ DefineEngineMethod(ShapeBase, getNodePoint, Point3F, (const char* nodeName), , return pos; } + +bool ShapeBase::setAIController(SimObjectId controller) +{ + if (Sim::findObject(controller, mAIController) && mAIController->mControllerData) + { + mAIController->setAIInfo(this); + mTypeMask |= AIObjectType; + return true; + } + Con::errorf("unable to find AIController : %i", controller); + mAIController = NULL; + mTypeMask |= ~AIObjectType; + return false; +} + +bool ShapeBase::getAIMove(Move* move) +{ + if (!isServerObject()) return false; + if (isControlled()) return false; //something else is steering us, so use that one's controller + if (!(mTypeMask & VehicleObjectType || mTypeMask & PlayerObjectType)) return false; //only support players and vehicles for now + if (mAIController) + { + mAIController->getAIMove(move); //actual result + mTypeMask |= AIObjectType; + return true; + } + mAIController = NULL; + mTypeMask &= ~AIObjectType; + return false; +} + + +DefineEngineMethod(ShapeBase, setAIController, bool, (S32 controller), , "") +{ + return object->setAIController(controller); +} + +DefineEngineMethod(ShapeBase, getAIController, AIController*, (), , "") +{ + return object->getAIController(); +} diff --git a/Engine/source/T3D/shapeBase.h b/Engine/source/T3D/shapeBase.h index 706f54b72..46f9a3270 100644 --- a/Engine/source/T3D/shapeBase.h +++ b/Engine/source/T3D/shapeBase.h @@ -88,6 +88,8 @@ class ShapeBase; class SFXSource; class SFXTrack; class SFXProfile; +struct AIController; +struct AIControllerData; typedef void* Light; @@ -378,7 +380,7 @@ struct ShapeBaseImageData: public GameBaseData { F32 scriptAnimTransitionTime; ///< The amount of time to transition between the previous sequence and new sequence ///< when the script prefix has changed. - DECLARE_SHAPEASSET_ARRAY(ShapeBaseImageData, Shape, MaxShapes); ///< Name of shape to render. + DECLARE_SHAPEASSET_ARRAY(ShapeBaseImageData, Shape, MaxShapes, onShapeChanged); ///< Name of shape to render. DECLARE_ASSET_ARRAY_SETGET(ShapeBaseImageData, Shape); //DECLARE_SHAPEASSET(ShapeBaseImageData, ShapeFP); ///< Name of shape to render in first person (optional). @@ -505,6 +507,11 @@ struct ShapeBaseImageData: public GameBaseData { void handleStateSoundTrack(const U32& stateId); + void onShapeChanged() + { + reloadOnLocalClient(); + } + /// @} /// @name Callbacks @@ -555,6 +562,7 @@ public: U32 cubeDescId; ReflectorDesc *reflectorDesc; + AIControllerData* mAIControllData; /// @name Destruction /// /// Everyone likes to blow things up! @@ -579,6 +587,8 @@ public: F32 density; F32 maxEnergy; F32 maxDamage; + F32 mCollisionMul; + F32 mImpactMul; F32 repairRate; ///< Rate per tick. F32 disabledLevel; @@ -681,8 +691,8 @@ public: Vector txr_tag_remappings; bool silent_bbox_check; - void onShapeChanged() {} - void onDebrisChanged() {} + void onShapeChanged(); + void onDebrisChanged(); public: ShapeBaseData(const ShapeBaseData&, bool = false); }; @@ -1754,6 +1764,11 @@ public: /// Returns true if this object is controlling by something bool isControlled() { return(mIsControlled); } + AIController* mAIController; + bool setAIController(SimObjectId controller); + AIController* getAIController() { return mAIController; }; + virtual bool getAIMove(Move* move); + /// Returns true if this object is being used as a camera in first person bool isFirstPerson() const; @@ -1895,7 +1910,6 @@ public: void registerCollisionCallback(CollisionEventCallback*); void unregisterCollisionCallback(CollisionEventCallback*); -protected: enum { ANIM_OVERRIDDEN = BIT(0), BLOCK_USER_CONTROL = BIT(1), @@ -1903,6 +1917,8 @@ protected: BAD_ANIM_ID = 999999999, BLENDED_CLIP = 0x80000000, }; + U8 anim_clip_flags; +protected: struct BlendThread { TSThread* thread; @@ -1910,7 +1926,6 @@ protected: }; Vector blend_clips; static U32 unique_anim_tag_counter; - U8 anim_clip_flags; S32 last_anim_id; U32 last_anim_tag; U32 last_anim_lock_tag; diff --git a/Engine/source/T3D/staticShape.cpp b/Engine/source/T3D/staticShape.cpp index de47194f5..66e9ec454 100644 --- a/Engine/source/T3D/staticShape.cpp +++ b/Engine/source/T3D/staticShape.cpp @@ -219,7 +219,7 @@ bool StaticShape::onNewDataBlock(GameBaseData* dptr, bool reload) if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload)) return false; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/trigger.cpp b/Engine/source/T3D/trigger.cpp index dcccd0778..9df293ba5 100644 --- a/Engine/source/T3D/trigger.cpp +++ b/Engine/source/T3D/trigger.cpp @@ -465,7 +465,7 @@ bool Trigger::onNewDataBlock( GameBaseData *dptr, bool reload ) if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) ) return false; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/turret/aiTurretShape.cpp b/Engine/source/T3D/turret/aiTurretShape.cpp index 0e5ce0248..5ad3df020 100644 --- a/Engine/source/T3D/turret/aiTurretShape.cpp +++ b/Engine/source/T3D/turret/aiTurretShape.cpp @@ -545,7 +545,7 @@ bool AITurretShape::onNewDataBlock(GameBaseData* dptr, bool reload) mShapeInstance->setTimeScale(mStateAnimThread,0); } - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/turret/turretShape.cpp b/Engine/source/T3D/turret/turretShape.cpp index 8c523588e..e155663aa 100644 --- a/Engine/source/T3D/turret/turretShape.cpp +++ b/Engine/source/T3D/turret/turretShape.cpp @@ -127,6 +127,7 @@ TurretShapeData::TurretShapeData() recoilSequence[i] = -1; pitchSequence = -1; headingSequence = -1; + mControlMap = StringTable->EmptyString(); } void TurretShapeData::initPersistFields() @@ -134,6 +135,8 @@ void TurretShapeData::initPersistFields() docsURL; Parent::initPersistFields(); addGroup("Steering"); + addField("controlMap", TypeString, Offset(mControlMap, TurretShapeData), + "@brief movemap used by these types of objects.\n\n"); addField("zRotOnly", TypeBool, Offset(zRotOnly, TurretShapeData), "@brief Should the turret allow only z rotations.\n\n" "True indicates that the turret may only be rotated on its z axis, just like the Item class. " @@ -440,7 +443,7 @@ bool TurretShape::onNewDataBlock(GameBaseData* dptr, bool reload) if (!mSubclassTurretShapeHandlesScene) { - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); } return true; diff --git a/Engine/source/T3D/turret/turretShape.h b/Engine/source/T3D/turret/turretShape.h index b31024e07..a086d79d7 100644 --- a/Engine/source/T3D/turret/turretShape.h +++ b/Engine/source/T3D/turret/turretShape.h @@ -80,6 +80,7 @@ public: bool startLoaded; ///< Should the turret's mounted weapon(s) start in a loaded state? bool zRotOnly; ///< Should the turret allow only z rotations (like an item)? + StringTableEntry mControlMap; public: TurretShapeData(); diff --git a/Engine/source/T3D/vehicles/flyingVehicle.cpp b/Engine/source/T3D/vehicles/flyingVehicle.cpp index efe611b9a..24cf33490 100644 --- a/Engine/source/T3D/vehicles/flyingVehicle.cpp +++ b/Engine/source/T3D/vehicles/flyingVehicle.cpp @@ -407,7 +407,7 @@ bool FlyingVehicle::onNewDataBlock(GameBaseData* dptr, bool reload) mJetThread[i] = 0; } - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/vehicles/hoverVehicle.cpp b/Engine/source/T3D/vehicles/hoverVehicle.cpp index 7e7f748a5..482364bd3 100644 --- a/Engine/source/T3D/vehicles/hoverVehicle.cpp +++ b/Engine/source/T3D/vehicles/hoverVehicle.cpp @@ -549,7 +549,7 @@ bool HoverVehicle::onNewDataBlock(GameBaseData* dptr, bool reload) } // Todo: Uncomment if this is a "leaf" class - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/vehicles/vehicle.cpp b/Engine/source/T3D/vehicles/vehicle.cpp index cfbd9a876..9ad0abdbf 100644 --- a/Engine/source/T3D/vehicles/vehicle.cpp +++ b/Engine/source/T3D/vehicles/vehicle.cpp @@ -141,12 +141,14 @@ VehicleData::VehicleData() dMemset( damageEmitterOffset, 0, sizeof( damageEmitterOffset ) ); dMemset( damageEmitterIDList, 0, sizeof( damageEmitterIDList ) ); dMemset( damageLevelTolerance, 0, sizeof( damageLevelTolerance ) ); + mControlMap = StringTable->EmptyString(); numDmgEmitterAreas = 0; collDamageThresholdVel = 20; collDamageMultiplier = 0.05f; enablePhysicsRep = true; + mControlMap = StringTable->EmptyString(); } @@ -320,7 +322,14 @@ void VehicleData::initPersistFields() "velocity).\n\nCurrently unused." ); endGroup("Collision"); + addGroup("Movement"); + addField("controlMap", TypeString, Offset(mControlMap, VehicleData), + "@brief movemap used by these types of objects.\n\n"); + endGroup("Movement"); + addGroup("Steering"); + addField("controlMap", TypeString, Offset(mControlMap, VehicleData), + "@brief movemap used by these types of objects.\n\n"); addFieldV( "jetForce", TypeRangedF32, Offset(jetForce, VehicleData), &CommonValidators::PositiveFloat, "@brief Additional force applied to the vehicle when it is jetting.\n\n" "For WheeledVehicles, the force is applied in the forward direction. For " @@ -471,7 +480,6 @@ bool Vehicle::onAdd() void Vehicle::onRemove() { SAFE_DELETE(mPhysicsRep); - U32 i=0; for( i=0; itrigger[0]); setImageTriggerState(1,move->trigger[1]); + //legacy code has trigger 2 and 3 reserved + setImageTriggerState(2, move->trigger[4]); + setImageTriggerState(3, move->trigger[5]); } // Throttle diff --git a/Engine/source/T3D/vehicles/vehicle.h b/Engine/source/T3D/vehicles/vehicle.h index 402a3109a..ba7bf8e68 100644 --- a/Engine/source/T3D/vehicles/vehicle.h +++ b/Engine/source/T3D/vehicles/vehicle.h @@ -27,6 +27,8 @@ #include "T3D/rigidShape.h" #endif +#include "T3D/AI/AIController.h" + class ParticleEmitter; class ParticleEmitterData; class ClippedPolyList; @@ -70,6 +72,7 @@ struct VehicleData : public RigidShapeData F32 numDmgEmitterAreas; bool enablePhysicsRep; + StringTableEntry mControlMap; // VehicleData(); @@ -98,7 +101,6 @@ class Vehicle : public RigidShape Point2F mSteering; F32 mThrottle; bool mJetting; - GFXStateBlockRef mSolidSB; SimObjectPtr mDamageEmitterList[VehicleData::VC_NUM_DAMAGE_EMITTERS]; @@ -146,6 +148,9 @@ public: bool onAdd() override; void onRemove() override; + Point2F getSteering() { return mSteering; }; + F32 getThrottle() { return mThrottle;}; + /// Interpolates between move ticks @see processTick /// @param dt Change in time between the last call and this call to the function void advanceTime(F32 dt) override; diff --git a/Engine/source/T3D/vehicles/wheeledVehicle.cpp b/Engine/source/T3D/vehicles/wheeledVehicle.cpp index 88d7f67ce..9f3febd13 100644 --- a/Engine/source/T3D/vehicles/wheeledVehicle.cpp +++ b/Engine/source/T3D/vehicles/wheeledVehicle.cpp @@ -711,7 +711,7 @@ bool WheeledVehicle::onNewDataBlock(GameBaseData* dptr, bool reload) mJetSound = SFX->createSource( mDataBlock->getWheeledVehicleSoundsProfile(WheeledVehicleData::JetSound), &getTransform() ); } - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/T3D/vehicles/wheeledVehicle.h b/Engine/source/T3D/vehicles/wheeledVehicle.h index 45161db12..f208fbf5b 100644 --- a/Engine/source/T3D/vehicles/wheeledVehicle.h +++ b/Engine/source/T3D/vehicles/wheeledVehicle.h @@ -74,7 +74,10 @@ struct WheeledVehicleTire: public SimDataBlock void packData(BitStream* stream) override; void unpackData(BitStream* stream) override; - void onShapeChanged() {} + void onShapeChanged() + { + reloadOnLocalClient(); + } }; diff --git a/Engine/source/afx/afxMagicMissile.h b/Engine/source/afx/afxMagicMissile.h index e3f6ee755..8aa8f8084 100644 --- a/Engine/source/afx/afxMagicMissile.h +++ b/Engine/source/afx/afxMagicMissile.h @@ -66,7 +66,10 @@ protected: public: enum { MaxLifetimeTicks = 4095 }; - void onShapeChanged() {} + void onShapeChanged() + { + reloadOnLocalClient(); + } public: // variables set in datablock definition: diff --git a/Engine/source/afx/afxSpellBook.cpp b/Engine/source/afx/afxSpellBook.cpp index 35d207c57..d902d36ad 100644 --- a/Engine/source/afx/afxSpellBook.cpp +++ b/Engine/source/afx/afxSpellBook.cpp @@ -206,7 +206,7 @@ bool afxSpellBook::onNewDataBlock(GameBaseData* dptr, bool reload) if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload)) return false; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/afx/ce/afxModel.h b/Engine/source/afx/ce/afxModel.h index 521409735..de2656b8f 100644 --- a/Engine/source/afx/ce/afxModel.h +++ b/Engine/source/afx/ce/afxModel.h @@ -94,7 +94,10 @@ public: static void initPersistFields(); - void onShapeChanged() {} + void onShapeChanged() + { + reloadOnLocalClient(); + } void onSequenceChanged() {} DECLARE_CONOBJECT(afxModelData); diff --git a/Engine/source/afx/ce/afxParticleEmitter.cpp b/Engine/source/afx/ce/afxParticleEmitter.cpp index cadf0d3ed..a3bb9e448 100644 --- a/Engine/source/afx/ce/afxParticleEmitter.cpp +++ b/Engine/source/afx/ce/afxParticleEmitter.cpp @@ -1064,7 +1064,7 @@ bool afxParticleEmitter::onNewDataBlock(GameBaseData* dptr, bool reload) if (mDataBlock->isTempClone()) return true; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } @@ -1108,7 +1108,7 @@ bool afxParticleEmitterVector::onNewDataBlock(GameBaseData* dptr, bool reload) if (mDataBlock->isTempClone()) return true; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } @@ -1177,7 +1177,7 @@ bool afxParticleEmitterCone::onNewDataBlock(GameBaseData* dptr, bool reload) if (mDataBlock->isTempClone()) return true; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } @@ -1294,7 +1294,7 @@ bool afxParticleEmitterPath::onNewDataBlock(GameBaseData* dptr, bool reload) if (mDataBlock->isTempClone()) return true; - scriptOnNewDataBlock(); + scriptOnNewDataBlock(reload); return true; } diff --git a/Engine/source/assets/assetManager.cpp b/Engine/source/assets/assetManager.cpp index 863f7638c..0b166a238 100644 --- a/Engine/source/assets/assetManager.cpp +++ b/Engine/source/assets/assetManager.cpp @@ -1563,6 +1563,53 @@ bool AssetManager::restoreAssetTags( void ) //----------------------------------------------------------------------------- +const char* AssetManager::getAssetLooseFiles(const char* pAssetId) +{ + // Debug Profiling. + PROFILE_SCOPE(AssetManager_getAssetLooseFIles); + + // Sanity! + AssertFatal(pAssetId != NULL, "Cannot look up NULL asset Id."); + + // Find asset. + AssetDefinition* pAssetDefinition = findAsset(pAssetId); + + // Did we find the asset? + if (pAssetDefinition == NULL) + { + // No, so warn. + Con::warnf("Asset Manager: Failed to find asset Id '%s' as it does not exist.", pAssetId); + return String::EmptyString; + } + + // Info. + if (mEchoInfo) + { + Con::printSeparator(); + Con::printf("Asset Manager: Started getting loose files of Asset Id '%s'...", pAssetId); + } + + String looseFileList = ""; + Vector& assetLooseFiles = pAssetDefinition->mAssetLooseFiles; + for (Vector::iterator looseFileItr = assetLooseFiles.begin(); looseFileItr != assetLooseFiles.end(); ++looseFileItr) + { + // Fetch loose file. + StringTableEntry looseFile = *looseFileItr; + + looseFileList += looseFile; + + if (looseFileItr != assetLooseFiles.end()) + looseFileList += "\t"; + } + + char* ret = Con::getReturnBuffer(1024); + dSprintf(ret, 1024, "%s", looseFileList.c_str()); + + return ret; +} + +//----------------------------------------------------------------------------- + S32 QSORT_CALLBACK descendingAssetDefinitionLoadCount(const void* a, const void* b) { // Debug Profiling. diff --git a/Engine/source/assets/assetManager.h b/Engine/source/assets/assetManager.h index 43a5a6c35..9f243fc17 100644 --- a/Engine/source/assets/assetManager.h +++ b/Engine/source/assets/assetManager.h @@ -341,6 +341,9 @@ public: bool restoreAssetTags( void ); inline AssetTagsManifest* getAssetTags( void ) const { return mAssetTagsManifest; } + /// Loose File management + const char* getAssetLooseFiles(const char* pAssetId); + /// Info. inline U32 getDeclaredAssetCount( void ) const { return (U32)mDeclaredAssets.size(); } inline U32 getReferencedAssetCount( void ) const { return (U32)mReferencedAssets.size(); } diff --git a/Engine/source/assets/assetManager_ScriptBinding.h b/Engine/source/assets/assetManager_ScriptBinding.h index ddfb3f3f2..9e675ed52 100644 --- a/Engine/source/assets/assetManager_ScriptBinding.h +++ b/Engine/source/assets/assetManager_ScriptBinding.h @@ -432,6 +432,20 @@ DefineEngineMethod(AssetManager, getAssetTags, S32, (), , //----------------------------------------------------------------------------- +DefineEngineMethod(AssetManager, getAssetLooseFiles, const char*, (const char* assetId), (""), + "Finds the specified asset Id and gets a list of its loose files.\n" + "@param assetId The selected asset Id.\n" + "@return A tab-delinated list of loose files associated to the assetId.\n") +{ + // Fetch asset Id. + const char* pAssetId = assetId; + + // Delete asset. + return object->getAssetLooseFiles(pAssetId); +} + +//----------------------------------------------------------------------------- + DefineEngineMethod(AssetManager, findAllAssets, S32, (const char* assetQuery, bool ignoreInternal, bool ignorePrivate), ("", true, true), "Performs an asset query searching for all assets optionally ignoring internal assets.\n" "@param assetQuery The asset query object that will be populated with the results.\n" diff --git a/Engine/source/console/propertyParsing.h b/Engine/source/console/propertyParsing.h index f782df2b4..69bdc09f6 100644 --- a/Engine/source/console/propertyParsing.h +++ b/Engine/source/console/propertyParsing.h @@ -162,6 +162,69 @@ namespace PropertyInfo bool hex_print(String & string, const S8 & hex); bool default_print(String & result, SimObjectType * const & data); + + template + char* FormatPropertyBuffer(const void* dataPtr, char* buffer, U32 bufSize) + { + const T* values = reinterpret_cast(dataPtr); + char* ptr = buffer; + + for (size_t i = 0; i < count; ++i) + { + S32 written = 0; + + if constexpr (std::is_same_v || std::is_same_v) + written = dSprintf(ptr, bufSize - (ptr - buffer), "%d", values[i]); + else if constexpr (std::is_same_v || std::is_same_v) + written = dSprintf(ptr, bufSize - (ptr - buffer), "%g", values[i]); + else + AssertFatal(sizeof(T) == 0, "Unsupported type in FormatProperty"); + + ptr += written; + if (i < count - 1) + *ptr++ = ' '; + } + + return ptr; // return end of written string for chaining + } + + template + const char* FormatProperty(const void* dataPtr) + { + static const U32 bufSize = 256; + char* buffer = Con::getReturnBuffer(bufSize); + FormatPropertyBuffer(dataPtr, buffer, bufSize); + return buffer; + } + + template + inline bool ParseProperty(char* str, T(&out)[count]) + { + + size_t index = 0; + char* tok = dStrtok(str, " \t"); + + while (tok && index < count) + { + if constexpr (std::is_same_v || std::is_same_v) + { + out[index++] = mRound(dAtof(tok)); + } + else if constexpr (std::is_same_v || std::is_same_v) + { + out[index++] = dAtof(tok); + } + else + { + AssertFatal(sizeof(T) == 0, "Unsupported type in PropertyInfo::ParseProperty"); + } + + tok = dStrtok(nullptr, " \t"); + } + + return index == count; + } + } // Default Scan/print definition diff --git a/Engine/source/console/sim.cpp b/Engine/source/console/sim.cpp index 48e3b627f..439f85ea9 100644 --- a/Engine/source/console/sim.cpp +++ b/Engine/source/console/sim.cpp @@ -102,7 +102,15 @@ DefineEngineFunction( isObject, bool, (const char * objectName), ,"isObject(obje if (!String::compare(objectName, "0") || !String::compare(objectName, "")) return false; else - return (Sim::findObject(objectName) != NULL); + { + SimObject* obj= Sim::findObject(objectName); + if (obj) + { + if (!obj->isProperlyAdded() || obj->isRemoved()) + obj = NULL; + } + return obj != NULL; + } } ConsoleDocFragment _spawnObject1( diff --git a/Engine/source/console/simDatablock.cpp b/Engine/source/console/simDatablock.cpp index d3969a069..fc5070224 100644 --- a/Engine/source/console/simDatablock.cpp +++ b/Engine/source/console/simDatablock.cpp @@ -425,39 +425,42 @@ void SimDataBlock::write(Stream &stream, U32 tabStop, U32 flags) // MARK: ---- API ---- //----------------------------------------------------------------------------- - -DefineEngineMethod( SimDataBlock, reloadOnLocalClient, void, (),, - "Reload the datablock. This can only be used with a local client configuration." ) +void SimDataBlock::reloadOnLocalClient() { // Make sure we're running a local client. GameConnection* localClient = GameConnection::getLocalClientConnection(); - if( !localClient ) + if (!localClient) return; // Do an in-place pack/unpack/preload. - if( !object->preload( true, NetConnection::getErrorBuffer() ) ) + if (!preload(true, NetConnection::getErrorBuffer())) { - Con::errorf( NetConnection::getErrorBuffer() ); + Con::errorf(NetConnection::getErrorBuffer()); return; } - U8 buffer[ 16384 ]; - BitStream stream( buffer, 16384 ); + U8 buffer[16384]; + BitStream stream(buffer, 16384); - object->packData( &stream ); + packData(&stream); stream.setPosition(0); - object->unpackData( &stream ); + unpackData(&stream); - if( !object->preload( false, NetConnection::getErrorBuffer() ) ) + if (!preload(false, NetConnection::getErrorBuffer())) { - Con::errorf( NetConnection::getErrorBuffer() ); + Con::errorf(NetConnection::getErrorBuffer()); return; } // Trigger a post-apply so that change notifications respond. - object->inspectPostApply(); + inspectPostApply(); +} +DefineEngineMethod( SimDataBlock, reloadOnLocalClient, void, (),, + "Reload the datablock. This can only be used with a local client configuration." ) +{ + object->reloadOnLocalClient(); } //----------------------------------------------------------------------------- diff --git a/Engine/source/console/simDatablock.h b/Engine/source/console/simDatablock.h index 1b61822d7..2f5c8efcc 100644 --- a/Engine/source/console/simDatablock.h +++ b/Engine/source/console/simDatablock.h @@ -176,6 +176,8 @@ public: /// Used by the console system to automatically tell datablock classes apart /// from non-datablock classes. static const bool __smIsDatablock = true; + + void reloadOnLocalClient(); protected: struct SubstitutionStatement { diff --git a/Engine/source/console/simObject.cpp b/Engine/source/console/simObject.cpp index fdbc13d72..6039393ef 100644 --- a/Engine/source/console/simObject.cpp +++ b/Engine/source/console/simObject.cpp @@ -82,7 +82,7 @@ ImplementBitfieldType(GameTypeMasksType, { SceneObjectTypes::PathShapeObjectType, "$TypeMasks::PathShapeObjectType", "Path-following Objects.\n" }, { SceneObjectTypes::TurretObjectType, "$TypeMasks::TurretObjectType", "Turret Objects.\n" }, { SceneObjectTypes::N_A_31, "$TypeMasks::N_A_31", "unused 31st bit.\n" }, -{ SceneObjectTypes::N_A_32, "$TypeMasks::N_A_32", "unused 32nd bit.\n" }, +{ SceneObjectTypes::AIObjectType, "$TypeMasks::AIObjectType", "AIObjectType.\n" }, EndImplementBitfieldType; @@ -3296,6 +3296,9 @@ DefineEngineMethod( SimObject, getGroup, SimGroup*, (),, DefineEngineMethod( SimObject, delete, void, (),, "Delete and remove the object." ) { + if (!object->isProperlyAdded() || object->isRemoved()) + return; + object->deleteObject(); } diff --git a/Engine/source/forest/forestItem.h b/Engine/source/forest/forestItem.h index 42bf56a5f..64e6eb611 100644 --- a/Engine/source/forest/forestItem.h +++ b/Engine/source/forest/forestItem.h @@ -143,7 +143,10 @@ public: return theSignal; } - void onShapeChanged() {} + void onShapeChanged() + { + reloadOnLocalClient(); + } }; typedef Vector ForestItemDataVector; diff --git a/Engine/source/gui/editor/popupMenu.cpp b/Engine/source/gui/editor/popupMenu.cpp index 783453f02..1f9de53fb 100644 --- a/Engine/source/gui/editor/popupMenu.cpp +++ b/Engine/source/gui/editor/popupMenu.cpp @@ -230,7 +230,7 @@ void PopupMenu::enableItem(S32 pos, bool enable) void PopupMenu::checkItem(S32 pos, bool checked) { - if (mMenuItems.empty() || mMenuItems.size() < pos || pos < 0) + if (mMenuItems.empty() || mMenuItems.size() <= pos || pos < 0) return; if (checked && mMenuItems[pos].mCheckGroup != -1 && mRadioSelection) diff --git a/Engine/source/math/mathTypes.cpp b/Engine/source/math/mathTypes.cpp index ef7616340..18526267c 100644 --- a/Engine/source/math/mathTypes.cpp +++ b/Engine/source/math/mathTypes.cpp @@ -24,6 +24,7 @@ #include "console/consoleTypes.h" #include "console/console.h" #include "console/engineAPI.h" +#include "console/propertyParsing.h" #include "math/mPoint2.h" #include "math/mPoint3.h" #include "math/mMatrix.h" @@ -169,21 +170,27 @@ ImplementConsoleTypeCasters( TypePoint2I, Point2I ) ConsoleGetType( TypePoint2I ) { - Point2I *pt = (Point2I *) dptr; - static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf(returnBuffer, bufSize, "%d %d", pt->x, pt->y); - return returnBuffer; + const char* buff = PropertyInfo::FormatProperty(dptr); + return buff; } ConsoleSetType( TypePoint2I ) { - if(argc == 1) - dSscanf(argv[0], "%d %d", &((Point2I *) dptr)->x, &((Point2I *) dptr)->y); - else if(argc == 2) - *((Point2I *) dptr) = Point2I(dAtoi(argv[0]), dAtoi(argv[1])); - else - Con::printf("Point2I must be set as { x, y } or \"x y\""); + if (argc >= 1) + { + S32 parsed[2]; + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + + dStrncpy(buffer, *argv, sizeof(buffer)); + + if (PropertyInfo::ParseProperty(buffer, parsed)) { + *((Point2I*)dptr) = Point2I(parsed[0], parsed[1]); + return; + } + } + + Con::warnf("Point2I must be set as { x, y } or \"x y\""); } //----------------------------------------------------------------------------- @@ -194,21 +201,27 @@ ImplementConsoleTypeCasters( TypePoint2F, Point2F ) ConsoleGetType( TypePoint2F ) { - Point2F *pt = (Point2F *) dptr; - static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf(returnBuffer, bufSize, "%g %g", pt->x, pt->y); - return returnBuffer; + const char* buff = PropertyInfo::FormatProperty(dptr); + return buff; } ConsoleSetType( TypePoint2F ) { - if(argc == 1) - dSscanf(argv[0], "%g %g", &((Point2F *) dptr)->x, &((Point2F *) dptr)->y); - else if(argc == 2) - *((Point2F *) dptr) = Point2F(dAtof(argv[0]), dAtof(argv[1])); - else - Con::printf("Point2F must be set as { x, y } or \"x y\""); + if (argc >= 1) + { + F32 parsed[2]; + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + + dStrncpy(buffer, *argv, sizeof(buffer)); + + if (PropertyInfo::ParseProperty(buffer, parsed)) { + *((Point2F*)dptr) = Point2F(parsed[0], parsed[1]); + return; + } + } + + Con::warnf("Point2F must be set as { x, y } or \"x y\""); } //----------------------------------------------------------------------------- @@ -219,21 +232,27 @@ ImplementConsoleTypeCasters(TypePoint3I, Point3I) ConsoleGetType( TypePoint3I ) { - Point3I *pt = (Point3I *) dptr; - static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf(returnBuffer, bufSize, "%d %d %d", pt->x, pt->y, pt->z); - return returnBuffer; + const char* buff = PropertyInfo::FormatProperty(dptr); + return buff; } ConsoleSetType( TypePoint3I ) { - if(argc == 1) - dSscanf(argv[0], "%d %d %d", &((Point3I *) dptr)->x, &((Point3I *) dptr)->y, &((Point3I *) dptr)->z); - else if(argc == 3) - *((Point3I *) dptr) = Point3I(dAtoi(argv[0]), dAtoi(argv[1]), dAtoi(argv[2])); - else - Con::printf("Point3I must be set as { x, y, z } or \"x y z\""); + if (argc >= 1) + { + S32 parsed[3]; + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + + dStrncpy(buffer, *argv, sizeof(buffer)); + + if (PropertyInfo::ParseProperty(buffer, parsed)) { + *((Point3I*)dptr) = Point3I(parsed[0], parsed[1], parsed[2]); + return; + } + } + + Con::warnf("Point3I must be set as { x, y, z } or \"x y z\""); } //----------------------------------------------------------------------------- @@ -244,21 +263,27 @@ ImplementConsoleTypeCasters(TypePoint3F, Point3F) ConsoleGetType( TypePoint3F ) { - Point3F *pt = (Point3F *) dptr; - static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf(returnBuffer, bufSize, "%g %g %g", pt->x, pt->y, pt->z); - return returnBuffer; + const char* buff = PropertyInfo::FormatProperty(dptr); + return buff; } ConsoleSetType( TypePoint3F ) { - if(argc == 1) - dSscanf(argv[0], "%g %g %g", &((Point3F *) dptr)->x, &((Point3F *) dptr)->y, &((Point3F *) dptr)->z); - else if(argc == 3) - *((Point3F *) dptr) = Point3F(dAtof(argv[0]), dAtof(argv[1]), dAtof(argv[2])); - else - Con::printf("Point3F must be set as { x, y, z } or \"x y z\""); + if (argc >= 1) + { + F32 parsed[3]; + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + + dStrncpy(buffer, *argv, sizeof(buffer)); + + if (PropertyInfo::ParseProperty(buffer, parsed)) { + *((Point3F*)dptr) = Point3F(parsed[0], parsed[1], parsed[2]); + return; + } + } + + Con::warnf("Point3F must be set as { x, y, z } or \"x y z\""); } //----------------------------------------------------------------------------- @@ -269,21 +294,27 @@ ImplementConsoleTypeCasters( TypePoint4F, Point4F ) ConsoleGetType( TypePoint4F ) { - Point4F *pt = (Point4F *) dptr; - static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf(returnBuffer, bufSize, "%g %g %g %g", pt->x, pt->y, pt->z, pt->w); - return returnBuffer; + const char* buff = PropertyInfo::FormatProperty(dptr); + return buff; } ConsoleSetType( TypePoint4F ) { - if(argc == 1) - dSscanf(argv[0], "%g %g %g %g", &((Point4F *) dptr)->x, &((Point4F *) dptr)->y, &((Point4F *) dptr)->z, &((Point4F *) dptr)->w); - else if(argc == 4) - *((Point4F *) dptr) = Point4F(dAtof(argv[0]), dAtof(argv[1]), dAtof(argv[2]), dAtof(argv[3])); - else - Con::printf("Point4F must be set as { x, y, z, w } or \"x y z w\""); + if (argc >= 1) + { + F32 parsed[4]; + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + + dStrncpy(buffer, *argv, sizeof(buffer)); + + if (PropertyInfo::ParseProperty(buffer, parsed)) { + *((Point4F*)dptr) = Point4F(parsed[0], parsed[1], parsed[2], parsed[3]); + return; + } + } + + Con::warnf("Point4F must be set as { x, y, z, w } or \"x y z w\""); } //----------------------------------------------------------------------------- @@ -294,23 +325,27 @@ ImplementConsoleTypeCasters( TypeRectI, RectI ) ConsoleGetType( TypeRectI ) { - RectI *rect = (RectI *) dptr; - static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf(returnBuffer, bufSize, "%d %d %d %d", rect->point.x, rect->point.y, - rect->extent.x, rect->extent.y); - return returnBuffer; + const char* buff = PropertyInfo::FormatProperty(dptr); + return buff; } ConsoleSetType( TypeRectI ) { - if(argc == 1) - dSscanf(argv[0], "%d %d %d %d", &((RectI *) dptr)->point.x, &((RectI *) dptr)->point.y, - &((RectI *) dptr)->extent.x, &((RectI *) dptr)->extent.y); - else if(argc == 4) - *((RectI *) dptr) = RectI(dAtoi(argv[0]), dAtoi(argv[1]), dAtoi(argv[2]), dAtoi(argv[3])); - else - Con::printf("RectI must be set as { x, y, w, h } or \"x y w h\""); + if (argc >= 1) + { + S32 parsed[4]; + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + + dStrncpy(buffer, *argv, sizeof(buffer)); + + if (PropertyInfo::ParseProperty(buffer, parsed)) { + *((RectI*)dptr) = RectI(parsed[0], parsed[1], parsed[2], parsed[3]); + return; + } + } + + Con::warnf("RectI must be set as { x, y, w, h } or \"x y w h\""); } //----------------------------------------------------------------------------- @@ -321,23 +356,27 @@ ImplementConsoleTypeCasters( TypeRectF, RectF ) ConsoleGetType( TypeRectF ) { - RectF *rect = (RectF *) dptr; - static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf(returnBuffer, bufSize, "%g %g %g %g", rect->point.x, rect->point.y, - rect->extent.x, rect->extent.y); - return returnBuffer; + const char* buff = PropertyInfo::FormatProperty(dptr); + return buff; } ConsoleSetType( TypeRectF ) { - if(argc == 1) - dSscanf(argv[0], "%g %g %g %g", &((RectF *) dptr)->point.x, &((RectF *) dptr)->point.y, - &((RectF *) dptr)->extent.x, &((RectF *) dptr)->extent.y); - else if(argc == 4) - *((RectF *) dptr) = RectF(dAtof(argv[0]), dAtof(argv[1]), dAtof(argv[2]), dAtof(argv[3])); - else - Con::printf("RectF must be set as { x, y, w, h } or \"x y w h\""); + if (argc >= 1) + { + F32 parsed[4]; + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + + dStrncpy(buffer, *argv, sizeof(buffer)); + + if (PropertyInfo::ParseProperty(buffer, parsed)) { + *((RectF*)dptr) = RectF(parsed[0], parsed[1], parsed[2], parsed[3]); + return; + } + } + + Con::warnf("RectF must be set as { x, y, w, h } or \"x y w h\""); } //----------------------------------------------------------------------------- @@ -351,36 +390,44 @@ ImplementConsoleTypeCasters( TypeMatrixF, MatrixF ) ConsoleGetType( TypeMatrixF ) { - MatrixF* mat = ( MatrixF* ) dptr; + MatrixF* mat = (MatrixF*)dptr; Point3F col0, col1, col2; mat->getColumn(0, &col0); mat->getColumn(1, &col1); mat->getColumn(2, &col2); static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf(returnBuffer,bufSize,"%g %g %g %g %g %g %g %g %g", - col0.x, col0.y, col0.z, col1.x, col1.y, col1.z, col2.x, col2.y, col2.z); - return returnBuffer; + char* buffer = Con::getReturnBuffer(bufSize); + + PropertyInfo::FormatPropertyBuffer(col0, buffer, bufSize); + *buffer++ = ' '; + PropertyInfo::FormatPropertyBuffer(col1, buffer, bufSize); + *buffer++ = ' '; + PropertyInfo::FormatPropertyBuffer(col2, buffer, bufSize); + + return buffer; } ConsoleSetType( TypeMatrixF ) { - if( argc != 1 ) + if (argc == 1) { - Con::errorf( "MatrixF must be set as \"c0x c0y c0z c1x c1y c1z c2x c2y c2z\"" ); - return; - } - - Point3F col0, col1, col2; - dSscanf( argv[ 0 ], "%g %g %g %g %g %g %g %g %g", - &col0.x, &col0.y, &col0.z, &col1.x, &col1.y, &col1.z, &col2.x, &col2.y, &col2.z ); + F32 parsed[9]; - MatrixF* mat = ( MatrixF* ) dptr; - - mat->setColumn( 0, col0 ); - mat->setColumn( 1, col1 ); - mat->setColumn( 2, col2 ); + char* buffer = new char[dStrlen(argv[0])]; + dStrcpy(buffer, argv[0], sizeof(buffer)); + + if (PropertyInfo::ParseProperty(buffer, parsed)) { + MatrixF* mat = (MatrixF*)dptr; + + mat->setColumn(0, Point3F(parsed[0], parsed[1], parsed[2])); + mat->setColumn(1, Point3F(parsed[3], parsed[4], parsed[5])); + mat->setColumn(2, Point3F(parsed[6], parsed[7], parsed[8])); + return; + } + } + + Con::warnf("MatrixF must be set as \"c0x c0y c0z c1x c1y c1z c2x c2y c2z\""); } //----------------------------------------------------------------------------- @@ -390,32 +437,40 @@ ConsoleMappedType(MatrixPosition, TypeMatrixPosition, Point3F, MatrixF, "") ConsoleGetType( TypeMatrixPosition ) { - F32 *col = (F32 *) dptr + 3; + F32* col = (F32*)dptr + 3; static const U32 bufSize = 256; char* returnBuffer = Con::getReturnBuffer(bufSize); - if(col[12] == 1.f) - dSprintf(returnBuffer, bufSize, "%g %g %g", col[0], col[4], col[8]); + Point4F pos(col[0], col[4], col[8], col[12]); + + if (col[12] == 1.0f) + PropertyInfo::FormatPropertyBuffer(&pos, returnBuffer, bufSize); else - dSprintf(returnBuffer, bufSize, "%g %g %g %g", col[0], col[4], col[8], col[12]); + PropertyInfo::FormatPropertyBuffer(&pos, returnBuffer, bufSize); + return returnBuffer; } ConsoleSetType( TypeMatrixPosition ) { - F32 *col = ((F32 *) dptr) + 3; - if (argc == 1) + if (argc >= 1) { - col[0] = col[4] = col[8] = 0.f; - col[12] = 1.f; - dSscanf(argv[0], "%g %g %g %g", &col[0], &col[4], &col[8], &col[12]); + F32 parsed[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + dStrncpy(buffer, *argv, sizeof(buffer)); + // we dont want to hard fail based on the count. + // this will allow any number of properties to be set. + PropertyInfo::ParseProperty(buffer, parsed); + { + Point4F temp(parsed[0], parsed[1], parsed[2], parsed[3]); + MatrixF* mat = (MatrixF*)dptr; + mat->setColumn(3, temp); + return; + } } - else if (argc <= 4) - { - for (S32 i = 0; i < argc; i++) - col[i << 2] = dAtof(argv[i]); - } - else - Con::printf("Matrix position must be set as { x, y, z, w } or \"x y z w\""); + + Con::warnf("Matrix position must be set as { x, y, z, w } or \"x y z w\""); + } //----------------------------------------------------------------------------- @@ -425,42 +480,38 @@ ConsoleMappedType(MatrixRotation, TypeMatrixRotation, AngAxisF, MatrixF, "") ConsoleGetType( TypeMatrixRotation ) { - AngAxisF aa(*(MatrixF *) dptr); + AngAxisF aa(*(MatrixF*)dptr); aa.axis.normalize(); - static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf(returnBuffer,bufSize,"%g %g %g %g",aa.axis.x,aa.axis.y,aa.axis.z,mRadToDeg(aa.angle)); - return returnBuffer; + aa.angle = mRadToDeg(aa.angle); + const char* buff = PropertyInfo::FormatProperty(&aa); + return buff; } ConsoleSetType( TypeMatrixRotation ) { - // DMM: Note that this will ONLY SET the ULeft 3x3 submatrix. - // - AngAxisF aa(Point3F(0,0,0),0); - if (argc == 1) + if (argc >= 1) { - dSscanf(argv[0], "%g %g %g %g", &aa.axis.x, &aa.axis.y, &aa.axis.z, &aa.angle); - aa.angle = mDegToRad(aa.angle); - } - else if (argc == 4) - { - for (S32 i = 0; i < argc; i++) - ((F32*)&aa)[i] = dAtof(argv[i]); - aa.angle = mDegToRad(aa.angle); - } - else - Con::printf("Matrix rotation must be set as { x, y, z, angle } or \"x y z angle\""); + F32 parsed[4]; + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + dStrncpy(buffer, *argv, sizeof(buffer)); - // - MatrixF temp; - aa.setMatrix(&temp); + if (PropertyInfo::ParseProperty(buffer, parsed)) + { + AngAxisF aa(Point3F(parsed[0], parsed[1], parsed[2]), mDegToRad(parsed[3])); + MatrixF temp; + aa.setMatrix(&temp); - F32* pDst = *(MatrixF *)dptr; - const F32* pSrc = temp; - for (U32 i = 0; i < 3; i++) - for (U32 j = 0; j < 3; j++) - pDst[i*4 + j] = pSrc[i*4 + j]; + F32* pDst = *(MatrixF*)dptr; + const F32* pSrc = temp; + for (U32 i = 0; i < 3; i++) + for (U32 j = 0; j < 3; j++) + pDst[i * 4 + j] = pSrc[i * 4 + j]; + return; + } + } + + Con::warnf("Matrix rotation must be set as { x, y, z, angle } or \"x y z angle\""); } //----------------------------------------------------------------------------- @@ -472,30 +523,29 @@ ImplementConsoleTypeCasters( TypeAngAxisF, AngAxisF ) ConsoleGetType( TypeAngAxisF ) { AngAxisF* aa = ( AngAxisF* ) dptr; - static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf(returnBuffer,bufSize,"%g %g %g %g",aa->axis.x,aa->axis.y,aa->axis.z,mRadToDeg(aa->angle)); - return returnBuffer; + aa->angle = mRadToDeg(aa->angle); + const char* buff = PropertyInfo::FormatProperty(aa); + return buff; } ConsoleSetType( TypeAngAxisF ) { - // DMM: Note that this will ONLY SET the ULeft 3x3 submatrix. - // - AngAxisF* aa = ( AngAxisF* ) dptr; - if (argc == 1) + if (argc >= 1) { - dSscanf(argv[0], "%g %g %g %g", &aa->axis.x, &aa->axis.y, &aa->axis.z, &aa->angle); - aa->angle = mDegToRad(aa->angle); + F32 parsed[4]; + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + dStrncpy(buffer, *argv, sizeof(buffer)); + + if(PropertyInfo::ParseProperty(buffer, parsed)) + { + AngAxisF* aa = (AngAxisF*)dptr; + aa->set(Point3F(parsed[0], parsed[1], parsed[2]), mDegToRad(parsed[3])); + return; + } } - else if (argc == 4) - { - for (S32 i = 0; i < argc; i++) - ((F32*)&aa)[i] = dAtof(argv[i]); - aa->angle = mDegToRad(aa->angle); - } - else - Con::printf("AngAxisF must be set as { x, y, z, angle } or \"x y z angle\""); + + Con::warnf("AngAxisF must be set as { x, y, z, angle } or \"x y z angle\""); } @@ -510,38 +560,35 @@ ImplementConsoleTypeCasters( TypeTransformF, TransformF ) ConsoleGetType( TypeTransformF ) { - TransformF* aa = ( TransformF* ) dptr; - static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf( returnBuffer, bufSize, "%g %g %g %g %g %g %g", - aa->mPosition.x, aa->mPosition.y, aa->mPosition.z, - aa->mOrientation.axis.x, aa->mOrientation.axis.y, aa->mOrientation.axis.z, aa->mOrientation.angle ); - return returnBuffer; + const char* buff = PropertyInfo::FormatProperty(dptr); + return buff; } ConsoleSetType( TypeTransformF ) { - TransformF* aa = ( TransformF* ) dptr; - if( argc == 1 ) + if(argc >= 1) { - U32 count = dSscanf( argv[ 0 ], "%g %g %g %g %g %g %g", - &aa->mPosition.x, &aa->mPosition.y, &aa->mPosition.z, - &aa->mOrientation.axis.x, &aa->mOrientation.axis.y, &aa->mOrientation.axis.z, &aa->mOrientation.angle ); + F32 parsed[7]; + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + dStrncpy(buffer, *argv, sizeof(buffer)); - aa->mHasRotation = ( count == 7 ); + if (PropertyInfo::ParseProperty(buffer, parsed)) + { + TransformF* aa = (TransformF*)dptr; + aa->mPosition.x = parsed[0]; + aa->mPosition.y = parsed[1]; + aa->mPosition.z = parsed[2]; + aa->mOrientation.axis.x = parsed[3]; + aa->mOrientation.axis.y = parsed[4]; + aa->mOrientation.axis.z = parsed[5]; + aa->mOrientation.angle = parsed[6]; + aa->mHasRotation = true; + return; + } } - else if( argc == 7 ) - { - aa->mPosition.x = dAtof( argv[ 0 ] ); - aa->mPosition.y = dAtof( argv[ 1 ] ); - aa->mPosition.z = dAtof( argv[ 2 ] ); - aa->mOrientation.axis.x = dAtof( argv[ 3 ] ); - aa->mOrientation.axis.y = dAtof( argv[ 4 ] ); - aa->mOrientation.axis.z = dAtof( argv[ 5 ] ); - aa->mOrientation.angle = dAtof( argv[ 6 ] ); - } - else - Con::errorf( "TransformF must be set as { px, py, pz, x, y, z, angle } or \"px py pz x y z angle\""); + + Con::warnf("TransformF must be set as { px, py, pz, x, y, z, angle } or \"px py pz x y z angle\""); } @@ -554,32 +601,33 @@ ImplementConsoleTypeCasters( TypeBox3F, Box3F ) ConsoleGetType( TypeBox3F ) { - const Box3F* pBox = (const Box3F*)dptr; - - static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf(returnBuffer, bufSize, "%g %g %g %g %g %g", - pBox->minExtents.x, pBox->minExtents.y, pBox->minExtents.z, - pBox->maxExtents.x, pBox->maxExtents.y, pBox->maxExtents.z); - - return returnBuffer; + const char* buff = PropertyInfo::FormatProperty(dptr); + return buff; } ConsoleSetType( TypeBox3F ) { - Box3F* pDst = (Box3F*)dptr; + if (argc >= 1) + { + F32 parsed[6]; + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + dStrncpy(buffer, *argv, sizeof(buffer)); - if (argc == 1) - { - U32 args = dSscanf(argv[0], "%g %g %g %g %g %g", - &pDst->minExtents.x, &pDst->minExtents.y, &pDst->minExtents.z, - &pDst->maxExtents.x, &pDst->maxExtents.y, &pDst->maxExtents.z); - AssertWarn(args == 6, "Warning, box probably not read properly"); - } - else - { - Con::printf("Box3F must be set as \"xMin yMin zMin xMax yMax zMax\""); + if (PropertyInfo::ParseProperty(buffer, parsed)) + { + Box3F* pDst = (Box3F*)dptr; + pDst->minExtents.x = parsed[0]; + pDst->minExtents.y = parsed[1]; + pDst->minExtents.z = parsed[2]; + pDst->maxExtents.x = parsed[3]; + pDst->maxExtents.y = parsed[4]; + pDst->maxExtents.z = parsed[5]; + return; + } } + + Con::warnf("Box3F must be set as \"xMin yMin zMin xMax yMax zMax\""); } @@ -591,31 +639,39 @@ ImplementConsoleTypeCasters( TypeEaseF, EaseF ) ConsoleGetType( TypeEaseF ) { - const EaseF* pEase = (const EaseF*)dptr; - static const U32 bufSize = 256; - char* returnBuffer = Con::getReturnBuffer(bufSize); - dSprintf(returnBuffer, bufSize, "%d %d %g %g", - pEase->mDir, pEase->mType, pEase->mParam[0], pEase->mParam[1]); + char* buffer = Con::getReturnBuffer(bufSize); - return returnBuffer; + EaseF* pEase = (EaseF*)dptr; + PropertyInfo::FormatPropertyBuffer(pEase + 0, buffer, bufSize); + *buffer++ = ' '; + PropertyInfo::FormatPropertyBuffer(pEase + 2, buffer, bufSize); + + return buffer; } ConsoleSetType( TypeEaseF ) { - EaseF* pDst = (EaseF*)dptr; + if (argc >= 1) + { + F32 parsed[4]; + parsed[2] = -1.0f; + parsed[3] = -1.0f; - // defaults... - pDst->mParam[0] = -1.0f; - pDst->mParam[1] = -1.0f; - if (argc == 1) { - U32 args = dSscanf(argv[0], "%d %d %f %f", // the two params are optional and assumed -1 if not present... - &pDst->mDir, &pDst->mType, &pDst->mParam[0],&pDst->mParam[1]); - if( args < 2 ) - Con::warnf( "Warning, EaseF probably not read properly" ); - } else { - Con::printf("EaseF must be set as \"dir type [param0 param1]\""); + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + + dStrncpy(buffer, *argv, sizeof(buffer)); + + // same as matrix do not hard fail based on count! + PropertyInfo::ParseProperty(buffer, parsed); + { + ((EaseF*)dptr)->set(mRound(parsed[0]), mRound(parsed[1]), parsed[2], parsed[3]); + return; + } } + + Con::warnf("EaseF must be set as \"dir type [param0 param1]\""); } //----------------------------------------------------------------------------- @@ -633,12 +689,12 @@ ConsoleGetType(TypeRotationF) if (pt->mRotationType == RotationF::Euler) { EulerF out = pt->asEulerF(RotationF::Degrees); - dSprintf(returnBuffer, bufSize, "%g %g %g", out.x, out.y, out.z); + PropertyInfo::FormatPropertyBuffer(out, returnBuffer, bufSize); } else if (pt->mRotationType == RotationF::AxisAngle) { AngAxisF out = pt->asAxisAngle(RotationF::Degrees); - dSprintf(returnBuffer, bufSize, "%g %g %g %g", out.axis.x, out.axis.y, out.axis.z, out.angle); + PropertyInfo::FormatPropertyBuffer(&out, returnBuffer, bufSize); } return returnBuffer; @@ -646,34 +702,36 @@ ConsoleGetType(TypeRotationF) ConsoleSetType(TypeRotationF) { - if (argc == 1) + if (argc >= 1) { - U32 elements = StringUnit::getUnitCount(argv[0], " \t\n"); + // Combine argv into a single space-separated string if argc > 1 + char buffer[256] = { 0 }; + dStrncpy(buffer, *argv, sizeof(buffer)); + + U32 elements = StringUnit::getUnitCount(buffer, " \t\n"); if (elements == 3) { - EulerF in; - dSscanf(argv[0], "%g %g %g", &in.x, &in.y, &in.z); - ((RotationF *)dptr)->set(in, RotationF::Degrees); + F32 parsed[3]; + if(PropertyInfo::ParseProperty(buffer, parsed)) + { + EulerF in(parsed[0], parsed[1], parsed[2]); + ((RotationF*)dptr)->set(in, RotationF::Degrees); + return; + } } - else + else if (elements == 4) { - AngAxisF in; - dSscanf(argv[0], "%g %g %g %g", &in.axis.x, &in.axis.y, &in.axis.z, &in.angle); - ((RotationF *)dptr)->set(in, RotationF::Degrees); + F32 parsed[4]; + if (PropertyInfo::ParseProperty(buffer, parsed)) + { + AngAxisF in(Point3F(parsed[0], parsed[1], parsed[2]), parsed[3]); + ((RotationF*)dptr)->set(in, RotationF::Degrees); + return; + } } } - else if (argc == 3) - { - EulerF in(dAtof(argv[0]), dAtof(argv[1]), dAtof(argv[2])); - ((RotationF *)dptr)->set(in, RotationF::Degrees); - } - else if (argc == 4) - { - AngAxisF in(Point3F(dAtof(argv[0]), dAtof(argv[1]), dAtof(argv[2])), dAtof(argv[3])); - ((RotationF *)dptr)->set(in, RotationF::Degrees); - } - else - Con::printf("RotationF must be set as { x, y, z, w } or \"x y z w\""); + + Con::warnf("RotationF must be set as { x, y, z, w } or \"x y z w\""); } //----------------------------------------------------------------------------- diff --git a/Engine/source/navigation/guiNavEditorCtrl.cpp b/Engine/source/navigation/guiNavEditorCtrl.cpp index bf164bc4b..eae204447 100644 --- a/Engine/source/navigation/guiNavEditorCtrl.cpp +++ b/Engine/source/navigation/guiNavEditorCtrl.cpp @@ -37,6 +37,7 @@ #include "gui/buttons/guiButtonCtrl.h" #include "gui/worldEditor/undoActions.h" #include "T3D/gameBase/gameConnection.h" +#include "T3D/AI/AIController.h" IMPLEMENT_CONOBJECT(GuiNavEditorCtrl); @@ -225,8 +226,29 @@ void GuiNavEditorCtrl::spawnPlayer(const Point3F &pos) SimGroup* missionCleanup = dynamic_cast(cleanup); missionCleanup->addObject(obj); } - mPlayer = static_cast(obj); - Con::executef(this, "onPlayerSelected", Con::getIntArg(mPlayer->mLinkTypes.getFlags())); + mPlayer = obj; +#ifdef TORQUE_NAVIGATION_ENABLED + AIPlayer* asAIPlayer = dynamic_cast(obj); + if (asAIPlayer) //try direct + { + Con::executef(this, "onPlayerSelected", Con::getIntArg(asAIPlayer->mLinkTypes.getFlags())); + } + else + { + ShapeBase* sbo = dynamic_cast(obj); + if (sbo->getAIController()) + { + if (sbo->getAIController()->mControllerData) + Con::executef(this, "onPlayerSelected", Con::getIntArg(sbo->getAIController()->mControllerData->mLinkTypes.getFlags())); + } + else + { +#endif + Con::executef(this, "onPlayerSelected"); +#ifdef TORQUE_NAVIGATION_ENABLED + } + } +#endif } } @@ -383,16 +405,56 @@ void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event) // Select/move character else { - if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType, &ri)) + if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri)) { - if(dynamic_cast(ri.object)) + if(ri.object) { - mPlayer = dynamic_cast(ri.object); - Con::executef(this, "onPlayerSelected", Con::getIntArg(mPlayer->mLinkTypes.getFlags())); + mPlayer = ri.object; +#ifdef TORQUE_NAVIGATION_ENABLED + AIPlayer* asAIPlayer = dynamic_cast(mPlayer.getPointer()); + if (asAIPlayer) //try direct + { + Con::executef(this, "onPlayerSelected", Con::getIntArg(asAIPlayer->mLinkTypes.getFlags())); + } + else + { + ShapeBase* sbo = dynamic_cast(mPlayer.getPointer()); + if (sbo->getAIController()) + { + if (sbo->getAIController()->mControllerData) + Con::executef(this, "onPlayerSelected", Con::getIntArg(sbo->getAIController()->mControllerData->mLinkTypes.getFlags())); + } + else + { +#endif + Con::executef(this, "onPlayerSelected"); + } +#ifdef TORQUE_NAVIGATION_ENABLED + } + } +#endif + } + else if (!mPlayer.isNull() && gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri)) + { + AIPlayer* asAIPlayer = dynamic_cast(mPlayer.getPointer()); + if (asAIPlayer) //try direct + { +#ifdef TORQUE_NAVIGATION_ENABLED + asAIPlayer->setPathDestination(ri.point); +#else + asAIPlayer->setMoveDestination(ri.point,false); +#endif + } + else + { + ShapeBase* sbo = dynamic_cast(mPlayer.getPointer()); + if (sbo->getAIController()) + { + if (sbo->getAIController()->mControllerData) + sbo->getAIController()->getNav()->setPathDestination(ri.point, true); + } } } - else if(!mPlayer.isNull() && gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri)) - mPlayer->setPathDestination(ri.point); } } } @@ -455,8 +517,8 @@ void GuiNavEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event) if(mMode == mTestMode) { - if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType, &ri)) - mCurPlayer = dynamic_cast(ri.object); + if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri)) + mCurPlayer = ri.object; else mCurPlayer = NULL; } diff --git a/Engine/source/navigation/guiNavEditorCtrl.h b/Engine/source/navigation/guiNavEditorCtrl.h index 6e0b34f5e..c5d2f1b5a 100644 --- a/Engine/source/navigation/guiNavEditorCtrl.h +++ b/Engine/source/navigation/guiNavEditorCtrl.h @@ -155,8 +155,8 @@ protected: /// @name Test mode /// @{ - SimObjectPtr mPlayer; - SimObjectPtr mCurPlayer; + SimObjectPtr mPlayer; + SimObjectPtr mCurPlayer; /// @} diff --git a/Templates/BaseGame/game/core/clientServer/scripts/client/connectionToServer.tscript b/Templates/BaseGame/game/core/clientServer/scripts/client/connectionToServer.tscript index cbd4b46cc..c9cebaa2b 100644 --- a/Templates/BaseGame/game/core/clientServer/scripts/client/connectionToServer.tscript +++ b/Templates/BaseGame/game/core/clientServer/scripts/client/connectionToServer.tscript @@ -111,8 +111,12 @@ function handleConnectionErrorMessage(%msgType, %msgString, %msgError) //----------------------------------------------------------------------------- // Disconnect //----------------------------------------------------------------------------- - function disconnect() +{ + callOnModules("disconnect"); +} + +function Core_ClientServer::disconnect(%this) { // We need to stop the client side simulation // else physics resources will not cleanup properly. @@ -158,3 +162,16 @@ function disconnectedCleanup() moduleExec("onDestroyClientConnection", "Game"); } + +function clientCmdsetMoveMap(%movemap) +{ + if (!isObject(%movemap)) return; + if(isObject(ServerConnection) && isObject(ServerConnection.curMoveMap)) + ServerConnection.curMoveMap.pop(); + + // clear movement + $mvForwardAction = 0; + $mvBackwardAction = 0; + %movemap.push(); + ServerConnection.curMoveMap = %movemap; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/clientServer/scripts/server/connectionToClient.tscript b/Templates/BaseGame/game/core/clientServer/scripts/server/connectionToClient.tscript index b804ac046..0e2a11e28 100644 --- a/Templates/BaseGame/game/core/clientServer/scripts/server/connectionToClient.tscript +++ b/Templates/BaseGame/game/core/clientServer/scripts/server/connectionToClient.tscript @@ -275,7 +275,9 @@ function GameConnection::onPostSpawn( %this ) if (%this.numModsNeedingLoaded) callOnObjectList("onPostSpawn", %modulesIdList, %this); else - %this.listener.onPostSpawnComplete(%this); + %this.listener.onPostSpawnComplete(%this); + if (isObject(%this.player.getDatablock().controlMap)) + commandToClient(%this, 'setMoveMap', %this.player.getDatablock().controlMap); } function GameConnectionListener::onPostSpawnComplete(%this, %client) diff --git a/Templates/BaseGame/game/core/gameObjects/datablocks/defaultDatablocks.tscript b/Templates/BaseGame/game/core/gameObjects/datablocks/defaultDatablocks.tscript index 1035f2d9a..512acd273 100644 --- a/Templates/BaseGame/game/core/gameObjects/datablocks/defaultDatablocks.tscript +++ b/Templates/BaseGame/game/core/gameObjects/datablocks/defaultDatablocks.tscript @@ -169,3 +169,20 @@ datablock LightAnimData( SpinLightAnim ) rotKeys[2] = "az"; rotSmooth[2] = true; }; + +datablock AIPlayerControllerData( aiPlayerControl ) +{ + moveTolerance = 0.25; followTolerance = 1.0; mAttackRadius = 2; +}; + +datablock AIWheeledVehicleControllerData( aiCarControl ) +{ + moveTolerance = 1.0; followTolerance = 2.0; mAttackRadius = 5.0; +}; + +datablock AIFlyingVehicleControllerData( aiPlaneControl ) +{ + moveTolerance = 2.0; followTolerance = 5.0; mAttackRadius = 10.0; + FlightFloor = 15; FlightCeiling = 150; +}; + diff --git a/Templates/BaseGame/game/core/utility/scripts/gameObjectManagement.tscript b/Templates/BaseGame/game/core/utility/scripts/gameObjectManagement.tscript index 64b75e331..51a4566fa 100644 --- a/Templates/BaseGame/game/core/utility/scripts/gameObjectManagement.tscript +++ b/Templates/BaseGame/game/core/utility/scripts/gameObjectManagement.tscript @@ -78,17 +78,15 @@ function spawnGameObject(%name, %addToScene) return 0; } -function GameBaseData::onNewDataBlock(%this, %obj) +function GameBaseData::onNewDataBlock(%this, %obj, %reload) { - if (%obj.firstDataCheck) + if (%reload) { if(%this.isMethod("onRemove")) %this.onRemove(%obj); if(%this.isMethod("onAdd")) %this.onAdd(%obj); } - else - %obj.firstDataCheck = true; } function saveGameObject(%name, %tamlPath, %scriptPath) diff --git a/Templates/BaseGame/game/data/DamageModel/DamageModel.module b/Templates/BaseGame/game/data/DamageModel/DamageModel.module new file mode 100644 index 000000000..0bce1ed70 --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/DamageModel.module @@ -0,0 +1,11 @@ + + + diff --git a/Templates/BaseGame/game/data/DamageModel/DamageModel.tscript b/Templates/BaseGame/game/data/DamageModel/DamageModel.tscript new file mode 100644 index 000000000..3268a5b9e --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/DamageModel.tscript @@ -0,0 +1,48 @@ +function DamageModel::onCreate(%this) +{ +} + +function DamageModel::onDestroy(%this) +{ +} + +//This is called when the server is initially set up by the game application +function DamageModel::initServer(%this) +{ +} + +//This is called when the server is created for an actual game/map to be played +function DamageModel::onCreateGameServer(%this) +{ + %this.registerDatablock("./scripts/managedData/managedParticleData"); + %this.registerDatablock("./scripts/managedData/managedParticleEmitterData"); + %this.queueExec("./scripts/server/utility"); + %this.queueExec("./scripts/server/radiusDamage"); + %this.queueExec("./scripts/server/projectile"); + %this.queueExec("./scripts/server/weapon"); + %this.queueExec("./scripts/server/shapeBase"); + %this.queueExec("./scripts/server/vehicle"); + %this.queueExec("./scripts/server/player"); +} + +//This is called when the server is shut down due to the game/map being exited +function DamageModel::onDestroyGameServer(%this) +{ +} + +//This is called when the client is initially set up by the game application +function DamageModel::initClient(%this) +{ + %this.queueExec("./guis/damageGuiOverlay.gui"); + %this.queueExec("./scripts/client/playGui"); +} + +//This is called when a client connects to a server +function DamageModel::onCreateClientConnection(%this) +{ +} + +//This is called when a client disconnects from a server +function DamageModel::onDestroyClientConnection(%this) +{ +} diff --git a/Templates/BaseGame/game/data/DamageModel/guis/damageGuiOverlay.asset.taml b/Templates/BaseGame/game/data/DamageModel/guis/damageGuiOverlay.asset.taml new file mode 100644 index 000000000..ab0935549 --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/guis/damageGuiOverlay.asset.taml @@ -0,0 +1 @@ + diff --git a/Templates/BaseGame/game/data/DamageModel/guis/damageGuiOverlay.gui b/Templates/BaseGame/game/data/DamageModel/guis/damageGuiOverlay.gui new file mode 100644 index 000000000..2c8ee1fe6 --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/guis/damageGuiOverlay.gui @@ -0,0 +1,285 @@ +//--- OBJECT WRITE BEGIN --- +$guiContent = new GuiContainer(DamageGuiOverlay) { + isContainer = "1"; + Profile = "GuiContentProfile"; + HorizSizing = "relative"; + VertSizing = "relative"; + position = "0 0"; + Extent = "1024 768"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + tooltipprofile = "GuiToolTipProfile"; + hovertime = "1000"; + canSaveDynamicFields = "1"; + Enabled = "1"; + helpTag = "0"; + noCursor = "1"; + new GuiShapeNameHud() { + fillColor = "0 0 0 0.25"; + frameColor = "0 1 0 1"; + textColor = "0 1 0 1"; + showFill = "0"; + showFrame = "0"; + verticalOffset = "0.2"; + distanceFade = "0.1"; + isContainer = "0"; + Profile = "GuiModelessDialogProfile"; + HorizSizing = "width"; + VertSizing = "height"; + position = "0 0"; + Extent = "1024 768"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + tooltipprofile = "GuiToolTipProfile"; + hovertime = "1000"; + canSaveDynamicFields = "0"; + }; + new GuiCrossHairHud(Reticle) { + damageFillColor = "0 1 0 1"; + damageFrameColor = "1 0.6 0 1"; + damageRect = "50 4"; + damageOffset = "0 10"; + bitmapAsset = "FPSEquipment:blank_image"; + wrap = "0"; + isContainer = "0"; + Profile = "GuiModelessDialogProfile"; + HorizSizing = "center"; + VertSizing = "center"; + position = "496 368"; + Extent = "32 32"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + tooltipprofile = "GuiToolTipProfile"; + hovertime = "1000"; + canSaveDynamicFields = "0"; + }; + new GuiCrossHairHud(ZoomReticle) { + damageFillColor = "0 1 0 1"; + damageFrameColor = "1 0.6 0 1"; + damageRect = "50 4"; + damageOffset = "0 10"; + bitmapAsset = "DamageModel:bino_image"; + wrap = "0"; + isContainer = "0"; + Profile = "GuiModelessDialogProfile"; + HorizSizing = "width"; + VertSizing = "height"; + position = "0 0"; + Extent = "1024 768"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "0"; + tooltipprofile = "GuiToolTipProfile"; + hovertime = "1000"; + canSaveDynamicFields = "0"; + }; + new GuiBitmapBorderCtrl(WeaponHUD) { + isContainer = "0"; + Profile = "ChatHudBorderProfile"; + HorizSizing = "right"; + VertSizing = "top"; + position = "78 693"; + Extent = "124 72"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + tooltipprofile = "GuiToolTipProfile"; + hovertime = "1000"; + canSaveDynamicFields = "0"; + + new GuiBitmapCtrl() { + bitmap = "UI:hudfill_image"; + wrap = "0"; + isContainer = "0"; + Profile = "GuiDefaultProfile"; + HorizSizing = "width"; + VertSizing = "height"; + position = "8 8"; + Extent = "108 56"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + tooltipprofile = "GuiToolTipProfile"; + hovertime = "1000"; + canSaveDynamicFields = "0"; + }; + new GuiBitmapCtrl(PreviewImage) { + bitmapAsset = "UI:hudfill_image"; + wrap = "0"; + isContainer = "0"; + Profile = "GuiDefaultProfile"; + HorizSizing = "width"; + VertSizing = "height"; + position = "8 8"; + Extent = "108 56"; + MinExtent = "8 2"; + canSave = "1"; + Visible = "1"; + tooltipprofile = "GuiToolTipProfile"; + hovertime = "1000"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(AmmoAmount) { + maxLength = "255"; + Margin = "0 0 0 0"; + Padding = "0 0 0 0"; + AnchorTop = "0"; + AnchorBottom = "0"; + AnchorLeft = "0"; + AnchorRight = "0"; + isContainer = "0"; + Profile = "HudTextItalicProfile"; + HorizSizing = "right"; + VertSizing = "top"; + position = "40 8"; + Extent = "120 16"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + tooltipprofile = "GuiToolTipProfile"; + hovertime = "1000"; + canSaveDynamicFields = "0"; + }; + }; + new GuiHealthTextHud() { + fillColor = "0 0 0 0.65"; + frameColor = "0 0 0 1"; + textColor = "1 1 1 1"; + warningColor = "1 0 0 1"; + showFill = "1"; + showFrame = "1"; + showTrueValue = "0"; + showEnergy = "0"; + warnThreshold = "25"; + pulseThreshold = "15"; + pulseRate = "750"; + position = "5 693"; + extent = "72 72"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "top"; + profile = "GuiBigTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiControl(DamageHUD) { + position = "384 256"; + extent = "256 256"; + minExtent = "8 2"; + horizSizing = "center"; + vertSizing = "center"; + profile = "GuiDefaultProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiBitmapCtrl(DamageFront) { + bitmapAsset = "DamageModel:damageFront_image"; + wrap = "0"; + position = "0 0"; + extent = "256 32"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiDefaultProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + internalName = "Damage[Front]"; + hidden = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiBitmapCtrl(DamageTop) { + bitmapAsset = "DamageModel:damageTop_image"; + wrap = "0"; + position = "0 0"; + extent = "256 32"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiDefaultProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + internalName = "Damage[Top]"; + hidden = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiBitmapCtrl(DamageBottom) { + bitmapAsset = "DamageModel:damageBottom_image"; + wrap = "0"; + position = "0 224"; + extent = "256 32"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiDefaultProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + internalName = "Damage[Bottom]"; + hidden = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiBitmapCtrl(DamageLeft) { + bitmapAsset = "DamageModel:damageLeft_image"; + wrap = "0"; + position = "0 0"; + extent = "32 256"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiDefaultProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + internalName = "Damage[Left]"; + hidden = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiBitmapCtrl(DamageRight) { + bitmapAsset = "DamageModel:damageRight_image"; + wrap = "0"; + position = "224 0"; + extent = "32 256"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiDefaultProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + internalName = "Damage[Right]"; + hidden = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; +}; +//--- OBJECT WRITE END --- diff --git a/Templates/BaseGame/game/data/DamageModel/images/crosshair.png b/Templates/BaseGame/game/data/DamageModel/images/crosshair.png new file mode 100644 index 000000000..06bcf5c6c Binary files /dev/null and b/Templates/BaseGame/game/data/DamageModel/images/crosshair.png differ diff --git a/Templates/BaseGame/game/data/DamageModel/images/crosshair_blue.png b/Templates/BaseGame/game/data/DamageModel/images/crosshair_blue.png new file mode 100644 index 000000000..d5b0485d7 Binary files /dev/null and b/Templates/BaseGame/game/data/DamageModel/images/crosshair_blue.png differ diff --git a/Templates/BaseGame/game/data/DamageModel/images/crosshair_blue_image.asset.taml b/Templates/BaseGame/game/data/DamageModel/images/crosshair_blue_image.asset.taml new file mode 100644 index 000000000..0962854e3 --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/images/crosshair_blue_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/DamageModel/images/damageBottom.png b/Templates/BaseGame/game/data/DamageModel/images/damageBottom.png new file mode 100644 index 000000000..883935ba8 Binary files /dev/null and b/Templates/BaseGame/game/data/DamageModel/images/damageBottom.png differ diff --git a/Templates/BaseGame/game/data/DamageModel/images/damageBottom_image.asset.taml b/Templates/BaseGame/game/data/DamageModel/images/damageBottom_image.asset.taml new file mode 100644 index 000000000..044292120 --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/images/damageBottom_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/DamageModel/images/damageFront.png b/Templates/BaseGame/game/data/DamageModel/images/damageFront.png new file mode 100644 index 000000000..ff759fc7c Binary files /dev/null and b/Templates/BaseGame/game/data/DamageModel/images/damageFront.png differ diff --git a/Templates/BaseGame/game/data/DamageModel/images/damageFront_image.asset.taml b/Templates/BaseGame/game/data/DamageModel/images/damageFront_image.asset.taml new file mode 100644 index 000000000..3b6d5836f --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/images/damageFront_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/DamageModel/images/damageLeft.png b/Templates/BaseGame/game/data/DamageModel/images/damageLeft.png new file mode 100644 index 000000000..9562db1dd Binary files /dev/null and b/Templates/BaseGame/game/data/DamageModel/images/damageLeft.png differ diff --git a/Templates/BaseGame/game/data/DamageModel/images/damageLeft_image.asset.taml b/Templates/BaseGame/game/data/DamageModel/images/damageLeft_image.asset.taml new file mode 100644 index 000000000..66e90be28 --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/images/damageLeft_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/DamageModel/images/damageRight.png b/Templates/BaseGame/game/data/DamageModel/images/damageRight.png new file mode 100644 index 000000000..3a9a626cc Binary files /dev/null and b/Templates/BaseGame/game/data/DamageModel/images/damageRight.png differ diff --git a/Templates/BaseGame/game/data/DamageModel/images/damageRight_image.asset.taml b/Templates/BaseGame/game/data/DamageModel/images/damageRight_image.asset.taml new file mode 100644 index 000000000..b9d0b382d --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/images/damageRight_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/DamageModel/images/damageTop.png b/Templates/BaseGame/game/data/DamageModel/images/damageTop.png new file mode 100644 index 000000000..ff759fc7c Binary files /dev/null and b/Templates/BaseGame/game/data/DamageModel/images/damageTop.png differ diff --git a/Templates/BaseGame/game/data/DamageModel/images/damageTop_image.asset.taml b/Templates/BaseGame/game/data/DamageModel/images/damageTop_image.asset.taml new file mode 100644 index 000000000..52eb13ffb --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/images/damageTop_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/DamageModel/scripts/client/playGui.tscript b/Templates/BaseGame/game/data/DamageModel/scripts/client/playGui.tscript new file mode 100644 index 000000000..77f533cce --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/scripts/client/playGui.tscript @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// PlayGui is the main TSControl through which the game is viewed. +// The PlayGui also contains the hud controls. +//----------------------------------------------------------------------------- + +function DamageModel::Playgui_onWake(%this) +{ + Canvas.pushDialog(DamageGuiOverlay); +} + +function DamageModel::Playgui_onSleep(%this) +{ + Canvas.popDialog(DamageGuiOverlay); +} + +function DamageModel::Playgui_clearHud( %this ) +{ + Canvas.popDialog(DamageGuiOverlay); +} + +function clientCmdSetDamageDirection(%direction) +{ + %ctrl = DamageHUD.findObjectByInternalName("damage[" @ %direction@"]"); + if (isObject(%ctrl)) + { + // Show the indicator, and schedule an event to hide it again + cancelAll(%ctrl); + %ctrl.setVisible(true); + %ctrl.schedule(1500, setVisible, false); + } +} \ No newline at end of file diff --git a/Templates/BaseGame/game/data/DamageModel/scripts/server/player.tscript b/Templates/BaseGame/game/data/DamageModel/scripts/server/player.tscript new file mode 100644 index 000000000..b874c9f5c --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/scripts/server/player.tscript @@ -0,0 +1,42 @@ +function PlayerData::damage(%this, %obj, %sourceObject, %position, %damage, %damageType) +{ + if (!isObject(%obj) || %obj.getDamageState() !$= "Enabled" || !%damage) + return; + + %rootObj = %obj; + if (%obj.healthFromMount) + %rootObj = findRootObject(%obj); + + %rootObj.applyDamage(%damage); + %this.onDamage(%rootObj, %damage); + + %this.setDamageDirection(%rootObj, %sourceObject, %position); + + // Deal with client callbacks here because we don't have this + // information in the onDamage or onDisable methods + %client = %rootObj.client; + %sourceClient = %sourceObject ? %sourceObject.client : 0; + + %location = "Body"; + if (isObject(%client)) + { + if (%rootObj.getDamageState() !$= "Enabled") + { + callGamemodeFunction("onDeath", %client, %sourceObject, %sourceClient, %damageType, %location); + } + } +} + +function PlayerData::onDamage(%this, %obj, %delta) +{ + Parent::onDamage(%this, %obj, %delta); + + // This method is invoked by the ShapeBase code whenever the + // object's damage level changes. + if (%delta > 0 && %obj.getDamageState() !$= "Destroyed") + { + // If the pain is excessive, let's hear about it. + if (%delta > 10) + %obj.playPain(); + } +} \ No newline at end of file diff --git a/Templates/BaseGame/game/data/DamageModel/scripts/server/projectile.tscript b/Templates/BaseGame/game/data/DamageModel/scripts/server/projectile.tscript new file mode 100644 index 000000000..1af454f61 --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/scripts/server/projectile.tscript @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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. +//----------------------------------------------------------------------------- + +// "Universal" script methods for projectile damage handling. You can easily +// override these support functions with an equivalent namespace method if your +// weapon needs a unique solution for applying damage. + +function ProjectileData::onCollision(%data, %proj, %col, %fade, %pos, %normal) +{ + //echo("ProjectileData::onCollision("@%data.getName()@", "@%proj@", "@%col.getClassName()@", "@%fade@", "@%pos@", "@%normal@")"); + + // Apply damage to the object all shape base objects + if (%data.directDamage > 0) + { + if (%col.getType() & ($TypeMasks::ShapeBaseObjectType)) + %col.damage(%proj, %pos, %data.directDamage, %data.damageType); + } +} + +function ProjectileData::onExplode(%data, %proj, %position, %mod) +{ + //echo("ProjectileData::onExplode("@%data.getName()@", "@%proj@", "@%position@", "@%mod@")"); + + // Damage objects within the projectiles damage radius + if (%data.damageRadius > 0) + radiusDamage(%proj, %position, %data.damageRadius, %data.radiusDamage, %data.damageType, %data.areaImpulse); +} diff --git a/Templates/BaseGame/game/data/DamageModel/scripts/server/radiusDamage.tscript b/Templates/BaseGame/game/data/DamageModel/scripts/server/radiusDamage.tscript new file mode 100644 index 000000000..91255f25c --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/scripts/server/radiusDamage.tscript @@ -0,0 +1,73 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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. +//----------------------------------------------------------------------------- + +// Support function which applies damage to objects within the radius of +// some effect, usually an explosion. This function will also optionally +// apply an impulse to each object. + +function radiusDamage(%sourceObject, %position, %radius, %damage, %damageType, %impulse) +{ + // Use the container system to iterate through all the objects + // within our explosion radius. We'll apply damage to all ShapeBase + // objects. + InitContainerRadiusSearch(%position, %radius, $TypeMasks::ShapeBaseObjectType | $TypeMasks::DynamicShapeObjectType); + + %halfRadius = %radius / 2; + while ((%targetObject = containerSearchNext()) != 0) + { + // Calculate how much exposure the current object has to + // the explosive force. The object types listed are objects + // that will block an explosion. If the object is totally blocked, + // then no damage is applied. + %coverage = calcExplosionCoverage(%position, %targetObject, + $TypeMasks::InteriorObjectType | + $TypeMasks::TerrainObjectType | + $TypeMasks::ForceFieldObjectType | + $TypeMasks::StaticShapeObjectType | + $TypeMasks::VehicleObjectType); + if (%coverage == 0) + continue; + + // Radius distance subtracts out the length of smallest bounding + // box axis to return an appriximate distance to the edge of the + // object's bounds, as opposed to the distance to it's center. + %dist = containerSearchCurrRadiusDist(); + + // Calculate a distance scale for the damage and the impulse. + // Full damage is applied to anything less than half the radius away, + // linear scale from there. + %distScale = (%dist < %halfRadius)? 1.0 : 1.0 - ((%dist - %halfRadius) / %halfRadius); + %distScale = mClamp(%distScale,0.0,1.0); + + // Apply the damage + %targetObject.damage(%sourceObject, %position, %damage * %coverage * %distScale, %damageType); + + // Apply the impulse + if (%impulse) + { + %impulseVec = VectorSub(%targetObject.getWorldBoxCenter(), %position); + %impulseVec = VectorNormalize(%impulseVec); + %impulseVec = VectorScale(%impulseVec, %impulse * %distScale); + %targetObject.applyImpulse(%position, %impulseVec); + } + } +} diff --git a/Templates/BaseGame/game/data/DamageModel/scripts/server/shapeBase.tscript b/Templates/BaseGame/game/data/DamageModel/scripts/server/shapeBase.tscript new file mode 100644 index 000000000..2a1b01fae --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/scripts/server/shapeBase.tscript @@ -0,0 +1,289 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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. +//----------------------------------------------------------------------------- + +// This file contains ShapeBase methods used by all the derived classes +$DeathDuration = 10000; +$CorpseTimeoutValue = 20000; +//----------------------------------------------------------------------------- +// ShapeBase object +//----------------------------------------------------------------------------- + +// A raycast helper function to keep from having to duplicate code everytime +// that a raycast is needed. +// %this = the object doing the cast, usually a player +// %range = range to search +// %mask = what to look for + +function ShapeBase::doRaycast(%this, %range, %mask) +{ + // get the eye vector and eye transform of the player + %eyeVec = %this.getEyeVector(); + %eyeTrans = %this.getEyeTransform(); + + // extract the position of the player's camera from the eye transform (first 3 words) + %eyePos = getWord(%eyeTrans, 0) SPC getWord(%eyeTrans, 1) SPC getWord(%eyeTrans, 2); + + // normalize the eye vector + %nEyeVec = VectorNormalize(%eyeVec); + + // scale (lengthen) the normalized eye vector according to the search range + %scEyeVec = VectorScale(%nEyeVec, %range); + + // add the scaled & normalized eye vector to the position of the camera + %eyeEnd = VectorAdd(%eyePos, %scEyeVec); + + // see if anything gets hit + %searchResult = containerRayCast(%eyePos, %eyeEnd, %mask, %this); + + return %searchResult; +} + +//----------------------------------------------------------------------------- + +function ShapeBase::damage(%this, %sourceObject, %position, %damage, %damageType) +{ + // All damage applied by one object to another should go through this method. + // This function is provided to allow objects some chance of overriding or + // processing damage values and types. As opposed to having weapons call + // ShapeBase::applyDamage directly. Damage is redirected to the datablock, + // this is standard procedure for many built in callbacks. + + if (isObject(%this)) + %this.getDataBlock().damage(%this, %sourceObject, %position, %damage, %damageType); +} + +//----------------------------------------------------------------------------- + +function ShapeBase::setDamageDt(%this, %damageAmount, %damageType) +{ + // This function is used to apply damage over time. The damage is applied + // at a fixed rate (50 ms). Damage could be applied over time using the + // built in ShapBase C++ repair functions (using a neg. repair), but this + // has the advantage of going through the normal script channels. + + if (%this.getState() !$= "Dead") + { + %this.damage(0, "0 0 0", %damageAmount, %damageType); + %this.damageSchedule = %this.schedule(50, "setDamageDt", %damageAmount, %damageType); + } + else + %this.damageSchedule = ""; +} + +function ShapeBase::clearDamageDt(%this) +{ + if (%this.damageSchedule !$= "") + { + cancel(%this.damageSchedule); + %this.damageSchedule = ""; + } +} + +function GameBase::damage(%this, %sourceObject, %position, %damage, %damageType) +{ + // All damage applied by one object to another should go through this method. + // This function is provided to allow objects some chance of overriding or + // processing damage values and types. As opposed to having weapons call + // ShapeBase::applyDamage directly. Damage is redirected to the datablock, + // this is standard procedure for many built in callbacks. + + %datablock = %this.getDataBlock(); + if ( isObject( %datablock ) ) + %datablock.damage(%this, %sourceObject, %position, %damage, %damageType); +} + +//----------------------------------------------------------------------------- +// ShapeBase datablock +//----------------------------------------------------------------------------- + +function GameBaseData::damage(%this, %obj, %source, %position, %amount, %damageType) +{ + // Ignore damage by default. This empty method is here to + // avoid console warnings. +} + +function ShapeBaseData::onAdd(%this, %obj) +{ + %obj.setDamageState("Enabled"); +} + +function ShapeBaseData::setDamageDirection(%this, %obj, %sourceObject, %damagePos) +{ + %client = (%obj.client) ? %obj.client : %obj.getControllingClient(); + if (!%client) return; + + if (%damagePos $= "" && isObject(%sourceObject)) + { + if (%sourceObject.isField(initialPosition)) + { + // Projectiles have this field set to the muzzle point of + // the firing weapon at the time the projectile was created. + // This gives a damage direction towards the firing object, + // turret, vehicle, etc. Bullets and weapon fired grenades + // are examples of projectiles. + %damagePos = %sourceObject.initialPosition; + } + else + { + // Other objects that cause damage, such as mines, use their own + // location as the damage position. This gives a damage direction + // towards the explosive origin rather than the person that lay the + // explosives. + %damagePos = %sourceObject.getPosition(); + } + } + + // Rotate damage vector into object space + %damageVec = VectorSub(%damagePos, %obj.getWorldBoxCenter()); + %damageVec = VectorNormalize(%damageVec); + %damageVec = MatrixMulVector(%client.getCameraObject().getInverseTransform(), %damageVec); + + // Determine largest component of damage vector to get direction + %vecComponents = -%damageVec.x SPC %damageVec.x SPC -%damageVec.y SPC %damageVec.y SPC -%damageVec.z SPC %damageVec.z; + %vecDirections = "Left" SPC "Right" SPC "Bottom" SPC "Front" SPC "Bottom" SPC "Top"; + + %max = -1; + for (%i = 0; %i < 6; %i++) + { + %value = getWord(%vecComponents, %i); + if (%value > %max) + { + %max = %value; + %damageDir = getWord(%vecDirections, %i); + } + } + commandToClient(%client, 'setDamageDirection', %damageDir); +} + + +function ShapeBaseData::onCollision(%this, %obj, %collObj, %vec, %len ) +{ + if (!isObject(%obj) || %obj.getDamageState() $= "Destroyed") + return; + + //echo(%this SPC %obj SPC %collObj SPC %vec SPC %len ); + %dmgPos = VectorSub(%obj.getPosition(), %vec); + %dmgAmt = %len/%this.minImpactSpeed * %this.collisionMul; + + %this.damage(%obj, %collObj, %dmgPos, %dmgAmt, "impact"); +} + +function ShapeBaseData::onImpact(%this, %obj, %collObj, %vec, %len ) +{ + if (!isObject(%obj) || %obj.getDamageState() $= "Destroyed") + return; + + //echo(%this SPC %obj SPC %collObj SPC %vec SPC %len ); + %dmgPos = VectorSub(%obj.getPosition(), %vec); + %dmgAmt = %len/%this.minImpactSpeed * %this.impactMul; + + %this.damage(%obj, %collObj, %dmgPos, %dmgAmt, "impact"); +} + +//---------------------------------------------------------------------------- + +function ShapeBaseData::damage(%this, %obj, %sourceObject, %position, %damage, %damageType) +{ + if (!isObject(%obj) || %obj.getDamageState() $= "Destroyed" || !%damage) + return; + + %rootObj = %obj; + if (%obj.healthFromMount) + %rootObj = findRootObject(%obj); + + %rootObj.applyDamage(%damage); + %this.onDamage(%rootObj, %damage); + + %this.setDamageDirection(%obj, %sourceObject, %position); + + // Deal with client callbacks here because we don't have this + // information in the onDamage or onDisable methods + %client = %rootObj.client; + %sourceClient = %sourceObject ? %sourceObject.client : 0; + + if (isObject(%client)) + { + if (%obj.getDamageState() $= "Destroyed") + { + callGamemodeFunction("onDeath", %client, %sourceObject, %sourceClient, %damageType, ""); + } + } +} + +function ShapeBaseData::onDamage(%this, %obj, %delta) +{ + // This method is invoked by the ShapeBase code whenever the + // object's damage level changes. + if (%delta > 0 && %obj.getDamageState() !$= "Destroyed") + { + // Apply a damage flash + %obj.setDamageFlash(1); + + //total raw damage allowed to be stored + if (%this.maxDamage> 1.0 && %obj.getDamageLevel() >= %this.maxDamage) + %obj.setDamageState("Destroyed"); + //damage before we are considered destroyed (can animate via "damage" thread) + else if (%this.destroyedLevel> 1.0 && %obj.getDamageLevel() >= %this.destroyedLevel) + %obj.setDamageState("Destroyed"); + //optional additional disabled level + else if (%this.disabledLevel> 1.0 && %obj.getDamageLevel() >= %this.disabledLevel) + %obj.setDamageState("Disabled"); + } +} + +function ShapeBaseData::onDisabled(%this, %obj, %state) +{ + // Release the weapon triggers + for (%slot = 0; %slot<4; %slot++) + { + if (%obj.getMountedImage(%slot)) + %obj.setImageTrigger(%slot, false); + } +} + +function ShapeBaseData::onDestroyed(%this, %obj, %state) +{ + // Release the weapon triggers + for (%slot = 0; %slot<4; %slot++) + { + if (%obj.getMountedImage(%slot)) + %obj.setImageTrigger(%slot, false); + } + + if (%obj.client) + { + %obj.client.player = 0; + %obj.client.schedule($DeathDuration, "spawnControlObject"); + } + // Schedule corpse removal. Just keeping the place clean. + %obj.schedule($CorpseTimeoutValue - 1000, "startFade", 1000, 0, true); + %obj.schedule($CorpseTimeoutValue, "delete"); + %obj.schedule($CorpseTimeoutValue,"blowUp"); +} + +function ShapeBaseData::onRemove(%this, %obj) +{ + if (isMethod(Parent, "onRemove")) + Parent::onRemove(%this, %obj); + + deleteMountchain(%obj); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/data/DamageModel/scripts/server/utility.tscript b/Templates/BaseGame/game/data/DamageModel/scripts/server/utility.tscript new file mode 100644 index 000000000..c74f8ee50 --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/scripts/server/utility.tscript @@ -0,0 +1,34 @@ +function findRootObject(%obj) +{ if (!isObject(%obj)) return -1; + %ret = %obj; + if (isObject(%obj.getObjectMount())) + %ret = findRootObject(%obj.getObjectMount()); + return %ret; +} + +function deleteMountchain(%obj) +{ + if (!isObject(%obj)) return; + %count = %obj.getMountedObjectCount(); + for (%i=%count; %i>=0; %i--) + { + if (isObject(%obj.getMountedObject(%i))) + deleteMountchain(%obj.getMountedObject(%i)); + } + if (%obj.isMounted()) + %obj.delete(); +} + + +function setMountChainDamage(%obj,%damagePercent) +{ + if (!isObject(%obj)) return; + %count = %obj.getMountedObjectCount(); + for (%i=0; %i<%count; %i++) + { + if (isObject(%obj.getMountedObject(%i))) + setMountChainDamage(%obj.getMountedObject(%i),%damagePercent); + } + + %obj.setDamageLevel(%obj.getMaxDamage()*%damagePercent); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/data/DamageModel/scripts/server/vehicle.tscript b/Templates/BaseGame/game/data/DamageModel/scripts/server/vehicle.tscript new file mode 100644 index 000000000..fec8c9ecd --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/scripts/server/vehicle.tscript @@ -0,0 +1,134 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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. +//----------------------------------------------------------------------------- + +// Parenting is in place for WheeledVehicleData to VehicleData. This should +// make it easier for people to simply drop in new (generic) vehicles. All that +// the user needs to create is a set of datablocks for the new wheeled vehicle +// to use. This means that no (or little) scripting should be necessary. + +// Special, or unique vehicles however will still require some scripting. They +// may need to override the onAdd() function in order to mount weapons, +// differing tires/springs, etc., almost everything else is taken care of in the +// WheeledVehicleData and VehicleData methods. This helps us by not having to +// duplicate the same code for every new vehicle. + +// In theory this would work for HoverVehicles and FlyingVehicles also, but +// hasn't been tested or fully implemented for those classes -- yet. + +function VehicleData::onAdd(%this, %obj) +{ + %obj.setRechargeRate(%this.rechargeRate); + %obj.setEnergyLevel(%this.MaxEnergy); + %obj.setRepairRate(0); + + if (%obj.mountable || %obj.mountable $= "") + %this.isMountable(%obj, true); + else + %this.isMountable(%obj, false); + + if (%this.nameTag !$= "") + %obj.setShapeName(%this.nameTag); +} + +function VehicleData::onDestroyed(%this, %obj, %state) +{ + //echo("\c4VehicleData::onRemove("@ %this.getName() @", "@ %obj.getClassName() @")"); + // if there are passengers/driver, kick them out + if (!%this.killPassengers) + { + for(%i = 0; %i < %obj.getMountedObjectCount(); %i++) + { + if (%obj.getMountedObject(%i)) + { + %passenger = %obj.getMountedObject(%i); + if (%passenger.isMemberOfClass("Player")) + %passenger.getDataBlock().doDismount(%passenger, true); + } + } + } + Parent::onDestroyed(%this, %obj, %state); +} + +// ---------------------------------------------------------------------------- +// Vehicle player mounting and dismounting +// ---------------------------------------------------------------------------- + +function VehicleData::isMountable(%this, %obj, %val) +{ + %obj.mountable = %val; +} + +function VehicleData::mountPlayer(%this, %vehicle, %player) +{ + //echo("\c4VehicleData::mountPlayer("@ %this.getName() @", "@ %vehicle @", "@ %player.client.nameBase @")"); + + if (isObject(%vehicle) && %vehicle.getDamageState() !$= "Destroyed") + { + %player.startFade(1000, 0, true); + %this.schedule(1000, "setMountVehicle", %vehicle, %player); + %player.schedule(1500, "startFade", 1000, 0, false); + } +} + +function VehicleData::setMountVehicle(%this, %vehicle, %player) +{ + //echo("\c4VehicleData::setMountVehicle("@ %this.getName() @", "@ %vehicle @", "@ %player.client.nameBase @")"); + + if (isObject(%vehicle) && %vehicle.getDamageState() !$= "Destroyed") + { + %node = %this.findEmptySeat(%vehicle, %player); + if (%node >= 0) + { + //echo("\c4Mount Node: "@ %node); + %vehicle.mountObject(%player, %node); + //%player.playAudio(0, MountVehicleSound); + %player.mVehicle = %vehicle; + } + } +} + +function VehicleData::findEmptySeat(%this, %vehicle, %player) +{ + //echo("\c4This vehicle has "@ %this.numMountPoints @" mount points."); + + for (%i = 0; %i < %this.numMountPoints; %i++) + { + %node = %vehicle.getMountNodeObject(%i); + if (%node == 0) + return %i; + } + return -1; +} + +function VehicleData::switchSeats(%this, %vehicle, %player) +{ + for (%i = 0; %i < %this.numMountPoints; %i++) + { + %node = %vehicle.getMountNodeObject(%i); + if (%node == %player || %node > 0) + continue; + + if (%node == 0) + return %i; + } + return -1; +} diff --git a/Templates/BaseGame/game/data/DamageModel/scripts/server/weapon.tscript b/Templates/BaseGame/game/data/DamageModel/scripts/server/weapon.tscript new file mode 100644 index 000000000..8cb476614 --- /dev/null +++ b/Templates/BaseGame/game/data/DamageModel/scripts/server/weapon.tscript @@ -0,0 +1,645 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// 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. +//----------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +// This file contains Weapon and Ammo Class/"namespace" helper methods as well +// as hooks into the inventory system. These functions are not attached to a +// specific C++ class or datablock, but define a set of methods which are part +// of dynamic namespaces "class". The Items include these namespaces into their +// scope using the ItemData and ItemImageData "className" variable. +// ---------------------------------------------------------------------------- + +// All ShapeBase images are mounted into one of 8 slots on a shape. This weapon +// system assumes all primary weapons are mounted into this specified slot: +$WeaponSlot = 0; + +//----------------------------------------------------------------------------- +// Weapon Class +//----------------------------------------------------------------------------- + +function Weapon::onUse(%data, %obj) +{ + // Default behavior for all weapons is to mount it into the object's weapon + // slot, which is currently assumed to be slot 0 + if (%obj.getMountedImage($WeaponSlot) != %data.image.getId()) + { + serverPlay3D(WeaponUseSound, %obj.getTransform()); + + %obj.mountImage(%data.image, $WeaponSlot); + if (%obj.client) + { + if (%data.description !$= "") + messageClient(%obj.client, 'MsgWeaponUsed', '\c0%1 selected.', %data.description); + else + messageClient(%obj.client, 'MsgWeaponUsed', '\c0Weapon selected'); + } + + // If this is a Player class object then allow the weapon to modify allowed poses + if (%obj.isInNamespaceHierarchy("Player")) + { + // Start by allowing everything + %obj.allowAllPoses(); + + // Now see what isn't allowed by the weapon + + %image = %data.image; + + if (%image.jumpingDisallowed) + %obj.allowJumping(false); + + if (%image.jetJumpingDisallowed) + %obj.allowJetJumping(false); + + if (%image.sprintDisallowed) + %obj.allowSprinting(false); + + if (%image.crouchDisallowed) + %obj.allowCrouching(false); + + if (%image.proneDisallowed) + %obj.allowProne(false); + + if (%image.swimmingDisallowed) + %obj.allowSwimming(false); + } + } +} + +function Weapon::onPickup(%this, %obj, %shape, %amount) +{ + // The parent Item method performs the actual pickup. + // For player's we automatically use the weapon if the + // player does not already have one in hand. + if (Parent::onPickup(%this, %obj, %shape, %amount)) + { + serverPlay3D(WeaponPickupSound, %shape.getTransform()); + if (%shape.getClassName() $= "Player" && %shape.getMountedImage($WeaponSlot) == 0) + %shape.use(%this); + } +} + +function Weapon::onInventory(%this, %obj, %amount) +{ + // Weapon inventory has changed, make sure there are no weapons + // of this type mounted if there are none left in inventory. + if (!%amount && (%slot = %obj.getMountSlot(%this.image)) != -1) + %obj.unmountImage(%slot); +} + +//----------------------------------------------------------------------------- +// Weapon Image Class +//----------------------------------------------------------------------------- + +function WeaponImage::onMount(%this, %obj, %slot) +{ + // Images assume a false ammo state on load. We need to + // set the state according to the current inventory. + if(%this.isField("clip")) + { + // Use the clip system for this weapon. Check if the player already has + // some ammo in a clip. + if (%obj.getInventory(%this.ammo)) + { + %obj.setImageAmmo(%slot, true); + %currentAmmo = %obj.getInventory(%this.ammo); + } + else if(%obj.getInventory(%this.clip) > 0) + { + // Fill the weapon up from the first clip + %obj.setInventory(%this.ammo, %this.ammo.maxInventory); + %obj.setImageAmmo(%slot, true); + + // Add any spare ammo that may be "in the player's pocket" + %currentAmmo = %this.ammo.maxInventory; + %amountInClips += %obj.getFieldValue( "remaining" @ %this.ammo.getName()); + } + else + { + %currentAmmo = 0 + %obj.getFieldValue( "remaining" @ %this.ammo.getName()); + } + + %amountInClips = %obj.getInventory(%this.clip); + %amountInClips *= %this.ammo.maxInventory; + + if (%obj.client !$= "" && !%obj.isAiControlled) + %obj.client.RefreshWeaponHud(%currentAmmo, %this.item.previewImage, %this.item.reticle, %this.item.zoomReticle, %amountInClips); + } + else if(%this.ammo !$= "") + { + // Use the ammo pool system for this weapon + if (%obj.getInventory(%this.ammo)) + { + %obj.setImageAmmo(%slot, true); + %currentAmmo = %obj.getInventory(%this.ammo); + } + else + %currentAmmo = 0; + + if (%obj.client !$= "" && !%obj.isAiControlled) + %obj.client.RefreshWeaponHud( 1, %this.item.previewImage, %this.item.reticle, %this.item.zoomReticle, %currentAmmo ); + } +} + +function WeaponImage::onUnmount(%this, %obj, %slot) +{ + if (%obj.client !$= "" && !%obj.isAiControlled) + %obj.client.RefreshWeaponHud(0, "", ""); +} + +// ---------------------------------------------------------------------------- +// A "generic" weaponimage onFire handler for most weapons. Can be overridden +// with an appropriate namespace method for any weapon that requires a custom +// firing solution. + +// projectileSpread is a dynamic property declared in the weaponImage datablock +// for those weapons in which bullet skew is desired. Must be greater than 0, +// otherwise the projectile goes straight ahead as normal. lower values give +// greater accuracy, higher values increase the spread pattern. +// ---------------------------------------------------------------------------- + +function WeaponImage::onFire(%this, %obj, %slot) +{ + //echo("\c4WeaponImage::onFire( "@%this.getName()@", "@%obj.client.nameBase@", "@%slot@" )"); + + // Make sure we have valid data + if (!isObject(%this.projectile)) + { + error("WeaponImage::onFire() - Invalid projectile datablock"); + return; + } + + // Decrement inventory ammo. The image's ammo state is updated + // automatically by the ammo inventory hooks. + if ( !%this.infiniteAmmo ) + %obj.decInventory(%this.ammo, 1); + + // Get the player's velocity, we'll then add it to that of the projectile + %objectVelocity = %obj.getVelocity(); + + %numProjectiles = %this.projectileNum; + if (%numProjectiles == 0) + %numProjectiles = 1; + + for (%i = 0; %i < %numProjectiles; %i++) + { + if (%this.projectileSpread) + { + // We'll need to "skew" this projectile a little bit. We start by + // getting the straight ahead aiming point of the gun + %vec = %obj.getMuzzleVector(%slot); + + // Then we'll create a spread matrix by randomly generating x, y, and z + // points in a circle + %matrix = ""; + for(%j = 0; %j < 3; %j++) + %matrix = %matrix @ (getRandom() - 0.5) * 2 * 3.1415926 * %this.projectileSpread @ " "; + %mat = MatrixCreateFromEuler(%matrix); + + // Which we'll use to alter the projectile's initial vector with + %muzzleVector = MatrixMulVector(%mat, %vec); + %muzzleVector = VectorScale(VectorNormalize(%muzzleVector), %this.projectileSpread *2); + %muzzleVector = VectorAdd(%muzzleVector, %vec); + } + else + { + // Weapon projectile doesn't have a spread factor so we fire it using + // the straight ahead aiming point of the gun + %muzzleVector = %obj.getMuzzleVector(%slot); + } + + // Add player's velocity + %muzzleVelocity = VectorAdd( + VectorScale(%muzzleVector, %this.projectile.muzzleVelocity), + VectorScale(%objectVelocity, %this.projectile.velInheritFactor)); + + // Create the projectile object + %p = new (%this.projectileType)() + { + dataBlock = %this.projectile; + initialVelocity = %muzzleVelocity; + initialPosition = %obj.getMuzzlePoint(%slot); + sourceObject = %obj; + sourceSlot = %slot; + client = %obj.client; + sourceClass = %obj.getClassName(); + }; + MissionCleanup.add(%p); + } +} + +// ---------------------------------------------------------------------------- +// A "generic" weaponimage onAltFire handler for most weapons. Can be +// overridden with an appropriate namespace method for any weapon that requires +// a custom firing solution. +// ---------------------------------------------------------------------------- + +function WeaponImage::onAltFire(%this, %obj, %slot) +{ + //echo("\c4WeaponImage::onAltFire("@%this.getName()@", "@%obj.client.nameBase@", "@%slot@")"); + + // Decrement inventory ammo. The image's ammo state is updated + // automatically by the ammo inventory hooks. + %obj.decInventory(%this.ammo, 1); + + // Get the player's velocity, we'll then add it to that of the projectile + %objectVelocity = %obj.getVelocity(); + + %numProjectiles = %this.altProjectileNum; + if (%numProjectiles == 0) + %numProjectiles = 1; + + for (%i = 0; %i < %numProjectiles; %i++) + { + if (%this.altProjectileSpread) + { + // We'll need to "skew" this projectile a little bit. We start by + // getting the straight ahead aiming point of the gun + %vec = %obj.getMuzzleVector(%slot); + + // Then we'll create a spread matrix by randomly generating x, y, and z + // points in a circle + %matrix = ""; + for(%i = 0; %i < 3; %i++) + %matrix = %matrix @ (getRandom() - 0.5) * 2 * 3.1415926 * %this.altProjectileSpread @ " "; + %mat = MatrixCreateFromEuler(%matrix); + + // Which we'll use to alter the projectile's initial vector with + %muzzleVector = MatrixMulVector(%mat, %vec); + } + else + { + // Weapon projectile doesn't have a spread factor so we fire it using + // the straight ahead aiming point of the gun. + %muzzleVector = %obj.getMuzzleVector(%slot); + } + + // Add player's velocity + %muzzleVelocity = VectorAdd( + VectorScale(%muzzleVector, %this.altProjectile.muzzleVelocity), + VectorScale(%objectVelocity, %this.altProjectile.velInheritFactor)); + + // Create the projectile object + %p = new (%this.projectileType)() + { + dataBlock = %this.altProjectile; + initialVelocity = %muzzleVelocity; + initialPosition = %obj.getMuzzlePoint(%slot); + sourceObject = %obj; + sourceSlot = %slot; + client = %obj.client; + }; + MissionCleanup.add(%p); + } +} + +// ---------------------------------------------------------------------------- +// A "generic" weaponimage onWetFire handler for most weapons. Can be +// overridden with an appropriate namespace method for any weapon that requires +// a custom firing solution. +// ---------------------------------------------------------------------------- + +function WeaponImage::onWetFire(%this, %obj, %slot) +{ + //echo("\c4WeaponImage::onWetFire("@%this.getName()@", "@%obj.client.nameBase@", "@%slot@")"); + + // Decrement inventory ammo. The image's ammo state is updated + // automatically by the ammo inventory hooks. + %obj.decInventory(%this.ammo, 1); + + // Get the player's velocity, we'll then add it to that of the projectile + %objectVelocity = %obj.getVelocity(); + + %numProjectiles = %this.projectileNum; + if (%numProjectiles == 0) + %numProjectiles = 1; + + for (%i = 0; %i < %numProjectiles; %i++) + { + if (%this.wetProjectileSpread) + { + // We'll need to "skew" this projectile a little bit. We start by + // getting the straight ahead aiming point of the gun + %vec = %obj.getMuzzleVector(%slot); + + // Then we'll create a spread matrix by randomly generating x, y, and z + // points in a circle + %matrix = ""; + for(%j = 0; %j < 3; %j++) + %matrix = %matrix @ (getRandom() - 0.5) * 2 * 3.1415926 * %this.wetProjectileSpread @ " "; + %mat = MatrixCreateFromEuler(%matrix); + + // Which we'll use to alter the projectile's initial vector with + %muzzleVector = MatrixMulVector(%mat, %vec); + } + else + { + // Weapon projectile doesn't have a spread factor so we fire it using + // the straight ahead aiming point of the gun. + %muzzleVector = %obj.getMuzzleVector(%slot); + } + + // Add player's velocity + %muzzleVelocity = VectorAdd( + VectorScale(%muzzleVector, %this.wetProjectile.muzzleVelocity), + VectorScale(%objectVelocity, %this.wetProjectile.velInheritFactor)); + + // Create the projectile object + %p = new (%this.projectileType)() + { + dataBlock = %this.wetProjectile; + initialVelocity = %muzzleVelocity; + initialPosition = %obj.getMuzzlePoint(%slot); + sourceObject = %obj; + sourceSlot = %slot; + client = %obj.client; + }; + MissionCleanup.add(%p); + } +} + +//----------------------------------------------------------------------------- +// Clip Management +//----------------------------------------------------------------------------- + +function WeaponImage::onClipEmpty(%this, %obj, %slot) +{ + //echo("WeaponImage::onClipEmpty: " SPC %this SPC %obj SPC %slot); + + // Attempt to automatically reload. Schedule this so it occurs + // outside of the current state that called this method + %this.schedule(0, "reloadAmmoClip", %obj, %slot); +} + +function WeaponImage::reloadAmmoClip(%this, %obj, %slot) +{ + //echo("WeaponImage::reloadAmmoClip: " SPC %this SPC %obj SPC %slot); + + // Make sure we're indeed the currect image on the given slot + if (%this != %obj.getMountedImage(%slot)) + return; + + if ( %this.isField("clip") ) + { + if (%obj.getInventory(%this.clip) > 0) + { + %obj.decInventory(%this.clip, 1); + %obj.setInventory(%this.ammo, %this.ammo.maxInventory); + %obj.setImageAmmo(%slot, true); + } + else + { + %amountInPocket = %obj.getFieldValue( "remaining" @ %this.ammo.getName()); + if ( %amountInPocket ) + { + %obj.setFieldValue( "remaining" @ %this.ammo.getName(), 0); + %obj.setInventory( %this.ammo, %amountInPocket ); + %obj.setImageAmmo( %slot, true ); + } + } + + } +} + +function WeaponImage::clearAmmoClip( %this, %obj, %slot ) +{ + //echo("WeaponImage::clearAmmoClip: " SPC %this SPC %obj SPC %slot); + + // if we're not empty put the remaining bullets from the current clip + // in to the player's "pocket". + + if ( %this.isField( "clip" ) ) + { + // Commenting out this line will use a "hard clip" system, where + // A player will lose any ammo currently in the gun when reloading. + %pocketAmount = %this.stashSpareAmmo( %obj ); + + if ( %obj.getInventory( %this.clip ) > 0 || %pocketAmount != 0 ) + %obj.setImageAmmo(%slot, false); + } +} +function WeaponImage::stashSpareAmmo( %this, %player ) +{ + // If the amount in our pocket plus what we are about to add from the clip + // Is over a clip, add a clip to inventory and keep the remainder + // on the player + if (%player.getInventory( %this.ammo ) < %this.ammo.maxInventory ) + { + %nameOfAmmoField = "remaining" @ %this.ammo.getName(); + + %amountInPocket = %player.getFieldValue( %nameOfAmmoField ); + + %amountInGun = %player.getInventory( %this.ammo ); + + %combinedAmmo = %amountInGun + %amountInPocket; + + // Give the player another clip if the amount in our pocket + the + // Amount in our gun is over the size of a clip. + if ( %combinedAmmo >= %this.ammo.maxInventory ) + { + %player.setFieldValue( %nameOfAmmoField, %combinedAmmo - %this.ammo.maxInventory ); + %player.incInventory( %this.clip, 1 ); + } + else if ( %player.getInventory(%this.clip) > 0 )// Only put it back in our pocket if we have clips. + %player.setFieldValue( %nameOfAmmoField, %combinedAmmo ); + + return %player.getFieldValue( %nameOfAmmoField ); + + } + + return 0; + +} + +//----------------------------------------------------------------------------- +// Clip Class +//----------------------------------------------------------------------------- + +function AmmoClip::onPickup(%this, %obj, %shape, %amount) +{ + // The parent Item method performs the actual pickup. + if (Parent::onPickup(%this, %obj, %shape, %amount)) + serverPlay3D(AmmoPickupSound, %shape.getTransform()); + + // The clip inventory state has changed, we need to update the + // current mounted image using this clip to reflect the new state. + if ((%image = %shape.getMountedImage($WeaponSlot)) > 0) + { + // Check if this weapon uses the clip we just picked up and if + // there is no ammo. + if (%image.isField("clip") && %image.clip.getId() == %this.getId()) + { + %outOfAmmo = !%shape.getImageAmmo($WeaponSlot); + + %currentAmmo = %shape.getInventory(%image.ammo); + + if ( isObject( %image.clip ) ) + %amountInClips = %shape.getInventory(%image.clip); + + %amountInClips *= %image.ammo.maxInventory; + %amountInClips += %obj.getFieldValue( "remaining" @ %this.ammo.getName() ); + + %shape.client.setAmmoAmountHud(%currentAmmo, %amountInClips ); + + if (%outOfAmmo) + { + %image.onClipEmpty(%shape, $WeaponSlot); + } + } + } +} + +//----------------------------------------------------------------------------- +// Ammmo Class +//----------------------------------------------------------------------------- + +function Ammo::onPickup(%this, %obj, %shape, %amount) +{ + // The parent Item method performs the actual pickup. + if (Parent::onPickup(%this, %obj, %shape, %amount)) + serverPlay3D(AmmoPickupSound, %shape.getTransform()); +} + +function Ammo::onInventory(%this, %obj, %amount) +{ + // The ammo inventory state has changed, we need to update any + // mounted images using this ammo to reflect the new state. + for (%i = 0; %i < 8; %i++) + { + if ((%image = %obj.getMountedImage(%i)) > 0) + if (isObject(%image.ammo) && %image.ammo.getId() == %this.getId()) + { + %obj.setImageAmmo(%i, %amount != 0); + %currentAmmo = %obj.getInventory(%this); + + if (%obj.getClassname() $= "Player") + { + if ( isObject( %this.clip ) ) + { + %amountInClips = %obj.getInventory(%this.clip); + %amountInClips *= %this.maxInventory; + %amountInClips += %obj.getFieldValue( "remaining" @ %this.getName() ); + } + else //Is a single fire weapon, like the grenade launcher. + { + %amountInClips = %currentAmmo; + %currentAmmo = 1; + } + + if (%obj.client !$= "" && !%obj.isAiControlled) + %obj.client.setAmmoAmountHud(%currentAmmo, %amountInClips); + } + } + } +} + +// ---------------------------------------------------------------------------- +// Weapon cycling +// ---------------------------------------------------------------------------- + +function ShapeBase::clearWeaponCycle(%this) +{ + %this.totalCycledWeapons = 0; +} + +function ShapeBase::addToWeaponCycle(%this, %weapon) +{ + %this.cycleWeapon[%this.totalCycledWeapons++ - 1] = %weapon; +} + +function ShapeBase::cycleWeapon(%this, %direction) +{ + // Can't cycle what we don't have + if (%this.totalCycledWeapons == 0) + return; + + // Find out the index of the current weapon, if any (not all + // available weapons may be part of the cycle) + %currentIndex = -1; + if (%this.getMountedImage($WeaponSlot) != 0) + { + %curWeapon = %this.getMountedImage($WeaponSlot).item.getName(); + for (%i=0; %i<%this.totalCycledWeapons; %i++) + { + if (%this.cycleWeapon[%i] $= %curWeapon) + { + %currentIndex = %i; + break; + } + } + } + + // Get the next weapon index + %nextIndex = 0; + %dir = 1; + if (%currentIndex != -1) + { + if (%direction $= "prev") + { + %dir = -1; + %nextIndex = %currentIndex - 1; + if (%nextIndex < 0) + { + // Wrap around to the end + %nextIndex = %this.totalCycledWeapons - 1; + } + } + else + { + %nextIndex = %currentIndex + 1; + if (%nextIndex >= %this.totalCycledWeapons) + { + // Wrap back to the beginning + %nextIndex = 0; + } + } + } + + // We now need to check if the next index is a valid weapon. If not, + // then continue to cycle to the next weapon, in the appropriate direction, + // until one is found. If nothing is found, then do nothing. + %found = false; + for (%i=0; %i<%this.totalCycledWeapons; %i++) + { + %weapon = %this.cycleWeapon[%nextIndex]; + if (%weapon !$= "" && %this.hasInventory(%weapon) && %this.hasAmmo(%weapon)) + { + // We've found out weapon + %found = true; + break; + } + + %nextIndex = %nextIndex + %dir; + if (%nextIndex < 0) + { + %nextIndex = %this.totalCycledWeapons - 1; + } + else if (%nextIndex >= %this.totalCycledWeapons) + { + %nextIndex = 0; + } + } + + if (%found) + { + %this.use(%this.cycleWeapon[%nextIndex]); + } +} diff --git a/Templates/BaseGame/game/tools/assetBrowser/main.tscript b/Templates/BaseGame/game/tools/assetBrowser/main.tscript index e4aad3292..2b3e0938c 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/main.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/main.tscript @@ -27,30 +27,9 @@ function initializeAssetBrowser() $AssetBrowser::collectionSetsFile = "tools/assetBrowser/searchCollectionSets.xml"; $AssetBrowser::currentImportConfig = ""; - if(!isObject(AssetFilterTypeList)) - { - new ArrayObject(AssetFilterTypeList); + if(!isObject(ABAssetTypesList)) + new ArrayObject(ABAssetTypesList){}; - AssetFilterTypeList.add("All"); - AssetFilterTypeList.add("ComponentAsset"); - AssetFilterTypeList.add("CppAsset"); - AssetFilterTypeList.add("CubemapAsset"); - AssetFilterTypeList.add("GameObjectAsset"); - AssetFilterTypeList.add("GUIAsset"); - AssetFilterTypeList.add("ImageAsset"); - AssetFilterTypeList.add("LevelAsset"); - AssetFilterTypeList.add("MaterialAsset"); - AssetFilterTypeList.add("ParticleAsset"); - AssetFilterTypeList.add("PostFXAsset"); - AssetFilterTypeList.add("ScriptAsset"); - AssetFilterTypeList.add("ShapeAsset"); - AssetFilterTypeList.add("ShapeAnimationAsset"); - AssetFilterTypeList.add("SoundAsset"); - AssetFilterTypeList.add("StateMachineAsset"); - AssetFilterTypeList.add("TerrainAsset"); - AssetFilterTypeList.add("TerrainMaterialAsset"); - } - exec("./scripts/profiles." @ $TorqueScriptFileExtension); exec("./guis/assetBrowser.gui"); @@ -90,19 +69,19 @@ function initializeAssetBrowser() exec("./scripts/utils." @ $TorqueScriptFileExtension); //Processing for the different asset types - exec("./scripts/assetTypes/component." @ $TorqueScriptFileExtension); + exec("./scripts/assetTypes/genericAsset." @ $TorqueScriptFileExtension); + exec("./scripts/assetTypes/cpp." @ $TorqueScriptFileExtension); - exec("./scripts/assetTypes/gameObject." @ $TorqueScriptFileExtension); exec("./scripts/assetTypes/gui." @ $TorqueScriptFileExtension); exec("./scripts/assetTypes/image." @ $TorqueScriptFileExtension); exec("./scripts/assetTypes/level." @ $TorqueScriptFileExtension); + exec("./scripts/assetTypes/subScene." @ $TorqueScriptFileExtension); exec("./scripts/assetTypes/material." @ $TorqueScriptFileExtension); exec("./scripts/assetTypes/postFX." @ $TorqueScriptFileExtension); exec("./scripts/assetTypes/script." @ $TorqueScriptFileExtension); exec("./scripts/assetTypes/shape." @ $TorqueScriptFileExtension); exec("./scripts/assetTypes/shapeAnimation." @ $TorqueScriptFileExtension); - exec("./scripts/assetTypes/sound." @ $TorqueScriptFileExtension); - exec("./scripts/assetTypes/stateMachine." @ $TorqueScriptFileExtension); + exec("./scripts/assetTypes/sound." @ $TorqueScriptFileExtension); exec("./scripts/assetTypes/cubemap." @ $TorqueScriptFileExtension); exec("./scripts/assetTypes/folder." @ $TorqueScriptFileExtension); exec("./scripts/assetTypes/terrain." @ $TorqueScriptFileExtension); diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript index 9e4421edd..9dcd48e63 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript @@ -29,6 +29,224 @@ function AssetBrowser::addToolbarButton(%this) } // +// +function AssetBrowser::registerAssetType(%assetTypeName, %humanReadableName, %assetClassNamesList, %showInFilters) +{ + if(%showInFilters $= "") + %showInFilters = true; + + ABAssetTypesList.add("Asset", %assetTypeName TAB %humanReadableName TAB %assetClassNamesList TAB %showInFilters); +} + +function AssetBrowser::registerFileType(%fileTypeName, %humanReadableName, %fileExtensionsList, %showInFilters) +{ + if(%showInFilters $= "") + %showInFilters = true; + + ABAssetTypesList.add("File", %fileTypeName TAB %humanReadableName TAB %fileExtensionsList TAB %showInFilters); +} + +function AssetBrowser::registerObjectType(%objectTypeName, %humanReadableName, %objectClassNames, %showInFilters) +{ + if(%showInFilters $= "") + %showInFilters = true; + + ABAssetTypesList.add("Object", %objectTypeName TAB %humanReadableName TAB %objectClassNames TAB %showInFilters); +} + +function AssetBrowser::callAssetTypeFunc(%this, %type, %function, %param0, %param1, %param2, %param3, %param4) +{ + //echo("AssetBrowser::callAssetTypeFunc() - deets: " @ %type @ ", " @ %function @ ", " @ %param0 @ ", " @ %param1 @ ", " @ %param2 @ ", " @ %param3 @ ", " @ %param4); + $paramCache0 = %param0; + $paramCache1 = %param1; + $paramCache2 = %param2; + $paramCache3 = %param3; + $paramCache4 = %param4; + + $CurrentAssetBrowser = %this; + + //look up the type group + %typeGroup = ""; + %typeData = ""; + for(%i=0; %i < ABAssetTypesList.count(); %i++) + { + %group = ABAssetTypesList.getKey(%i); + %typeData = ABAssetTypesList.getValue(%i); + + if(getField(%typeData, 0) $= %type) + { + %typeGroup = %group; + %typeData = %typeData; + break; + } + } + + %paramOffset = 0; + %isStaticCall = false; + %command = ""; + if(%typeGroup $= "Asset") + { + //check to see if the first param is an asset definition + if(isObject(%param0) && %param0.isInNamespaceHierarchy("AssetBase")) + { + if(%param0.isMethod(%function)) + { + %command = %param0 @ "." @ %function @ "("; + %paramOffset = 1; + } + else + { + %command = "GenericAsset::" @ %function @ "(" @ %param0; + %paramOffset = 1; + %isStaticCall = true; + } + } + else + { + if(AssetDatabase.isDeclaredAsset(%param0)) + { + %assetDef = AssetDatabase.acquireAsset(%param0); + if(%assetDef.isMethod(%function)) + { + %command = %assetDef @ "." @ %function @ "("; + %paramOffset = 1; + } + else + { + %command = "GenericAsset::" @ %function @ "(" @ %assetDef; + %paramOffset = 1; + %isStaticCall = true; + } + } + else + { + //we may have to build the assetID + %assetId = %param0 @ ":" @ %param1; + if(AssetDatabase.isDeclaredAsset(%assetId)) + { + %assetDef = AssetDatabase.acquireAsset(%assetId); + + if(%assetDef.isMethod(%function)) + { + %command = %assetDef @ "." @ %function @ "("; + %paramOffset = 2; + } + else + { + %command = "GenericAsset::" @ %function @ "(" @ %assetDef; + %paramOffset = 2; + %isStaticCall = true; + } + } + } + } + } + else if(%typeGroup $= "File") + { + %compoundPath = %param0 @ "/" @ %param1; + if(isFile(%compoundPath) || isDirectory(%compoundPath)) + { + if(isMethod(%type, %function)) + { + %command = %type @ "::" @ %function @ "(\"" @ %compoundPath @ "\""; + %paramOffset = 2; + %isStaticCall = true; + } + else + { + %command = "GenericAsset::" @ %function @ "(\"" @ %compoundPath @ "\""; + %paramOffset = 2; + %isStaticCall = true; + } + } + else if(isFile(%param0) || isDirectory(%param0)) + { + if(isMethod(%type, %function)) + { + %command = %type @ "::" @ %function @ "(\"" @ %param0 @ "\""; + %paramOffset = 1; + %isStaticCall = true; + } + else + { + %command = "GenericAsset::" @ %function @ "(\"" @ %param0 @ "\""; + %paramOffset = 1; + %isStaticCall = true; + } + } + } + else if(%typeGroup $= "Object") + { + if(isObject(%param0) && %param0.isMethod(%function)) + { + %command = %param0 @ "." @ %function @ "("; + %paramOffset = 1; + } + else + { + if(isMethod(%type, %function)) + { + %command = %type @ "::" @ %function @ "("; + %isStaticCall = true; + } + } + } + + if(%command $= "") + { + //check in case it's a purely static type call with no usual incoming vars. + //Usually only relevent for create functions + if($paramCache0 $= "" && $paramCache1 $= "" && isMethod(%type, %function)) + { + %command = %type @ "::" @ %function @ "("; + %isStaticCall = true; + } + else if(isMethod("GenericAsset", %function)) + { + %command = "GenericAsset::" @ %function @ "("; + %isStaticCall = true; + } + else + { + error("AssetBrowser::callAssetTypeFunc() - unable to find a valid type: " @ %type @ " with function: " @ %function); + return; + } + } + + for(%i=%paramOffset; %i < 5; %i++) + { + %paramVar = getVariable("$paramCache" @ %i); + if(%paramVar !$= "") + { + if(%paramOffset != 0 && %i==%paramOffset && %isStaticCall) + %command = %command @ ","; + + if(getWordCount(%paramVar) > 1 || strPos(%paramVar, "/") != 0 || stePos(%paramVar, "\\") != 0) + %command = %command @ "\"" @ %paramVar @ "\""; + else + %command = %command @ %paramVar; + } + %nextParamVar = getVariable("$paramCache" @ %i+1); + if(%nextParamVar !$= "") + { + %command = %command @ ","; + } + } + + %command = %command @ ");"; + + //echo("AssetBrowser::callAssetTypeFunc() - executing command: " @ %command); + + %return = ""; + if(%command !$= "") + %return = eval(%command); + + $CurrentAssetBrowser = ""; + + return %return; +} + +// function AssetBrowser::initialize(%this) { // manage preview array @@ -40,11 +258,11 @@ function AssetBrowser::initialize(%this) if(!isObject(%this.dirHandler)) { - %this.dirHandler = makedirectoryHandler(AssetBrowser-->filterTree, "cache,shaderCache", ""); + %this.dirHandler = makedirectoryHandler(%this-->filterTree, "cache,shaderCache", ""); %this.dirHandler.currentAddress = "data/"; } - AssetBrowser-->filterTree.buildIconTable( ":tools/classIcons/Prefab:tools/classIcons/Prefab" @ + %this-->filterTree.buildIconTable( ":tools/classIcons/Prefab:tools/classIcons/Prefab" @ ":tools/classIcons/SimSet:tools/classIcons/SimSet"); %this.isReImportingAsset = false; @@ -61,9 +279,11 @@ function AssetBrowser::initialize(%this) //First, build our our list of active modules %modulesList = ModuleDatabase.findModules(true); - AssetBrowser-->previewSlider.setValue(EditorSettings.value("Assets/Browser/previewTileSize", "1.0")); + %this-->previewSlider.setValue(EditorSettings.value("Assets/Browser/previewTileSize", "1.0")); - AssetBrowser-->filterAssetsButton.setActive(true); + %this-->filterAssetsButton.setActive(true); + + %this.toggleAssetTypeFilter(0); } function AssetBrowser::onAdd(%this) @@ -109,11 +329,11 @@ function AssetBrowser::setTab(%this, %tab, %text, %command) function AssetBrowser::putToFront(%this) { // Close the object - AssetBrowser.hideDialog(); + %this.hideDialog(); // Create the object again so it will render on top - AssetBrowser.ShowDialog(); + %this.ShowDialog(); // Put the focus on this window - AssetBrowser.restoreLastPosExt(); + %this.restoreLastPosExt(); AssetBrowserWindow.selectWindow(); } @@ -173,7 +393,7 @@ function AssetBrowser::viewToolsModulesFilter(%this) EditorSettings.setValue("Assets/Browser/showToolsModule", %newVal); - AssetBrowser.loadDirectories(); + %this.loadDirectories(); } function AssetBrowser::viewPopulatedModulesFilter(%this) @@ -185,7 +405,7 @@ function AssetBrowser::viewPopulatedModulesFilter(%this) EditorSettings.setValue("Assets/Browser/showOnlyPopulatedModule", %newVal); - AssetBrowser.loadDirectories(); + %this.loadDirectories(); } function AssetBrowser::toggleShowingFolders(%this) @@ -197,7 +417,7 @@ function AssetBrowser::toggleShowingFolders(%this) EditorSettings.setValue("Assets/Browser/showFolders", %newVal); - AssetBrowser.loadDirectories(); + %this.loadDirectories(); } function AssetBrowser::toggleShowingEmptyFolders(%this) @@ -209,7 +429,7 @@ function AssetBrowser::toggleShowingEmptyFolders(%this) EditorSettings.setValue("Assets/Browser/showEmptyFolders", %newVal); - AssetBrowser.refresh(); + %this.refresh(); } function AssetBrowser::toggleAssetTypeFilter(%this, %assetTypeIdx) @@ -219,24 +439,24 @@ function AssetBrowser::toggleAssetTypeFilter(%this, %assetTypeIdx) //Clear existing filters if(%assetTypeIdx == 0) { - for(%i=0; %i < AssetFilterTypeList.Count() + 1; %i++) + for(%i=0; %i < ABAssetTypesList.Count(); %i++) { - AssetTypeListPopup.checkItem(%i, false); + AssetTypeListPopup.checkItem(%i+2, false); } AssetTypeListPopup.checkItem(0, true); } - else + else if(%assetTypeIdx > 1) //slot 1 is the divider so ignore it { if(%isChecked) { %anyOtherFilters = false; - for(%i=1; %i < AssetFilterTypeList.Count() + 1; %i++) + for(%i=0; %i < ABAssetTypesList.Count(); %i++) { - if(%assetTypeIdx == %i) + if(%assetTypeIdx == %i+2) continue; - if(AssetTypeListPopup.isItemChecked(%i)) + if(AssetTypeListPopup.isItemChecked(%i+1)) { %anyOtherFilters = true; break; @@ -246,9 +466,9 @@ function AssetBrowser::toggleAssetTypeFilter(%this, %assetTypeIdx) if(%isChecked && !%anyOtherFilters) { - for(%i=0; %i < AssetFilterTypeList.Count() + 1; %i++) + for(%i=0; %i < ABAssetTypesList.Count(); %i++) { - AssetTypeListPopup.checkItem(%i, false); + AssetTypeListPopup.checkItem(%i+2, false); } AssetTypeListPopup.checkItem(0, true); @@ -272,21 +492,26 @@ function AssetBrowser::toggleAssetTypeFilter(%this, %assetTypeIdx) %i--; } } - - //Update our search terms - %newSearchPhrase = ""; - for(%i=0; %i < AssetFilterTypeList.Count() + 1; %i++) + + for(%i=2; %i < AssetTypeListPopup.getItemCount(); %i++) { %isChecked = AssetTypeListPopup.isItemChecked(%i); - if(!%isChecked) continue; - - %itemText = AssetTypeListPopup.getItemText(%i); - if(%itemText $= "All") - continue; - AssetSearchTerms.add("type", %itemText); + %typeListText = AssetTypeListPopup.getItemText(%i); + + for(%t=0; %t < ABAssetTypesList.Count(); %t++) + { + %typeData = ABAssetTypesList.getValue(%t); + %typeName = getField(%typeData, 1); + + if(%typeListText $= %typeName) + { + AssetSearchTerms.add("type", getField(%typeData, 0)); + break; + } + } } %this.updateSearchTextFromFilter(); @@ -297,19 +522,19 @@ function AssetBrowser::toggleAssetTypeFilter(%this, %assetTypeIdx) // function AssetBrowser::selectAsset( %this, %asset ) { - if(AssetBrowser.selectCallback !$= "") + if(%this.selectCallback !$= "") { // The callback function should be ready to intake the returned material //eval("materialEd_previewMaterial." @ %propertyField @ " = " @ %value @ ";"); - if( AssetBrowser.returnType $= "name" ) + if( %this.returnType $= "name" ) { // TODO! %name = ""; - eval( "" @ AssetBrowser.selectCallback @ "(" @ %name @ ");"); + eval( "" @ %this.selectCallback @ "(" @ %name @ ");"); } else { - %command = "" @ AssetBrowser.selectCallback @ "(\"" @ %asset @ "\");"; + %command = "" @ %this.selectCallback @ "(\"" @ %asset @ "\");"; eval(%command); } } @@ -322,22 +547,22 @@ function AssetBrowser::selectAsset( %this, %asset ) if(isObject(Inspector)) Inspector.refresh(); - AssetBrowser.hideDialog(); + %this.hideDialog(); } function AssetBrowser::showDialog( %this, %AssetTypeFilter, %selectCallback, %targetObj, %fieldName, %returnType) { // Set the select callback - AssetBrowser.selectCallback = %selectCallback; - AssetBrowser.returnType = %returnType; - AssetBrowser.assetTypeFilter = %AssetTypeFilter; - AssetBrowser.fieldTargetObject = %targetObj; - AssetBrowser.fieldTargetName = %fieldName; + %this.selectCallback = %selectCallback; + %this.returnType = %returnType; + %this.assetTypeFilter = %AssetTypeFilter; + %this.fieldTargetObject = %targetObj; + %this.fieldTargetName = %fieldName; - Canvas.popDialog(AssetBrowser); - Canvas.pushDialog(AssetBrowser); + Canvas.popDialog(%this); + Canvas.pushDialog(%this); - AssetBrowser.setVisible(1); + %this.setVisible(1); AssetBrowserWindow.setVisible(1); AssetBrowserWindow.selectWindow(); @@ -350,11 +575,11 @@ function AssetBrowser::showDialog( %this, %AssetTypeFilter, %selectCallback, %ta //visibility filter if(%AssetTypeFilter !$= "") { - AssetBrowser-->filterAssetsButton.setActive(false); + %this-->filterAssetsButton.setActive(false); } else { - AssetBrowser-->filterAssetsButton.setActive(true); + %this-->filterAssetsButton.setActive(true); } if(%selectCallback $= "") @@ -369,30 +594,30 @@ function AssetBrowser::showDialog( %this, %AssetTypeFilter, %selectCallback, %ta %this.selectMode = 1; } - AssetBrowser.loadDirectories(); + %this.loadDirectories(); - AssetBrowser.restoreLastPosExt(); + %this.restoreLastPosExt(); } function AssetBrowser::hideDialog( %this ) { - AssetBrowser.setVisible(1); + %this.setVisible(1); AssetBrowserWindow.setVisible(1); Canvas.popDialog(AssetBrowser_addModule); Canvas.popDialog(ImportAssetWindow); - Canvas.popDialog(AssetBrowser); + Canvas.popDialog(%this); } function AssetBrowser::toggleDialog( %this ) { - if(AssetBrowser.isAwake()) + if(%this.isAwake()) { - AssetBrowser.hideDialog(); + %this.hideDialog(); } else { - AssetBrowser.showDialog(); + %this.showDialog(); } } @@ -425,114 +650,14 @@ function AssetBrowser::buildAssetPreview( %this, %asset, %moduleName ) { %assetType = getField(%asset,0); %assetName = getField(%asset, 1); - %sdfasdgah = true; - if(%assetType $= "Folder") - { - %fullPath = %moduleName !$= "" ? %moduleName @ "/" @ %assetName : %assetName; - %fullPath = strreplace(%fullPath, "/", "_"); - - if(isObject(%fullPath)) - %assetDesc = %fullPath; - else - %assetDesc = new ScriptObject(%fullPath); - - %assetDesc.dirPath = %moduleName; - %assetDesc.assetName = %assetName; - %assetDesc.description = %moduleName @ "/" @ %assetName; - %assetDesc.assetType = %assetType; - } - else if(%assetType $= "Datablock") - { - %assetDesc = %assetName; - %assetDesc.assetType = %assetType; - } - else if(%assetType $= "LooseFile") - { - %fullPath = %moduleName !$= "" ? %moduleName @ "/" @ %assetName : %assetName; - %fullPath = strreplace(%fullPath, "/", "_"); - %fullPath = strreplace(%fullPath, ".", "-"); - - if(isObject(%fullPath)) - %assetDesc = %fullPath; - else - %assetDesc = new ScriptObject(%fullPath); - - %assetDesc.dirPath = %moduleName; - %assetDesc.assetName = %assetName; - %assetDesc.description = %moduleName @ "/" @ %assetName; - %assetDesc.assetType = %assetType; - } - else if(%assetType $= "Prefab") - { - %fullPath = %moduleName !$= "" ? %moduleName @ "/" @ %assetName : %assetName; - %fullPath = strreplace(%fullPath, "/", "_"); - %fullPath = strreplace(%fullPath, ".", "-"); - - if(isObject(%fullPath)) - %assetDesc = %fullPath; - else - %assetDesc = new ScriptObject(%fullPath); - - %assetDesc.dirPath = %moduleName; - %assetDesc.assetName = %assetName; - %assetDesc.description = %moduleName @ "/" @ %assetName; - %assetDesc.assetType = %assetType; - } - else if(%assetType $= "Cpp") - { - %fullPath = %moduleName !$= "" ? %moduleName @ "/" @ %assetName : %assetName; - %fullPath = strreplace(%fullPath, "/", "_"); - %fullPath = strreplace(%fullPath, ".", "-"); - - if(isObject(%fullPath)) - %assetDesc = %fullPath; - else - %assetDesc = new ScriptObject(%fullPath); - - %assetDesc.dirPath = %moduleName; - %assetDesc.assetName = %assetName; - %assetDesc.description = %moduleName @ "/" @ %assetName; - %assetDesc.assetType = %assetType; - } - else if(%assetType $= "tscript") - { - %fullPath = %moduleName !$= "" ? %moduleName @ "/" @ %assetName : %assetName; - %fullPath = strreplace(%fullPath, "/", "_"); - %fullPath = strreplace(%fullPath, ".", "-"); - - if(isObject(%fullPath)) - %assetDesc = %fullPath; - else - %assetDesc = new ScriptObject(%fullPath); - - %assetDesc.dirPath = %moduleName; - %assetDesc.assetName = %assetName; - %assetDesc.description = %moduleName @ "/" @ %assetName; - %assetDesc.assetType = %assetType; - } - else if(%assetType $= "Creator") + if(%assetType $= "Creator") { %assetDesc = %assetName; %assetDesc.assetType = %assetType; %moduleName = %assetDesc; } } - /*%fullPath = %moduleName !$= "" ? %moduleName @ "/" @ %assetName : %assetName; - %fullPath = strreplace(%fullPath, "/", "_"); - - if(isObject(%fullPath)) - %assetDesc = %fullPath; - else - %assetDesc = new ScriptObject(%fullPath); - - %assetDesc.dirPath = %moduleName; - %assetDesc.assetName = %assetName; - %assetDesc.description = %moduleName @ "/" @ %assetName; - %assetDesc.assetType = %assetType;*/ - - //%assetName = %asset; - //%assetType = "Folder"; } %previewSize = 100 SPC 100; @@ -554,17 +679,18 @@ function AssetBrowser::buildAssetPreview( %this, %asset, %moduleName ) buttonType = "RadioButton"; buttonMargin = "0 -10"; profile = ToolsGuiDefaultIconBtnProfile; + assetBrowser = %this; }; - %previewScaleSize = AssetBrowser-->previewSlider.getValue(); + %previewScaleSize = %this-->previewSlider.getValue(); if(%previewScaleSize $= "") { %previewScaleSize = 1; - AssetBrowser-->previewSlider.setValue(1); + %this-->previewSlider.setValue(1); } - if(%previewScaleSize == 0 || startsWith(AssetBrowser.dirHandler.currentAddress, "Creator")) + if(%previewScaleSize == 0 || startsWith(%this.dirHandler.currentAddress, "Creator")) { %previewButton.iconLocation = "Left"; %previewButton.textLocation = "Right"; @@ -572,14 +698,14 @@ function AssetBrowser::buildAssetPreview( %this, %asset, %moduleName ) %previewButton.buttonMargin = "8 8"; %previewButton.textMargin = "6"; - AssetBrowser.previewListMode = true; + %this.previewListMode = true; } else { %size = %previewSize.x * %previewScaleSize; %previewButton.setextent(%size,%size + %textBottomPad); - AssetBrowser.previewListMode = false; + %this.previewListMode = false; } //%previewButton.extent = %previewSize.x + %previewBounds SPC %previewSize.y + %previewBounds + 24; @@ -589,18 +715,17 @@ function AssetBrowser::buildAssetPreview( %this, %asset, %moduleName ) if(%this.selectMode) { - %doubleClickCommand = "AssetBrowser.selectAsset( AssetBrowser.selectedAsset );"; + %doubleClickCommand = %this @ ".selectAsset( "@ %this @ ".selectedAsset );"; } else { - %doubleClickCommand = "AssetBrowser.editAsset( "@%assetDesc@" );"; + %doubleClickCommand = %this @ ".callAssetTypeFunc(" @ %assetType @ ", \"onEdit\", \"" @ %moduleName @ "\", \"" @ %assetName @ "\" );"; } %this.previewData.previewLoaded = true; - //Build out the preview - %buildCommand = %this @ ".build" @ %assetType @ "Preview(\"" @ %assetDesc @ "\"," @ %this.previewData @ ");"; - eval(%buildCommand); + //echo("AssetBrowser::buildAssetPreview() - building preview of asset type: " @ %assetType); + %this.callAssetTypeFunc(%assetType, "buildBrowserElement", %moduleName, %assetName, %this.previewData); //debug dump %tooltip = %this.previewData.tooltip; @@ -613,19 +738,20 @@ function AssetBrowser::buildAssetPreview( %this, %asset, %moduleName ) %previewButton.assetName = %assetName; %previewButton.moduleName = %moduleName; %previewButton.assetType = %assetType; + %previewButton.assetBrowser = %this; %previewButton.bitmapAsset = %this.previewData.previewImage; %previewButton.profile = "AssetBrowserPreview" @ %previewButton.assetType; %previewButton.tooltip = %this.previewData.tooltip; - %previewButton.Command = "AssetBrowser.updateSelection( $ThisControl.assetName, $ThisControl.moduleName );"; + %previewButton.Command = %this @ ".updateSelection( $ThisControl.assetName, $ThisControl.moduleName );"; %previewButton.altCommand = %doubleClickCommand; %previewButton.text = %this.previewData.assetName; %previewButton.text.originalAssetName = %this.previewData.assetName; // add to the gui control array - AssetBrowser-->assetList.add(%previewButton); + %this-->assetList.add(%previewButton); // add to the array object for reference later if(%this.previewData.previewLoaded == false) @@ -649,12 +775,12 @@ function AssetBrowser::doRefresh(%this) %this.navigateTo(%this.dirHandler.currentAddress); //Forces a clean collapse of the tree for any not-really-exposed items - %dataItem = AssetBrowser-->filterTree.findItemByName("data"); + %dataItem = %this-->filterTree.findItemByName("data"); if(%dataItem != 0) { - AssetBrowser-->filterTree.expandItem(%dataItem, false); - AssetBrowser-->filterTree.expandItem(%dataItem); + %this-->filterTree.expandItem(%dataItem, false); + %this-->filterTree.expandItem(%dataItem); } %this.dirty = false; @@ -669,15 +795,16 @@ function AssetBrowser::populatePreviewImages(%this) for(%i=0; %i < AssetPreviewArray.count(); %i++) { %previewButton = AssetPreviewArray.getKey(%i); - %type = %previewButton.assetType; + %assetType = %previewButton.assetType; echo(" - Generating preview for asset: " @ %previewButton.moduleName @ ":" @ %previewButton.assetName); - AssetBrowser.call("generate" @ %previewButton.assetType @ "PreviewImage", %previewButton); + %this.callAssetTypeFunc(%assetType, "generatePreviewImage", %previewButton.moduleName, %previewButton.assetName, %previewButton); + AssetPreviewArray.erase(%i); echo(" - done, scheduling another pass"); - AssetBrowser.schedule(32, "populatePreviewImages"); + %this.schedule(32, "populatePreviewImages"); return; } } @@ -703,33 +830,33 @@ function assetBrowserPreviewSlider::onMouseDragged(%this) function AssetBrowser::loadDirectories( %this ) { - AssetBrowser-->filterTree.clear(); + %this-->filterTree.clear(); %dataItem = AssetBrowser-->filterTree.insertItem(0, "Content"); - AssetBrowser-->filterTree.collectionsIdx = AssetBrowser-->filterTree.insertItem(1, "Collections"); + %this-->filterTree.collectionsIdx = %this-->filterTree.insertItem(1, "Collections"); - AssetBrowser-->filterTree.modulesIdx = AssetBrowser-->filterTree.insertItem(1, "Modules"); + %this-->filterTree.modulesIdx = %this-->filterTree.insertItem(1, "Modules"); %dataItem = AssetBrowser-->filterTree.insertItem(AssetBrowser-->filterTree.modulesIdx, "data"); - AssetBrowser-->filterTree.tagsIdx = AssetBrowser-->filterTree.insertItem(1, "Tags"); + %this-->filterTree.tagsIdx = %this-->filterTree.insertItem(1, "Tags"); - AssetBrowser-->filterTree.creatorIdx = AssetBrowser-->filterTree.insertItem(1, "Creator"); + %this-->filterTree.creatorIdx = %this-->filterTree.insertItem(1, "Creator"); - AssetBrowser-->filterTree.clearSelection(); + %this-->filterTree.clearSelection(); if(%this.selectMode) { //Due to a fluke in how this tracks, it overrides the current addres, so we'll //store it real fast - %curAdd = AssetBrowser.dirHandler.currentAddress; + %curAdd = %this.dirHandler.currentAddress; //Disable these for this go - AssetBrowser-->filterTree.addSelection(AssetBrowser-->filterTree.collectionsIdx); - AssetBrowser-->filterTree.addSelection(AssetBrowser-->filterTree.creatorIdx); - AssetBrowser-->filterTree.hideSelection(); - AssetBrowser-->filterTree.clearSelection(); + %this-->filterTree.addSelection(%this-->filterTree.collectionsIdx); + %this-->filterTree.addSelection(%this-->filterTree.creatorIdx); + %this-->filterTree.hideSelection(); + %this-->filterTree.clearSelection(); - AssetBrowser.dirHandler.currentAddress = %curAdd; + %this.dirHandler.currentAddress = %curAdd; } %this.dirHandler.loadFolders("data", %dataItem); @@ -744,18 +871,18 @@ function AssetBrowser::loadDirectories( %this ) //If set to, show core if(EditorSettings.value("Assets/Browser/showCoreModule", false) == 1) { - %coreItem = AssetBrowser-->filterTree.insertItem(AssetBrowser-->filterTree.modulesIdx, "core"); + %coreItem = %this-->filterTree.insertItem(%this-->filterTree.modulesIdx, "core"); %this.dirHandler.loadFolders("core", %coreItem); } //If set to, show tools if(EditorSettings.value("Assets/Browser/showToolsModule", false) == 1) { - %toolsItem = AssetBrowser-->filterTree.insertItem(AssetBrowser-->filterTree.modulesIdx, "tools"); + %toolsItem = %this-->filterTree.insertItem(%this-->filterTree.modulesIdx, "tools"); %this.dirHandler.loadFolders("tools", %toolsItem); } - AssetBrowser-->filterTree.buildVisibleTree(true); + %this-->filterTree.buildVisibleTree(true); //Remove any modules that have no assets if we have that filter on if(%this.onlyShowModulesWithAssets) @@ -765,30 +892,30 @@ function AssetBrowser::loadDirectories( %this ) { %moduleName = getWord(%modulesList, %i).ModuleId; - %moduleItemId = AssetBrowser-->filterTree.findItemByName(%moduleName); + %moduleItemId = %this-->filterTree.findItemByName(%moduleName); - if(AssetBrowser-->filterTree.isParentItem(%moduleItemId) == false) - AssetBrowser-->filterTree.removeItem(%moduleItemId); + if(%this-->filterTree.isParentItem(%moduleItemId) == false) + %this-->filterTree.removeItem(%moduleItemId); } } //special handling for selections - if(AssetBrowser.newModuleId !$= "") + if(%this.newModuleId !$= "") { - AssetBrowser-->filterTree.clearSelection(); - %newModuleItem = AssetBrowser-->filterTree.findItemByName(AssetBrowser.newModuleId); - AssetBrowser-->filterTree.selectItem(%newModuleItem); - AssetBrowser.newModuleId = ""; + %this-->filterTree.clearSelection(); + %newModuleItem = %this-->filterTree.findItemByName(%this.newModuleId); + %this-->filterTree.selectItem(%newModuleItem); + %this.newModuleId = ""; } - AssetBrowser.dirHandler.expandTreeToAddress(AssetBrowser.dirHandler.currentAddress); + %this.dirHandler.expandTreeToAddress(%this.dirHandler.currentAddress); - %selectedItem = AssetBrowser.dirHandler.getFolderTreeItemFromAddress(AssetBrowser.dirHandler.currentAddress); - AssetBrowser-->filterTree.scrollVisibleByObjectId(%selectedItem); + %selectedItem = %this.dirHandler.getFolderTreeItemFromAddress(%this.dirHandler.currentAddress); + %this-->filterTree.scrollVisibleByObjectId(%selectedItem); - AssetBrowser-->filterTree.buildVisibleTree(true); + %this-->filterTree.buildVisibleTree(true); - AssetBrowser.refresh(); + %this.refresh(); } function AssetBrowser::updateSelection( %this, %asset, %moduleName ) @@ -1145,63 +1272,8 @@ function AssetBrowser::reImportAsset(%this) // RMB context popups function AssetBrowserPreviewButton::onRightClick(%this) { - AssetBrowser.selectedAssetPreview = %this; - EditAssetPopup.assetId = %this.moduleName @ ":" @ %this.assetName; - EditAssetPopup.assetType = %this.assetType; - %assetType = %this.assetType; - - //Do some enabling/disabling of options depending on asset type - EditAssetPopup.enableItem(0, true); - EditAssetPopup.enableItem(9, true); - - //Is it an editable type? - if(%assetType $= "ImageAsset" /*|| %assetType $= "GameObjectAsset"*/ || %assetType $= "CppAsset") - { - EditAssetPopup.enableItem(0, false); - } - - //Is it an importable type? - if(%assetType $= "GameObjectAsset" || %assetType $= "ComponentAsset" || %assetType $= "GUIAsset" || %assetType $= "LevelAsset" - || %assetType $= "MaterialAsset" || %assetType $= "ParticleAsset" || %assetType $= "PostEffectAsset" || %assetType $= "ScriptAsset" - || %assetType $= "StateMachineAsset") - { - EditAssetPopup.enableItem(9, false); - } - - /*if(AssetDatabase.acquireAsset(EditAssetPopup.assetId)) - { - %assetDef = AssetDatabase.acquireAsset(EditAssetPopup.assetId); - if(%assetDef.originalFilePath $= "" || !isFile(%assetDef.originalFilePath)) - { - //if we have no noted original import file path or it's invalid - //we can't reimport either - EditAssetPopup.enableItem(9, false); - } - AssetDatabase.releaseAsset(EditAssetPopup.assetId); - }*/ - - if(%assetType $= "LevelAsset") - { - EditLevelAssetPopup.showPopup(Canvas); - } - else if(%assetType $= "Folder") - { - EditFolderPopup.dirPath = %this.moduleName @ "/" @ %this.assetName; - EditFolderPopup.showPopup(Canvas); - } - else if(%assetType $= "TerrainAsset") - { - EditTerrainAssetPopup.showPopup(Canvas); - } - else - { - EditAssetPopup.showPopup(Canvas); - } - - if(%assetType $= "Folder") - { - EditAssetPopup.assetId = %this.moduleName @ "/" @ %this.assetName; - } + %this.assetBrowser.selectedAssetPreview = %this; + %this.assetBrowser.callAssetTypeFunc(%this.assetType, "onShowActionMenu", %this.moduleName, %this.assetName); } //function AssetListPanel::onRightMouseDown(%this) @@ -1431,6 +1503,9 @@ function AssetBrowserFilterTree::onSelect(%this, %itemId) //can't select root return; + %scrollCtrl = %this.getParent(); + %scrollPos = %scrollCtrl.getScrollPosition(); + //process special cases %parentItem = %this.getParentItem(%itemId); if(%parentItem == %this.tagsIdx) @@ -1468,6 +1543,9 @@ function AssetBrowserFilterTree::onSelect(%this, %itemId) AssetBrowser.navigateTo(%breadcrumbPath); } + + //restore the scroll position + %scrollCtrl.schedule(1, "setScrollPosition", %scrollPos.x, %scrollPos.y); } function AssetBrowserFilterTree::hasAsParent(%this, %itemId, %text) @@ -1519,172 +1597,115 @@ function AssetBrowser::doRebuildAssetArray(%this) %finalAssetCount = 0; - //Add folders - if(EditorSettings.value("Assets/Browser/showFolders", true) == true) + if(!startsWith(%breadcrumbPath, "Creator")) { - %folders = getDirectoryList(%breadcrumbPath); - for(%f=0; %f < getFieldCount(%folders); %f++) + //Add folders + if(EditorSettings.value("Assets/Browser/showFolders", true) == true) { - %folderName = getField(%folders, %f); - - %searchActive = AssetSearchTerms.count() != 0; - if(%searchActive) + %folders = getDirectoryList(%breadcrumbPath); + for(%f=0; %f < getFieldCount(%folders); %f++) { - if(matchesSearch(%folderName, "Folder", "")) + %folderName = getField(%folders, %f); + + %searchActive = AssetSearchTerms.count() != 0; + if(%searchActive) { - $AssetBrowser::AssetArray.add( %breadcrumbPath, "Folder" TAB %folderName ); - continue; - } - } - else - { - //got it. - if(%folderName $= "shaderCache" || %folderName $= "cache" || %folderName $= ".git") - continue; - - if(!%this.coreModulesFilter && %folderName $= "core" && %breadcrumbPath $= "") - continue; - - if(!%this.toolsModulesFilter && %folderName $= "tools" && %breadcrumbPath $= "") - continue; - - $AssetBrowser::AssetArray.add( %breadcrumbPath, "Folder" TAB %folderName ); - } - } - } - - //now, we'll iterate through, and find the assets that are in this module, and this category - for( %i=0; %i < %numAssetsFound; %i++) - { - %assetId = %assetQuery.getAsset(%i); - - %assetPath = makeRelativePath(AssetDatabase.getAssetFilePath(%assetId)); - %assetBasePath = filePath(%assetPath); - - //clean up the path - %assetBasePath = strreplace(%assetBasePath, "//", "/"); - - %searchActive = AssetSearchTerms.count() != 0; - if(%assetBasePath $= %breadcrumbPath || (%searchActive && startsWith(%assetBasePath,%breadcrumbPath))) - { - //first, get the asset's module, as our major categories - %module = AssetDatabase.getAssetModule(%assetId); - %moduleName = %module.moduleId; - - //it's good, so test that the category is right! - %assetType = AssetDatabase.getAssetCategory(%assetId); - if(%assetType $= "") - { - %assetType = AssetDatabase.getAssetType(%assetId); - } - - //stop adding after previewsPerPage is hit - %assetName = AssetDatabase.getAssetName(%assetId); - - if(%searchActive) - { - if(matchesSearch(%assetName, %assetType)) - { - $AssetBrowser::AssetArray.add( %moduleName, %assetId); - - if(%assetType !$= "Folder") - %finalAssetCount++; - - continue; - } - } - else - { - if(AssetBrowser.assetTypeFilter !$= "") - { - %filtersCount = getWordCount(AssetBrowser.assetTypeFilter); - for(%fltrIdx = 0; %fltrIdx < %filtersCount; %fltrIdx++) + if(matchesSearch(%folderName, "Folder", "")) { - %fltr = getWord(AssetBrowser.assetTypeFilter, %fltrIdx); - if(%fltr $= %assetType) - { - $AssetBrowser::AssetArray.add( %moduleName, %assetId ); - - if(%assetType !$= "Folder") - %finalAssetCount++; + $AssetBrowser::AssetArray.add( %breadcrumbPath, "FolderObjectType" TAB %folderName ); + continue; } } - } else { //got it. - $AssetBrowser::AssetArray.add( %moduleName, %assetId ); - - if(%assetType !$= "Folder") - %finalAssetCount++; + if(%folderName $= "shaderCache" || %folderName $= "cache" || %folderName $= ".git") + continue; + + if(!%this.coreModulesFilter && %folderName $= "core" && %breadcrumbPath $= "") + continue; + + if(!%this.toolsModulesFilter && %folderName $= "tools" && %breadcrumbPath $= "") + continue; + + $AssetBrowser::AssetArray.add( %breadcrumbPath, "FolderObjectType" TAB %folderName ); } } } - } + + //now, we'll iterate through, and find the assets that are in this module, and this category + for( %i=0; %i < %numAssetsFound; %i++) + { + %assetId = %assetQuery.getAsset(%i); + + %assetPath = makeRelativePath(AssetDatabase.getAssetFilePath(%assetId)); + %assetBasePath = filePath(%assetPath); + + //clean up the path + %assetBasePath = strreplace(%assetBasePath, "//", "/"); + + %searchActive = AssetSearchTerms.count() != 0; + if(%assetBasePath $= %breadcrumbPath || (%searchActive && startsWith(%assetBasePath,%breadcrumbPath))) + { + //first, get the asset's module, as our major categories + %module = AssetDatabase.getAssetModule(%assetId); + %moduleName = %module.moduleId; + + //it's good, so test that the category is right! + %assetType = AssetDatabase.getAssetCategory(%assetId); + if(%assetType $= "") + { + %assetType = AssetDatabase.getAssetType(%assetId); + } + + //stop adding after previewsPerPage is hit + %assetName = AssetDatabase.getAssetName(%assetId); - //Add Non-Asset Scripted Objects. Datablock, etc based - %hasDBFilter = true; - if(AssetBrowser.assetTypeFilter !$= "") - { - %hasDBFilter = false; - %filterCount = getWordCount(AssetBrowser.assetTypeFilter); - for(%fltrIdx = 0; %fltrIdx < %filterCount; %fltrIdx++) - { - %fltr = getWord(AssetBrowser.assetTypeFilter, %fltrIdx); - if(%fltr $= "Datablock" || %fltr $= "Datablocks") - { - %hasDBFilter = true; - break; - } - } - } - if(%hasDBFilter && %breadcrumbPath !$= "" && isDirectory(%breadcrumbPath)) - { - %category = getWord( %breadcrumbPath, 1 ); - %dataGroup = "DataBlockGroup"; - - for ( %i = 0; %i < %dataGroup.getCount(); %i++ ) - { - %obj = %dataGroup.getObject(%i); - // echo ("Obj: " @ %obj.getName() @ " - " @ %obj.category ); - - //if ( %obj.category $= "" && %obj.category == 0 ) - // continue; - - %dbFilename = %obj.getFileName(); - %dbFilePath = filePath(%dbFilename); - - %searchActive = AssetSearchTerms.count() != 0; - if(%searchActive) - { - if(startsWith(%dbFilePath, %breadcrumbPath)) + if(%searchActive) { - %dbName = %obj.getName(); - if(matchesSearch(%dbName, "Datablock")) + if(matchesSearch(%assetName, %assetType)) { - $AssetBrowser::AssetArray.add( %dbFilename, "Datablock" TAB %dbName ); - } + $AssetBrowser::AssetArray.add( %moduleName, %assetId); + + if(%assetType !$= "Folder") + %finalAssetCount++; + + continue; + } + } + else + { + if(AssetBrowser.assetTypeFilter !$= "") + { + %filtersCount = getWordCount(AssetBrowser.assetTypeFilter); + for(%fltrIdx = 0; %fltrIdx < %filtersCount; %fltrIdx++) + { + %fltr = getWord(AssetBrowser.assetTypeFilter, %fltrIdx); + if(%fltr $= %assetType) + { + $AssetBrowser::AssetArray.add( %moduleName, %assetId ); + + if(%assetType !$= "FolderObjectType") + %finalAssetCount++; + } + } + } + else + { + //got it. + $AssetBrowser::AssetArray.add( %moduleName, %assetId ); + + if(%assetType !$= "FolderObjectType") + %finalAssetCount++; + } } } - else if(%dbFilePath $= %breadcrumbPath) - { - %dbName = %obj.getName(); - $AssetBrowser::AssetArray.add( %dbFilename, "Datablock" TAB %dbName ); - - /*%catItem = AssetBrowser-->filterTree.findItemByName(%obj.category); - - if(%catItem == 0) - AssetBrowser-->filterTree.insertItem(%scriptedItem, %obj.category, "scripted");*/ - /*%ctrl = %this.findIconCtrl( %obj.category ); - if ( %ctrl == -1 ) - { - %this.addFolderIcon( %obj.category ); - }*/ - } } - - %this.getLooseFilesInDir(); + if(!isObject(ABLooseFileArray)) + new ArrayObject(ABLooseFileArray){}; + + %nonAssetFileCount = getNonAssetFilesInDir(%this.dirHandler.currentAddress, ABLooseFileArray); %looseFiles = ABLooseFileArray.count(); for( %i=0; %i < %looseFiles; %i++) @@ -1694,136 +1715,92 @@ function AssetBrowser::doRebuildAssetArray(%this) %looseFileName = fileName(%looseFileFullPath); %looseFileExt = fileExt(%looseFileFullPath); - $AssetBrowser::AssetArray.add( %looseFilePath, "LooseFile" TAB %looseFileName ); - } - - //Prefabs - %expr = "*.prefab"; - %fullPrefabPath = findFirstFile( %breadcrumbPath @ "/" @ %expr ); - - while ( %fullPrefabPath !$= "" ) - { - %prefabPath = filePath(%fullPrefabPath); - %prefabName = fileName(%fullPrefabPath); - - %searchActive = AssetSearchTerms.count() != 0; - if(%searchActive) + //iterate over the registered types to filter out types we special handle + for(%t=0; %t < ABAssetTypesList.count(); %t++) { - if(startsWith(%prefabPath, %breadcrumbPath)) - { - if(matchesSearch(%prefabName, "Prefab")) - { - $AssetBrowser::AssetArray.add( %prefabPath, "Prefab" TAB %prefabName ); - } - } - } - else if(%prefabPath $= %breadcrumbPath) - { - $AssetBrowser::AssetArray.add( %prefabPath, "Prefab" TAB %prefabName ); - } + %typeGroup = ABAssetTypesList.getKey(%t); - %fullPrefabPath = findNextFile( %breadcrumbPath @ "/" @ %expr ); - } - - //C++ files - %cppPattern = %breadcrumbPath @ "/" @ "*.cpp"; - for (%fullCppPath = findFirstFile(%cppPattern); %fullCppPath !$= ""; %fullCppPath = findNextFile(%cppPattern)) - { - %cppPath = filePath(%fullCppPath); - %cppName = fileName(%fullCppPath); - - %searchActive = AssetSearchTerms.count() != 0; - if(%searchActive) - { - if(startsWith(%cppPath, %breadcrumbPath)) - { - if(matchesSearch(%cppName, "Cpp")) - { - $AssetBrowser::AssetArray.add( %cppPath, "Cpp" TAB %cppName ); - } - } - } - else if(%cppPath $= %breadcrumbPath) - { - $AssetBrowser::AssetArray.add( %cppPath, "Cpp" TAB %cppName ); - } - } - - //C++ Header files - %cppPattern = %breadcrumbPath @ "/" @ "*.h"; - for (%fullCppPath = findFirstFile(%cppPattern); %fullCppPath !$= ""; %fullCppPath = findNextFile(%cppPattern)) - { - %cppPath = filePath(%fullCppPath); - %cppName = fileName(%fullCppPath); - - %searchActive = AssetSearchTerms.count() != 0; - if(%searchActive) - { - if(startsWith(%cppPath, %breadcrumbPath)) - { - if(matchesSearch(%cppName, "Cpp")) - { - $AssetBrowser::AssetArray.add( %cppPath, "Cpp" TAB %cppName ); - } - } - } - else if(%cppPath $= %breadcrumbPath) - { - $AssetBrowser::AssetArray.add( %cppPath, "Cpp" TAB %cppName ); - } - } - - //script files - %tscriptPattern = %breadcrumbPath @ "/" @ "*.tscript"; - for (%fullScriptPath = findFirstFile(%tscriptPattern); %fullScriptPath !$= ""; %fullScriptPath = findNextFile(%tscriptPattern)) - { - //If it's associated to an asset, we'll want to do extra checks - %assetQuery = new AssetQuery(); - %foundAssets = AssetDatabase.findAssetLooseFile(%assetQuery, %fullScriptPath); - - if(%foundAssets != 0) - { - %doSkip = false; - %count = %assetQuery.getCount(); - for(%i=0; %i < %count; %i++) - { - %assetId = %assetQuery.getAsset(%i); - %foundAssetType = AssetDatabase.getAssetType(%assetId); - - if(%foundAssetType !$= "ScriptAsset" && %foundAssetType !$= "GUIAsset") - { - %doSkip = true; - break; - } - } + %typeEntryName = getField(ABAssetTypesList.getValue(%t), 0); + %filterDataList = getField(ABAssetTypesList.getValue(%t), 2); - if(%doSkip) - continue; - } - - %tscriptPath = filePath(%fullScriptPath); - %tscriptName = fileName(%fullScriptPath); - - %searchActive = AssetSearchTerms.count() != 0; - if(%searchActive) - { - if(startsWith(%tscriptPath, %breadcrumbPath)) + if(%typeGroup $= "Asset") { - if(matchesSearch(%tscriptName, "tscript")) + %classNameCount = getTokenCount(%filterDataList, ";"); + + for(%e=0; %e < %classNameCount; %e++) { - $AssetBrowser::AssetArray.add( %tscriptPath, "tscript" TAB %tscriptName ); - } + %className = getToken(%filterDataList, ";", %e); + + if(%className $= %looseFileExt) + { + if(matchesSearch(%looseFileName, %typeEntryName)) + $AssetBrowser::AssetArray.add( %looseFilePath, %typeEntryName TAB %looseFileName ); + } + } + } + else if(%typeGroup $= "File") + { + %extensionsCount = getTokenCount(%filterDataList, ";"); + + for(%e=0; %e < %extensionsCount; %e++) + { + %extension = getToken(%filterDataList, ";", %e); + + if(%extension $= %looseFileExt) + { + if(matchesSearch(%looseFileName, %typeEntryName)) + $AssetBrowser::AssetArray.add( %looseFilePath, %typeEntryName TAB %looseFileName ); + } + } + } + else if(%typeGroup $= "Object") + { + %classNameCount = getTokenCount(%filterDataList, ";"); + + //now we iterate over the root group to find any and all objects that match to class + for(%rgo = 0; %rgo < RootGroup.getCount(); %rgo++) + { + %rootGroupObj = RootGroup.getObject(%rgo); + %rootGroupObjPath = filePath(%rootGroupObj.getFileName()); + if(%rootGroupObjPath !$= %this.dirHandler.currentAddress) + continue; + + for(%c=0; %c < %classNameCount; %c++) + { + %className = getToken(%filterDataList, ";", %c); + + if(%rootGroupObj.isMemberOfClass(%className)) + { + if(matchesSearch(%className, %typeEntryName)) + $AssetBrowser::AssetArray.add( %rootGroupObj, %typeEntryName TAB %className ); + } + } + } + + //check the datablocks group for certainty as well` + for(%rgo = 0; %rgo < DatablockGroup.getCount(); %rgo++) + { + %dbGroupObject = DatablockGroup.getObject(%rgo); + %dbGroupObjPath = filePath(%dbGroupObject.getFileName()); + if(%dbGroupObjPath !$= %this.dirHandler.currentAddress) + continue; + + for(%c=0; %c < %classNameCount; %c++) + { + %className = getToken(%filterDataList, ";", %c); + + if(%dbGroupObject.isMemberOfClass(%className)) + { + if(matchesSearch(%className, %typeEntryName)) + $AssetBrowser::AssetArray.add( %dbGroupObject, %typeEntryName TAB %className ); + } + } + } } - } - else if(%tscriptPath $= %breadcrumbPath) - { - $AssetBrowser::AssetArray.add( %tscriptPath, "tscript" TAB %tscriptName ); } } } - - //If we've selected into the Creator section, we have special handling for that - if(startsWith(%breadcrumbPath, "Creator")) + else //If we've selected into the Creator section, we have special handling for that { //One of the creator folders was selected %creatorGroup = AssetBrowserFilterTree.getItemText(AssetBrowserFilterTree.getSelectedItem(0)); @@ -1835,9 +1812,9 @@ function AssetBrowser::doRebuildAssetArray(%this) } else { - for ( %i = 0; %i < AssetBrowser.creatorClassArray.count(); %i++ ) - { - %group = AssetBrowser.creatorClassArray.getKey( %i ); + for ( %i = 0; %i < %this.creatorClassArray.count(); %i++ ) + { + %group = %this.creatorClassArray.getKey( %i ); //Do some filter logic do skip out of groups if we're in the wrong editor mode for it %creatorEditorFilter = "WorldEditor"; @@ -1850,26 +1827,27 @@ function AssetBrowser::doRebuildAssetArray(%this) %creatorGroupKey = AssetBrowserCreatorGroupsList.getKey(%creatorGroupIndex); if ( %group $= %creatorGroup && %creatorGroupKey $= %creatorEditorFilter ) - { - %creatorObj = AssetBrowser.creatorClassArray.getValue( %i ); - %class = %creatorObj.val[0]; - %name = %creatorObj.val[1]; - %func = %creatorObj.val[2]; - + { + %creatorObj = %this.creatorClassArray.getValue( %i ); + %class = %creatorObj.val[0]; + %name = %creatorObj.val[1]; + %func = %creatorObj.val[2]; + %searchActive = AssetSearchTerms.count() != 0; if(%searchActive && !matchesSearch(%name, "Creator")) continue; - - $AssetBrowser::AssetArray.add( %name, "Creator" TAB %creatorObj ); - } - } - } + + $AssetBrowser::AssetArray.add( %name, "Creator" TAB %creatorObj ); + } + } + } } for(%i=0; %i < $AssetBrowser::AssetArray.count(); %i++) - AssetBrowser.buildAssetPreview( $AssetBrowser::AssetArray.getValue(%i), $AssetBrowser::AssetArray.getKey(%i) ); + %this.buildAssetPreview( $AssetBrowser::AssetArray.getValue(%i), $AssetBrowser::AssetArray.getKey(%i) ); + //Queue population of any non-Type Card preview images - AssetBrowser.schedule(32, "populatePreviewImages"); + %this.schedule(32, "populatePreviewImages"); AssetBrowser_FooterText.text = %finalAssetCount @ " Assets"; @@ -1878,13 +1856,14 @@ function AssetBrowser::doRebuildAssetArray(%this) { if(!AssetTypeListPopup.isItemChecked(0)) { - for(%f=1; %f < AssetFilterTypeList.Count(); %f++) + for(%f=0; %f < ABAssetTypesList.Count(); %f++) { - %isChecked = AssetTypeListPopup.isItemChecked(%f+1); + %isChecked = AssetTypeListPopup.isItemChecked(%f+2); if(%isChecked) { - %filterTypeName = AssetFilterTypeList.getKey(%f); + %filterTypeData = ABAssetTypesList.getKey(%f); + %filterTypeName = getField(%filterTypeData, 0); if(%activeTypeFilterList $= "") %activeTypeFilterList = %filterTypeName; @@ -2494,35 +2473,27 @@ function EWorldEditor::onControlDropped( %this, %payload, %position ) %assetType = %payload.assetType; - %pos = ObjectCreator.getCreateObjectPosition(); //LocalClientConnection.camera.position; - %module = %payload.moduleName; - %asset = %payload.assetName; + %createPosition = ObjectCreator.getCreateObjectPosition(); //LocalClientConnection.camera.position; + %targetPosition = EWorldEditor.unproject(%createPosition SPC 1); + %camPos = LocalClientConnection.camera.getPosition(); + %rayResult = containerRayCast(%camPos, %targetPosition, -1); - if(AssetBrowser.isMethod("on" @ %assetType @ "EditorDropped")) + %pos = ObjectCreator.getCreateObjectPosition(); + + if(%rayResult != 0) { - if(%assetType $= "Datablock") - { - %buildCommand = AssetBrowser @ ".on" @ %assetType @ "EditorDropped(" @ %asset @ ",\"" @ %pos @ "\");"; - } - else if(%assetType $= "Prefab") - { - %buildCommand = AssetBrowser @ ".on" @ %assetType @ "EditorDropped(\"" @ %module @ "/" @ %asset @ "\",\"" @ %pos @ "\");"; - } - else if(%assetType $= "Creator") - { - %buildCommand = AssetBrowser @ ".on" @ %assetType @ "EditorDropped(" @ %module @ ",\"" @ %pos @ "\");"; - } - else - { - %assetDef = AssetDatabase.acquireAsset(%module @ ":" @ %asset); - %buildCommand = AssetBrowser @ ".on" @ %assetType @ "EditorDropped(" @ %assetDef @ ",\"" @ %pos @ "\");"; - } - eval(%buildCommand); - - if(EditorSettings.value("AssetManagement/Assets/closeBrowserOnDragAction", false)) - { - AssetBrowser.hideDialog(); - } + %pos = getWords(%rayResult, 1, 3); + } + else + { + %pos = "0 0 0"; + } + + AssetBrowser.callAssetTypeFunc(%assetType, "onWorldEditorDropped", %payload.moduleName, %payload.assetName, %pos); + + if(EditorSettings.value("AssetManagement/Assets/closeBrowserOnDragAction", false)) + { + AssetBrowser.hideDialog(); } EWorldEditor.isDirty = true; @@ -2549,25 +2520,8 @@ function GuiEditor::onControlDropped(%this, %payload, %position) //dealing with an actual asset, so build the assetName %assetId = %payload.moduleName @ ":" @ %payload.assetName; %assetType = AssetDatabase.getAssetType(%assetId); - - if(AssetBrowser.isMethod("on" @ %assetType @ "GUIEditorDropped")) - { - %module = %payload.moduleName; - %asset = %payload.assetName; - %assetDef = AssetDatabase.acquireAsset(%module @ ":" @ %asset); - %buildCommand = AssetBrowser @ ".on" @ %assetType @ "GUIEditorDropped(" @ %assetDef @ ",\"" @ %pos @ "\");"; - eval(%buildCommand); - } - else - { - //fallback example - if(%assetType $= "ImageAsset") - { - %cmd = "return new guiBitmapCtrl();"; - %ctrl = eval( %cmd ); - %ctrl.bitmapAsset = %assetId; - } - } + + AssetBrowser.callAssetTypeFunc(%assetType, "GUIEditorDropped", %payload.moduleName, %payload.assetName, %pos); } else { @@ -2616,38 +2570,18 @@ function AssetBrowserFilterTree::onControlDropped( %this, %payload, %position ) if(%path !$= AssetBrowser.dirHandler.CurrentAddress) { - //we're trying to move the asset to a different module! - //toolsMessageBoxYesNo( "Move Asset", "Do you wish to move asset " @ %assetName @ " to " @ %path @ "?", - // "AssetBrowser.moveAsset(\""@ %moduleName @ ":" @ %assetName @"\", \""@%path@"\");", ""); - - if(%assetType $= "Folder") + if(getModuleFromAddress(%path) !$= getModuleFromAddress(AssetBrowser.dirHandler.CurrentAddress)) { - %originFolder = %moduleName @ "/" @ %assetName; - %path = %path @ "/" @ %assetName; - - //Do any cleanup required given the type - if(AssetBrowser.isMethod("moveFolder")) - { - eval(AssetBrowser @ ".moveFolder(\""@%originFolder@"\",\""@%path@"\");"); - - AssetBrowser.refresh(); - } + AssetBrowser.callAssetTypeFunc(%this.assetType, "onMoveModule", %this.moduleName, %this.assetName, %path); } else { - %assetId = %moduleName @ ":" @ %assetName; - %assetDef = AssetDatabase.acquireAsset(%assetId); - %assetType = AssetDatabase.getAssetType(%assetId); - - //Do any cleanup required given the type - if(AssetBrowser.isMethod("move"@%assetType)) - { - %command = AssetBrowser @ ".move" @ %assetType @ "(" @ %assetDef @ ",\"" @ %path @ "\");"; - eval(AssetBrowser @ ".move" @ %assetType @ "(" @ %assetDef @ ",\"" @ %path @ "\");"); - - AssetBrowser.refresh(); - } + AssetBrowser.callAssetTypeFunc(%this.assetType, "onMovePath", %this.moduleName, %this.assetName, %path); } + + //we're trying to move the asset to a different module! + //toolsMessageBoxYesNo( "Move Asset", "Do you wish to move asset " @ %assetName @ " to " @ %path @ "?", + // "AssetBrowser.moveAsset(\""@ %moduleName @ ":" @ %assetName @"\", \""@%path@"\");", ""); } } } @@ -2760,6 +2694,44 @@ function AssetBrowser::getLooseFilesInDir(%this) %aq.delete(); return false; } + +function getNonAssetFilesInDir(%path, %arrayObj) +{ + //echo("getNonAssetFilesInDir() - path: " @ %path); + + if(!isObject(%arrayObj)) + { + error("getNonAssetFilesInDir() - requires a valid arrayObject to place found non-Asset files into!"); + return 0; + } + + %arrayObj.empty(); + + //First, wipe out any files inside the folder first + %file = findFirstFileMultiExpr( %path @ "/*.*", false); + + %aq = new AssetQuery(); + + while( %file !$= "" ) + { + if(!strIsMatchExpr("*.asset.taml", %file) && !strIsMatchExpr("*.taml", %file) && !strIsMatchExpr("*.cached.dts", %file)) + { + %assetsFound = AssetDatabase.findAssetLooseFile(%aq, %file); + + if(%assetsFound == 0) + { + %arrayObj.add(%file); + } + } + + %file = findNextFileMultiExpr( %path @ "/*.*" ); + } + + %aq.delete(); + + return %arrayObj.count(); +} + // // function AssetBrowser::importLooseFiles(%this) diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/assetTypeExample.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/assetTypeExample.tscript deleted file mode 100644 index 907bb851c..000000000 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/assetTypeExample.tscript +++ /dev/null @@ -1,86 +0,0 @@ - -//Builds the preview data of the asset for the Asset Browser -function AssetBrowser::build_AssetPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = ""; - %previewData.doubleClickCommand = ""; - - %previewData.previewImage = "tools/assetBrowser/art/gameObjectIcon"; - - %previewData.assetFriendlyName = %assetDef.gameObjectName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = %assetDef.gameObjectName; -} - -//Some last-step setup for the creation of the new asset before we do the actual making -//This is generally intended to just set up any type-specific fields for creation -function AssetBrowser::setupCreateNew_Asset(%this) -{ -} - -//Performs the actual creation of the asset, including loose file copy or generation -function AssetBrowser::create_Asset(%this) -{ -} - -//This is a pre-process step to prepare the asset item for import -function AssetBrowser::prepareImport_Asset(%this, %assetItem) -{ - -} - -//Performs the action of actually importing the asset item -function AssetBrowser::import_Asset(%this, %assetDef) -{ -} - -//Editing the asset -function AssetBrowser::edit_Asset(%this, %assetDef) -{ -} - -//Duplicates the asset -function AssetBrowser::duplicate_Asset(%this, %assetDef, %targetModule) -{ -} - -//Renames the asset -function AssetBrowser::rename_Asset(%this, %assetDef, %newAssetName) -{ -} - -//Deletes the asset -function AssetBrowser::delete_Asset(%this, %assetDef) -{ -} - -//Moves the asset to a new path/module -function AssetBrowser::move_Asset(%this, %assetDef, %destinationFolder) -{ -} - -//Drag and drop action onto a GUI control -function AssetBrowser::dragAndDrop_Asset(%this, %assetDef, %dropTarget) -{ - if(!isObject(%dropTarget)) - return; -} - -//Even for when -function AssetBrowser::on_AssetEditorDropped(%this, %assetDef, %position) -{ -} - -//Clicking of the button for the asset type inspector field -function GuiInspectorType_AssetPtr::onClick( %this, %fieldName ) -{ - //Get our data - %obj = %this.getInspector().getInspectObject(0); -} - -//Drag and droppin onto the asset type inspector field -function GuiInspectorType_AssetPtr::onControlDropped( %this, %payload, %position ) -{ - -} \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/component.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/component.tscript deleted file mode 100644 index d443157ea..000000000 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/component.tscript +++ /dev/null @@ -1,143 +0,0 @@ -function AssetBrowser::createComponentAsset(%this) -{ - %moduleName = AssetBrowser.newAssetSettings.moduleName; - %modulePath = "data/" @ %moduleName; - - %assetName = AssetBrowser.newAssetSettings.assetName; - - %tamlpath = %modulePath @ "/components/" @ %assetName @ ".asset.taml"; - %scriptPath = %modulePath @ "/components/" @ %assetName @ "." @ $TorqueScriptFileExtension; - - %asset = new ComponentAsset() - { - AssetName = %assetName; - versionId = 1; - componentName = %assetName; - componentClass = AssetBrowser.newAssetSettings.parentClass; - friendlyName = AssetBrowser.newAssetSettings.friendlyName; - componentType = AssetBrowser.newAssetSettings.componentGroup; - description = AssetBrowser.newAssetSettings.description; - scriptFile = %assetName @ "." @ $TorqueScriptFileExtension; - }; - - TamlWrite(%asset, %tamlpath); - - %file = new FileObject(); - %templateFile = new FileObject(); - - %templateCodeFilePath = %this.templateFilesPath @ "componentFile." @ $TorqueScriptFileExtension @ ".template"; - - if(%file.openForWrite(%scriptPath) && %templateFile.openForRead(%templateCodeFilePath)) - { - while( !%templateFile.isEOF() ) - { - %line = %templateFile.readline(); - %line = strreplace( %line, "@@", %assetName ); - - %file.writeline(%line); - echo(%line); - } - - %file.close(); - %templateFile.close(); - } - else - { - %file.close(); - %templateFile.close(); - - warnf("CreateComponentAsset - Something went wrong and we couldn't write the Component script file!"); - } - - Canvas.popDialog(AssetBrowser_newComponentAsset); - - %moduleDef = ModuleDatabase.findModule(%moduleName, 1); - AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath); - - AssetBrowser.refresh(); - - return %tamlpath; -} - -function AssetBrowser::editComponentAsset(%this, %assetDef) -{ - %scriptFile = %assetDef.scriptFile; - - EditorOpenFileInTorsion(makeFullPath(%scriptFile), 0); -} - -function AssetBrowser::duplicateComponentAsset(%this, %assetId) -{ - -} - -function AssetBrowser::renameComponentAsset(%this, %assetDef, %newAssetId, %originalName, %newName) -{ - %assetPath = AssetDatabase.getAssetFilePath(%newAssetId); - - //rename the file to match - %path = filePath(%assetPath); - - %oldScriptFilePath = %assetDef.scriptFile; - %scriptFilePath = filePath(%assetDef.scriptFile); - %scriptExt = fileExt(%assetDef.scriptFile); - - %newScriptFileName = %scriptFilePath @ "/" @ %newName @ %scriptExt; - %newAssetFile = %path @ "/" @ %newName @ ".asset.taml"; - - %assetDef.componentName = %newName; - %assetDef.scriptFile = %newScriptFileName; - - TamlWrite(%assetDef, %newAssetFile); - fileDelete(%assetPath); - - pathCopy(%oldScriptFilePath, %newScriptFileName); - fileDelete(%oldScriptFilePath); - - //Go through our scriptfile and replace the old namespace with the new - %editedFileContents = ""; - - %file = new FileObject(); - if ( %file.openForRead( %newScriptFileName ) ) - { - while ( !%file.isEOF() ) - { - %line = %file.readLine(); - %line = trim( %line ); - - %editedFileContents = %editedFileContents @ strreplace(%line, %originalName, %newName) @ "\n"; - } - - %file.close(); - } - - if(%editedFileContents !$= "") - { - %file.openForWrite(%newScriptFileName); - - %file.writeline(%editedFileContents); - - %file.close(); - } - - exec(%newScriptFileName); -} - -//not used -function AssetBrowser::importComponentAsset(%this, %assetId) -{ - -} - -function AssetBrowser::buildComponentAssetPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.scriptFile; - %previewData.doubleClickCommand = "EditorOpenFileInTorsion( "@%previewData.assetPath@", 0 );"; - - %previewData.previewImage = "ToolsModule:componentIcon_image"; - - %previewData.assetFriendlyName = %assetDef.friendlyName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = %assetDef.friendlyName @ "\n" @ %assetDef; -} diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/cpp.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/cpp.tscript index da45e2059..ce28531c6 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/cpp.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/cpp.tscript @@ -1,44 +1,21 @@ -function AssetBrowser::buildCppPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.codeFilePath; - %previewData.doubleClickCommand = "echo(\"Not yet implemented to edit C++ files from the editor\");";//"EditorOpenFileInTorsion( "@%previewData.assetPath@", 0 );"; - - %previewData.previewImage = "ToolsModule:cppIcon_image"; - - %previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = %assetDef.assetName; -} +AssetBrowser::registerAssetType("CppAsset", "C++ Assets", ""); +AssetBrowser::registerFileType("CPPFileType", "C++ Files", ".cpp;.h;.c", false); -function AssetBrowser::buildCppAssetPreview(%this, %assetDef, %previewData) +function CppAsset::onCreateNew() { - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.codeFilePath; - %previewData.doubleClickCommand = "echo(\"Not yet implemented to edit C++ files from the editor\");";//"EditorOpenFileInTorsion( "@%previewData.assetPath@", 0 );"; - - %previewData.previewImage = "ToolsModule:cppIcon_image"; - - %previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = %assetDef.assetName; -} - -function AssetBrowser::createCppAsset(%this) -{ - %moduleName = AssetBrowser.newAssetSettings.moduleName; + %moduleName = $CurrentAssetBrowser.newAssetSettings.moduleName; %modulePath = "data/" @ %moduleName; - %assetName = AssetBrowser.newAssetSettings.assetName; + %assetName = $CurrentAssetBrowser.newAssetSettings.assetName; %assetPath = NewAssetTargetAddress.getText() @ "/"; - //%tamlpath = %assetPath @ %assetName @ ".asset.taml"; + %tamlpath = %assetPath @ %assetName @ ".asset.taml"; %codePath = %assetPath @ %assetName @ ".cpp"; %headerPath = %assetPath @ %assetName @ ".h"; //Do the work here - /*%assetType = AssetBrowser.newAssetSettings.assetType; + //%assetType = $CurrentAssetBrowser.newAssetSettings.assetType; %asset = new CppAsset() { @@ -48,7 +25,7 @@ function AssetBrowser::createCppAsset(%this) headerFile = %headerPath; }; - TamlWrite(%asset, %tamlpath);*/ + TamlWrite(%asset, %tamlpath); %tamlpath = %assetPath @ %assetName @ ".asset.taml"; @@ -67,28 +44,28 @@ function AssetBrowser::createCppAsset(%this) if($AssetBrowser::newAssetTypeOverride $= "StaticClass") { - %cppTemplateCodeFilePath = %this.templateFilesPath @ "CppStaticClassFile.cpp.template"; - %cppTemplateHeaderFilePath = %this.templateFilesPath @ "CppStaticClassFile.h.template"; + %cppTemplateCodeFilePath = $CurrentAssetBrowser.templateFilesPath @ "CppStaticClassFile.cpp.template"; + %cppTemplateHeaderFilePath = $CurrentAssetBrowser.templateFilesPath @ "CppStaticClassFile.h.template"; } else if($AssetBrowser::newAssetTypeOverride $= "ScriptClass") { - %cppTemplateCodeFilePath = %this.templateFilesPath @ "CppScriptClassFile.cpp.template"; - %cppTemplateHeaderFilePath = %this.templateFilesPath @ "CppScriptClassFile.h.template"; + %cppTemplateCodeFilePath = $CurrentAssetBrowser.templateFilesPath @ "CppScriptClassFile.cpp.template"; + %cppTemplateHeaderFilePath = $CurrentAssetBrowser.templateFilesPath @ "CppScriptClassFile.h.template"; } else if($AssetBrowser::newAssetTypeOverride $= "AssetTypeCppClass") { - %cppTemplateCodeFilePath = %this.templateFilesPath @ "CppAssetTypeClassFile.cpp.template"; - %cppTemplateHeaderFilePath = %this.templateFilesPath @ "CppAssetTypeClassFile.h.template"; + %cppTemplateCodeFilePath = $CurrentAssetBrowser.templateFilesPath @ "CppAssetTypeClassFile.cpp.template"; + %cppTemplateHeaderFilePath = $CurrentAssetBrowser.templateFilesPath @ "CppAssetTypeClassFile.h.template"; } else if($AssetBrowser::newAssetTypeOverride $= "RenderCppClass") { - %cppTemplateCodeFilePath = %this.templateFilesPath @ "CppRenderClassFile.cpp.template"; - %cppTemplateHeaderFilePath = %this.templateFilesPath @ "CppRenderClassFile.h.template"; + %cppTemplateCodeFilePath = $CurrentAssetBrowser.templateFilesPath @ "CppRenderClassFile.cpp.template"; + %cppTemplateHeaderFilePath = $CurrentAssetBrowser.templateFilesPath @ "CppRenderClassFile.h.template"; } else if($AssetBrowser::newAssetTypeOverride $= "SceneObjectCppClass") { - %cppTemplateCodeFilePath = %this.templateFilesPath @ "CppSceneObjectClassFile.cpp.template"; - %cppTemplateHeaderFilePath = %this.templateFilesPath @ "CppSceneObjectClassFile.h.template"; + %cppTemplateCodeFilePath = $CurrentAssetBrowser.templateFilesPath @ "CppSceneObjectClassFile.cpp.template"; + %cppTemplateHeaderFilePath = $CurrentAssetBrowser.templateFilesPath @ "CppSceneObjectClassFile.h.template"; } $AssetBrowser::newAssetTypeOverride = ""; @@ -101,7 +78,6 @@ function AssetBrowser::createCppAsset(%this) %line = strreplace( %line, "@", %assetName ); %file.writeline(%line); - //echo(%line); } %file.close(); @@ -134,7 +110,7 @@ function AssetBrowser::createCppAsset(%this) %file.close(); %templateFile.close(); - warnf("CreateNewCppAsset - Something went wrong and we couldn't write the C++ header file!"); + warn("CreateNewCppAsset - Something went wrong and we couldn't write the C++ header file!"); } //Last, check that we have a C++ Module definition. If not, make one so anything important can be initialized on startup there @@ -144,7 +120,7 @@ function AssetBrowser::createCppAsset(%this) %file = new FileObject(); %templateFile = new FileObject(); - if(%file.openForWrite(%cppModuleFilePath) && %templateFile.openForRead(%this.templateFilesPath @ "CppModuleFile.cpp")) + if(%file.openForWrite(%cppModuleFilePath) && %templateFile.openForRead($CurrentAssetBrowser.templateFilesPath @ "CppModuleFile.cpp")) { while( !%templateFile.isEOF() ) { @@ -163,57 +139,133 @@ function AssetBrowser::createCppAsset(%this) %file.close(); %templateFile.close(); - warnf("CreateNewCppAsset - Something went wrong and we couldn't write the C++ module file!"); + warn("CreateNewCppAsset - Something went wrong and we couldn't write the C++ module file!"); } } return ""; } -function AssetBrowser::editCppAsset(%this, %assetDef) +function CppAsset::buildBrowserElement(%this, %previewData) { + %previewData.assetName = %this.assetName; + %previewData.assetPath = %this.codeFilePath; + //%previewData.doubleClickCommand = "echo(\"Not yet implemented to edit C++ files from the editor\");";//"EditorOpenFileInTorsion( "@%previewData.assetPath@", 0 );"; + + %previewData.previewImage = "ToolsModule:cppIcon_image"; + + %previewData.assetFriendlyName = %this.assetName; + %previewData.assetDesc = %this.description; + %previewData.tooltip = %this.assetName; } -//Renames the asset -function AssetBrowser::renameCppAsset(%this, %assetDef, %newAssetName) +function CppAsset::onEditCodeFile(%this, %filePath) { - %newCodeLooseFilename = renameAssetLooseFile(%assetDef.codefile, %newAssetName); - - if(!%newCodeLooseFilename $= "") - return; - - %newHeaderLooseFilename = renameAssetLooseFile(%assetDef.headerFile, %newAssetName); - - if(!%newHeaderLooseFilename $= "") - return; - - %assetDef.codefile = %newCodeLooseFilename; - %assetDef.headerFile = %newHeaderLooseFilename; - %assetDef.saveAsset(); - - renameAssetFile(%assetDef, %newAssetName); + if(isFunction("systemCommand")) + eval("systemCommand(\"start \\\"\\\" \\\"" @ %this.getCodeFile() @ "\\\"\");"); + else + warn("CppAsset::onEditCodeFile() - systemCommand function disabled in this build. Unable to launch application to edit file."); } -//Deletes the asset -function AssetBrowser::deleteCppAsset(%this, %assetDef) +function CppAsset::onEditHeaderFile(%this, %filePath) { - AssetDatabase.deleteAsset(%assetDef.getAssetId(), true); + if(isFunction("systemCommand")) + eval("systemCommand(\"start \\\"\\\" \\\"" @ %this.getHeaderFile() @ "\\\"\");"); + else + warn("CppAsset::onEditHeaderFile() - systemCommand function disabled in this build. Unable to launch application to edit file."); } -//Moves the asset to a new path/module -function AssetBrowser::moveCppAsset(%this, %assetDef, %destination) +function CppAsset::onShowActionMenu(%this) { - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); + GenericAsset::onShowActionMenu(%this); - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; + if( !isObject( EditCPPFilesSubmenuPopup ) ) + { + new PopupMenu( EditCPPFilesSubmenuPopup ) + { + superClass = "MenuBuilder"; + class = "EditorWorldMenu"; - moveAssetLooseFile(%assetDef.codeFile, %destination); - moveAssetLooseFile(%assetDef.headerFile, %destination); + jumpFileName = ""; + jumpLineNumber = ""; + }; + } - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); + //Regen the menu so we're fully up and current with options and references + EditCPPFilesSubmenuPopup.clearItems(); + + EditCPPFilesSubmenuPopup.item[ 0 ] = "Code file" TAB "" TAB %this @ ".onEditCodeFile();"; + EditCPPFilesSubmenuPopup.item[ 1 ] = "Header file" TAB "" TAB %this @ ".onEditHeaderFile();"; + + EditCPPFilesSubmenuPopup.reloadItems(); + + EditAssetPopup.item[ 0 ] = "Edit C++ Files" TAB EditCPPFilesSubmenuPopup; + + EditAssetPopup.reloadItems(); + + EditAssetPopup.showPopup(Canvas); + + $CurrentAssetBrowser.popupMenu = EditAssetPopup; } +//============================================================================== +function CPPFileType::buildBrowserElement(%filePath, %previewData) +{ + %previewData.assetName = fileName(%filePath); + %previewData.assetPath = %filePath; + //%previewData.doubleClickCommand = "echo(\"Not yet implemented to edit C++ files from the editor\");";//"EditorOpenFileInTorsion( "@%previewData.assetPath@", 0 );"; + + %previewData.previewImage = "ToolsModule:cppIcon_image"; + + %previewData.assetFriendlyName = %previewData.assetName; + %previewData.assetDesc = %filePath; + %previewData.tooltip = %filePath; +} + +function CPPFileType::onEdit(%filePath) +{ + if(isFunction("systemCommand")) + eval("systemCommand(\"start \\\"\\\" \\\"" @ %filePath @ "\\\"\");"); + else + warn("CPPFileType::onEdit() - systemCommand function disabled in this build. Unable to launch application to edit file."); +} + +function CPPFileType::onShowActionMenu(%filePath) +{ + if( !isObject( EditCPPFileTypePopup ) ) + { + new PopupMenu( EditCPPFileTypePopup ) + { + superClass = "MenuBuilder"; + class = "EditorWorldMenu"; + + jumpFileName = ""; + jumpLineNumber = ""; + }; + } + + //Regen the menu so we're fully up and current with options and references + EditCPPFileTypePopup.clearItems(); + + EditCPPFileTypePopup.item[ 0 ] = "Edit C++ File" TAB "" TAB $CurrentAssetBrowser @ ".editAsset();"; + EditCPPFileTypePopup.item[ 1 ] = "Rename File" TAB "" TAB $CurrentAssetBrowser @ ".renameAsset();"; + EditCPPFileTypePopup.item[ 2 ] = "-"; + EditCPPFileTypePopup.item[ 3 ] = "Duplicate File" TAB "" TAB $CurrentAssetBrowser @ ".duplicateAsset();"; + EditCPPFileTypePopup.item[ 4 ] = "-"; + EditCPPFileTypePopup.item[ 5 ] = "Open File Location" TAB "" TAB $CurrentAssetBrowser @ ".openFileLocation();"; + EditCPPFileTypePopup.item[ 6 ] = "-"; + EditCPPFileTypePopup.item[ 7 ] = "Delete File" TAB "" TAB $CurrentAssetBrowser @ ".deleteAsset();"; + + EditCPPFileTypePopup.objectData = %filePath; + EditCPPFileTypePopup.objectType = "CPPFileType"; + + EditCPPFileTypePopup.reloadItems(); + + EditCPPFileTypePopup.showPopup(Canvas); + + $CurrentAssetBrowser.popupMenu = EditCPPFileTypePopup; +} + +function CPPFileType::onEditProperties(%this, %inspector) +{ + +} \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/cubemap.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/cubemap.tscript index 95872ca8d..067ececc5 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/cubemap.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/cubemap.tscript @@ -1,9 +1,11 @@ -function AssetBrowser::createCubemapAsset(%this) +AssetBrowser::registerAssetType("CubemapAsset", "Cubemaps"); + +function CubemapAsset::onCreateNew() { Canvas.pushDialog(CubemapEditor); return; - %moduleName = AssetBrowser.newAssetSettings.moduleName; + /*%moduleName = AssetBrowser.newAssetSettings.moduleName; %modulePath = "data/" @ %moduleName; %assetName = AssetBrowser.newAssetSettings.assetName; @@ -30,57 +32,13 @@ function AssetBrowser::createCubemapAsset(%this) AssetBrowser.refresh(); - return %tamlpath; + return %tamlpath;*/ } -function AssetBrowser::editCubemapAsset(%this, %assetDef) +function CubemapAsset::onEdit(%this) { %this.hideDialog(); - CubemapEditor.openCubemapAsset(%assetDef); -} - -//Renames the asset -function AssetBrowser::renameCubemapAsset(%this, %assetDef, %newAssetName) -{ - /*%newCodeLooseFilename = renameAssetLooseFile(%assetDef.codefile, %newAssetName); - - if(!%newCodeLooseFilename $= "") - return; - - %newHeaderLooseFilename = renameAssetLooseFile(%assetDef.headerFile, %newAssetName); - - if(!%newHeaderLooseFilename $= "") - return; - - %assetDef.codefile = %newCodeLooseFilename; - %assetDef.headerFile = %newHeaderLooseFilename; - %assetDef.saveAsset(); - - renameAssetFile(%assetDef, %newAssetName);*/ -} - -//Deletes the asset -function AssetBrowser::deleteCubemapAsset(%this, %assetDef) -{ - AssetDatabase.deleteAsset(%assetDef.getAssetId(), true); -} - -//Moves the asset to a new path/module -function AssetBrowser::moveCubemapAsset(%this, %assetDef, %destination) -{ - /*%currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.codeFile, %destination); - moveAssetLooseFile(%assetDef.headerFile, %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath);*/ + CubemapEditor.openCubemapAsset(%this); } function GuiInspectorTypeCubemapAssetPtr::onControlDropped( %this, %payload, %position ) diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/datablockObjects.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/datablockObjects.tscript index c9ee2c2d6..d46aeac57 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/datablockObjects.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/datablockObjects.tscript @@ -1,54 +1,29 @@ -function AssetBrowser::createNewDatablock(%this) -{ - AssetBrowser_newFolderNameTxt.text = "NewFolder"; - Canvas.pushDialog(AssetBrowser_newFolder); -} +AssetBrowser::registerObjectType("DatablockObjectType", "Datablock Objects", "GameBaseData"); -function AssetBrowser::doCreateNewDatablock(%this) +function DatablockObjectType::onEdit(%this, %className) { - %newFolderName = AssetBrowser_newFolderNameTxt.getText(); - - if(%newFolderName $= "") - %newFolderName = "NewFolder"; - - %newFolderIdx = ""; - %matched = true; - %newFolderPath = ""; - while(%matched == true) + if(EditorSettings.value("Assets/Browser/doubleClickAction", "Edit Asset") $= "Edit Asset") { - %newFolderPath = AssetBrowser.dirHandler.currentAddress @ "/" @ %newFolderName @ %newFolderIdx; - if(!isDirectory(%newFolderPath)) - { - %matched = false; - } - else - { - %newFolderIdx++; - } + $CurrentAssetBrowser.hideDialog(); + + DatablockEditorPlugin.openDatablock(%this); } - - //make a dummy file - %file = new FileObject(); - %file.openForWrite(%newFolderPath @ "/test"); - %file.close(); - - fileDelete(%newFolderPath @ "/test"); - - //refresh the directory - AssetBrowser.loadDirectories(); - - %this.navigateTo(%newFolderPath); + else + { + %this.onWorldEditorDropped(); + } } -function AssetBrowser::buildDatablockPreview(%this, %assetDef, %previewData) +function DatablockObjectType::buildBrowserElement(%this, %className, %previewData) { - %previewData.assetName = %assetDef; - %previewData.assetPath = ""; + echo("DatablockObjectType::buildBrowserElement() - " @ %this @ ", " @ %previewData); + %previewData.assetName = %this.getName(); + %previewData.assetPath = %this.getFileName(); %previewData.previewImage = "ToolsModule:datablockIcon_image"; //Lets see if we have a icon for specifically for this datablock type - %dataClass = %assetDef.getClassName(); + %dataClass = %this.getClassName(); %dataClass = strreplace(%dataClass, "Data", ""); %previewImage = "tools/classIcons/" @ %dataClass @ ".png"; @@ -58,27 +33,42 @@ function AssetBrowser::buildDatablockPreview(%this, %assetDef, %previewData) } //%previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef; - %previewData.tooltip = "\nDatablock Name: " @ %assetDef @ - "\nDatablock Type: " @ %assetDef.getClassName() @ - "\nDefinition Path: " @ %assetDef.getFilename(); + %previewData.assetDesc = %this; + %previewData.tooltip = "\nDatablock Name: " @ %previewData.assetName @ + "\nDatablock Type: " @ %dataClass @ + "\nDefinition Path: " @ %previewData.assetPath; +} + +function DatablockObjectType::onShowActionMenu(%this, %className) +{ + if( !isObject( EditDatablockObjectTypePopup ) ) + { + new PopupMenu( EditDatablockObjectTypePopup ) + { + superClass = "MenuBuilder"; + class = "EditorWorldMenu"; + + jumpFileName = ""; + jumpLineNumber = ""; + }; + } - if(%this.selectMode) - { - %previewData.doubleClickCommand = "AssetBrowser.selectAsset( AssetBrowser.selectedAsset );"; - } - else - { - if(EditorSettings.value("Assets/Browser/doubleClickAction", "Edit Asset") $= "Edit Asset") - { - %previewData.doubleClickCommand = "DatablockEditorPlugin.openDatablock( "@%assetDef@" );"; - } - else - { - %previewData.doubleClickCommand = "AssetBrowser.onDatablockEditorDropped( "@%assetDef@" );"; - } - } + EditDatablockObjectTypePopup.objectData = %this; + EditDatablockObjectTypePopup.objectType = "DatablockObjectType"; + + //Regen the menu so we're fully up and current with options and references + EditDatablockObjectTypePopup.clearItems(); + + EditDatablockObjectTypePopup.item[ 0 ] = "Edit Datablock" TAB "" TAB $CurrentAssetBrowser @ ".editAsset();"; + EditDatablockObjectTypePopup.item[ 1 ] = "-"; + EditDatablockObjectTypePopup.item[ 2 ] = "Open Datablock Location" TAB "" TAB $CurrentAssetBrowser @ ".openFolderLocation(" @ %this.getFilename() @ ");"; + + EditDatablockObjectTypePopup.reloadItems(); + + EditDatablockObjectTypePopup.showPopup(Canvas); + + $CurrentAssetBrowser.popupMenu = EditDatablockObjectTypePopup; } function spawnDatablockObject(%datablock) @@ -92,96 +82,8 @@ function spawnDatablockObject(%datablock) return eval(%createCmd);//eval("showImportDialog( \"" @ %shapePath @ "\", \"" @ %createCmd @ "\" );"); } -function AssetBrowser::renameDatablock(%this, %folderPath, %newFolderName) +function DatablockObjectType::onWorldEditorDropped(%this, %position) { - %fullPath = makeFullPath(%folderPath); - %newFullPath = makeFullPath(%folderPath); - - %fullPath = strreplace(%fullPath, "//", "/"); - - %count = getTokenCount(%fullPath, "/"); - %basePath = getTokens(%fullPath, "/", 0, %count-2); - %oldName = getToken(%fullPath, "/", %count-1); - - //We need to ensure that no files are 'active' while we try and clean up behind ourselves with the delete action - //so, we nix any assets active for the module, do the delete action on the old folder, and then re-acquire our assets. - //This will have the added benefit of updating paths for asset items - - %module = AssetBrowser.dirHandler.getModuleFromAddress(AssetBrowser.dirHandler.currentAddress); - %moduleId = %module.ModuleId; - - AssetDatabase.removeDeclaredAssets(%moduleId); - - %copiedSuccess = %this.dirHandler.copyDatablock(%fullPath, %basePath @ "/" @ %newFolderName); - %this.dirHandler.deleteDatablock(%fullPath); - - %this.loadDirectories(); - - AssetDatabase.addModuleDeclaredAssets(%moduleId); -} - -function AssetBrowser::moveDatablock(%this, %folderPath, %newFolderPath) -{ - %fullPath = makeFullPath(%folderPath); - %newFullPath = makeFullPath(%newFolderPath); - - %fullPath = strreplace(%fullPath, "//", "/"); - %newFullPath = strreplace(%newFullPath, "//", "/"); - - %count = getTokenCount(%fullPath, "/"); - %basePath = getTokens(%fullPath, "/", 0, %count-2); - %oldName = getToken(%fullPath, "/", %count-1); - - %copiedSuccess = %this.dirHandler.copyDatablock(%fullPath, %newFullPath); - %this.dirHandler.deleteDatablock(%fullPath); - - %this.loadDirectories(); - - //thrash the modules and reload them - %oldModule = %this.dirHandler.getModuleFromAddress(%folderPath); - %newModule = %this.dirHandler.getModuleFromAddress(%newFolderPath); - - //if we didn't move modules, then we don't need to do anything other than refresh the assets within it - if(%oldModule == %newModule) - { - //only do a refresh to update asset loose file paths - AssetDatabase.refreshAllAssets(); - } - else - { - //they're different moduels now, so we gotta unload/reload both - ModuleDatabase.unloadExplicit(%oldModule.getModuleId()); - ModuleDatabase.loadExplicit(%oldModule.getModuleId()); - - ModuleDatabase.unloadExplicit(%newModule.getModuleId()); - ModuleDatabase.loadExplicit(%newModule.getModuleId()); - } -} - -function AssetBrowser::deleteDatablock(%this, %folderPath) -{ - %this.dirHandler.deleteDatablock(%folderPath); - - %this.refresh(); -} - -function AssetBrowser::onDatablockEditorDropped(%this, %assetDef, %position) -{ - %targetPosition = EWorldEditor.unproject(%position SPC 1); - %camPos = LocalClientConnection.camera.getPosition(); - %rayResult = containerRayCast(%camPos, %targetPosition, -1); - - %pos = ObjectCreator.getCreateObjectPosition(); - - if(%rayResult != 0) - { - %pos = getWords(%rayResult, 1, 3); - } - else - { - %pos = "0 0 0"; - } - - %newObj = spawnDatablockObject(%assetDef); - %newObj.position = %pos; + %newObj = spawnDatablockObject(%this); + %newObj.position = %position; } \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/decal.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/decal.tscript deleted file mode 100644 index e69de29bb..000000000 diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/explosion.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/explosion.tscript deleted file mode 100644 index e69de29bb..000000000 diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/folder.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/folder.tscript index 8817cc337..0dd37bf1b 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/folder.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/folder.tscript @@ -1,4 +1,6 @@ -function AssetBrowser::createNewFolder(%this) +AssetBrowser::registerFileType("FolderObjectType", "Folder", "/", false); + +function FolderObjectType::setupCreateNew() { AssetBrowser_newFolderNameTxt.text = "NewFolder"; Canvas.pushDialog(AssetBrowser_newFolder, 99, true); @@ -6,7 +8,7 @@ function AssetBrowser::createNewFolder(%this) AssetBrowser_newFolderNameTxt.selectAllText(); } -function AssetBrowser::doCreateNewFolder(%this) +function FolderObjectType::onCreateNew() { %newFolderName = AssetBrowser_newFolderNameTxt.getText(); @@ -19,7 +21,7 @@ function AssetBrowser::doCreateNewFolder(%this) } else { - %currentAddressPath = AssetBrowser.dirHandler.currentAddress; + %currentAddressPath = $CurrentAssetBrowser.dirHandler.currentAddress; } %newFolderIdx = ""; @@ -46,29 +48,65 @@ function AssetBrowser::doCreateNewFolder(%this) fileDelete(%newFolderPath @ "/test"); //refresh the directory - AssetBrowser.loadDirectories(); + $CurrentAssetBrowser.loadDirectories(); - %this.navigateTo(%newFolderPath); + $CurrentAssetBrowser.navigateTo(%newFolderPath); //On the off chance we're trying to select a path, we'll update the select path window too if(SelectAssetPath.isAwake()) SelectAssetPath.showDialog(%newFolderPath, SelectAssetPath.callback); } -function AssetBrowser::buildFolderPreview(%this, %assetDef, %previewData) +function FolderObjectType::buildBrowserElement(%folderPath, %previewData) { - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.dirPath; + %folderName = fileBase(%folderPath); + + %previewData.assetName = %folderName; + %previewData.assetPath = %folderPath; %previewData.previewImage = "ToolsModule:FolderIcon_image"; //%previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = %assetDef.dirPath; - %previewData.doubleClickCommand = "AssetBrowser.schedule(10, \"navigateTo\",\""@ %assetDef.dirPath @ "/" @ %assetDef.assetName @"\");";//browseTo %assetDef.dirPath / %assetDef.assetName + %previewData.assetDesc = "Folder"; + %previewData.tooltip = %folderPath; + %previewData.doubleClickCommand = "AssetBrowser.schedule(10, \"navigateTo\",\""@ %folderPath @"\");"; //browseTo %this.dirPath / %this.assetName } -function AssetBrowser::renameFolder(%this, %folderPath, %newFolderName) +function FolderObjectType::onShowActionMenu(%folderPath) +{ + if( !isObject( EditFolderTypePopup ) ) + { + new PopupMenu( EditFolderTypePopup ) + { + superClass = "MenuBuilder"; + class = "EditorWorldMenu"; + + jumpFileName = ""; + jumpLineNumber = ""; + }; + } + + EditFolderTypePopup.objectData = %folderPath; + EditFolderTypePopup.objectType = "FolderObjectType"; + + //Regen the menu so we're fully up and current with options and references + EditFolderTypePopup.clearItems(); + + EditFolderTypePopup.item[ 0 ] = "Rename Folder" TAB "" TAB $CurrentAssetBrowser @ ".renameAsset();"; + EditFolderTypePopup.item[ 1 ] = "Duplicate Folder" TAB "" TAB $CurrentAssetBrowser @ ".duplicateAsset();"; + EditFolderTypePopup.item[ 2 ] = "-"; + EditFolderTypePopup.item[ 3 ] = "Open Folder Location" TAB "" TAB $CurrentAssetBrowser @ ".openFolderLocation(" @ %folderPath @ ");"; + EditFolderTypePopup.item[ 4 ] = "-"; + EditFolderTypePopup.item[ 5 ] = "Delete Folder" TAB "" TAB $CurrentAssetBrowser @ ".deleteAsset();"; + + EditFolderTypePopup.reloadItems(); + + EditFolderTypePopup.showPopup(Canvas); + + $CurrentAssetBrowser.popupMenu = EditFolderTypePopup; +} + +function FolderObjectType::onRename(%folderPath, %newFolderName) { %fullPath = makeFullPath(%folderPath); %newFullPath = makeFullPath(%folderPath); @@ -83,23 +121,40 @@ function AssetBrowser::renameFolder(%this, %folderPath, %newFolderName) //so, we nix any assets active for the module, do the delete action on the old folder, and then re-acquire our assets. //This will have the added benefit of updating paths for asset items - %module = AssetBrowser.dirHandler.getModuleFromAddress(AssetBrowser.dirHandler.currentAddress); + %module = $CurrentAssetBrowser.dirHandler.getModuleFromAddress($CurrentAssetBrowser.dirHandler.currentAddress); %moduleId = %module.ModuleId; - AssetDatabase.removeDeclaredAssets(%moduleId); + $CurrentAssetBrowser.removeDeclaredAssets(%moduleId); - %copiedSuccess = %this.dirHandler.copyFolder(%fullPath, %basePath @ "/" @ %newFolderName); - %this.dirHandler.deleteFolder(%fullPath); + %copiedSuccess = $CurrentAssetBrowser.dirHandler.copyFolder(%fullPath, %basePath @ "/" @ %newFolderName); + $CurrentAssetBrowser.dirHandler.deleteFolder(%fullPath); - %this.loadDirectories(); + $CurrentAssetBrowser.loadDirectories(); - AssetDatabase.addModuleDeclaredAssets(%moduleId); + $CurrentAssetBrowser.addModuleDeclaredAssets(%moduleId); } -function AssetBrowser::moveFolder(%this, %folderPath, %newFolderPath) +function FolderObjectType::onDelete(%folderPath) +{ + $CurrentAssetBrowser.dirHandler.deleteFolder(%folderPath); + + $CurrentAssetBrowser.refresh(); +} + +function FolderObjectType::onWorldEditorDropped(%folderPath, %position) +{ + //We do nothing with this as we don't process entire folders for spawning +} + +function FolderObjectType::onGuiEditorDropped(%folderPath, %position) +{ + //We do nothing with this as we don't process entire folders for spawning +} + +function FolderObjectType::onMovePath(%folderPath, %destinationPath) { %fullPath = makeFullPath(%folderPath); - %newFullPath = makeFullPath(%newFolderPath); + %newFullPath = makeFullPath(%destinationPath); %fullPath = strreplace(%fullPath, "//", "/"); %newFullPath = strreplace(%newFullPath, "//", "/"); @@ -108,14 +163,20 @@ function AssetBrowser::moveFolder(%this, %folderPath, %newFolderPath) %basePath = getTokens(%fullPath, "/", 0, %count-2); %oldName = getToken(%fullPath, "/", %count-1); - %copiedSuccess = %this.dirHandler.copyFolder(%fullPath, %newFullPath); - %this.dirHandler.deleteFolder(%fullPath); + %copiedSuccess = $CurrentAssetBrowser.dirHandler.copyFolder(%fullPath, %newFullPath); + $CurrentAssetBrowser.dirHandler.deleteFolder(%fullPath); - %this.loadDirectories(); + $CurrentAssetBrowser.loadDirectories(); +} + +function FolderObjectType::onMoveModule(%folderPath, %destinationPath) +{ + //Same logic as a regular folder move + FolderObjectType::onMovePath(%folderPath, %destinationPath); //thrash the modules and reload them - %oldModule = %this.dirHandler.getModuleFromAddress(%folderPath); - %newModule = %this.dirHandler.getModuleFromAddress(%newFolderPath); + %oldModule = $CurrentAssetBrowser.dirHandler.getModuleFromAddress(%folderPath); + %newModule = $CurrentAssetBrowser.dirHandler.getModuleFromAddress(%destinationPath); //if we didn't move modules, then we don't need to do anything other than refresh the assets within it if(%oldModule == %newModule) @@ -132,11 +193,4 @@ function AssetBrowser::moveFolder(%this, %folderPath, %newFolderPath) ModuleDatabase.unloadExplicit(%newModule.getModuleId()); ModuleDatabase.loadExplicit(%newModule.getModuleId()); } -} - -function AssetBrowser::deleteFolder(%this, %folderPath) -{ - %this.dirHandler.deleteFolder(%folderPath); - - %this.refresh(); } \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/forest.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/forest.tscript deleted file mode 100644 index e69de29bb..000000000 diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/gameObject.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/gameObject.tscript deleted file mode 100644 index c8e682669..000000000 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/gameObject.tscript +++ /dev/null @@ -1,285 +0,0 @@ -function AssetBrowser::createGameObjectAsset(%this) -{ - GameObjectCreatorObjectName.text = ""; - - %activeSelection = EWorldEditor.getActiveSelection(); - if( %activeSelection.getCount() == 0 ) - return; - - GameObjectCreator.selectedEntity = %activeSelection.getObject( 0 ); - - Canvas.pushDialog(GameObjectCreator); -} - -function AssetBrowser::editGameObjectAsset(%this, %assetDef) -{ - //We have no dedicated GO editor for now, so just defer to the script editing aspect - %this.editGameObjectAssetScript(%assetDef); -} - -function AssetBrowser::editGameObjectAssetScript(%this, %assetDef) -{ - %scriptFile = %assetDef.scriptFile; - - if(%scriptFile !$= "") - EditorOpenFileInTorsion(makeFullPath(%scriptFile), 0); -} - -function AssetBrowser::applyInstanceToGameObject(%this, %assetDef) -{ - %obj = EditGameObjectAssetPopup.object; - - //TODO add proper validation against the original GO asset - %obj.dirtyGameObject = true; - - TamlWrite(%obj, %assetDef.TAMLFilePath); -} - -function AssetBrowser::duplicateGameObjectAsset(%this, %assetDef, %targetModule) -{ - //Check if we have a target module, if not we need to select one - if(%targetModule $= "") - { - error("AssetBrowser::duplicateGameObjectAsset - No target module selected!"); - return; - } - - %assetId = %assetDef.getAssetId(); - %assetName = AssetDatabase.getAssetName(%assetId); - - //First step, copy the files - %modulePath = "data/" @ %targetModule @ "/gameObjects/"; - - if(!isDirectory(%modulePath)) - createPath(%modulePath); - - %assetFile = AssetDatabase.getAssetFilePath(%assetId); - %scriptFile = %assetDef.scriptFile; - %gameObjectFile = %assetDef.TAMLFile; - - echo("AssetBrowser::duplicateGameObjectAsset - duplicating! " @ %assetId @ " to " @ %targetModule); - - %tamlPath = %modulePath @ fileName(%assetFile); - - pathCopy(%assetFile, %tamlPath); - pathCopy(%scriptFile, %modulePath @ fileName(%scriptFile)); - pathCopy(%gameObjectFile, %modulePath @ fileName(%gameObjectFile)); - - echo("AssetBrowser::duplicateGameObjectAsset - duplicated!"); - - //Register the asset - %moduleDef = ModuleDatabase.findModule(%targetModule, 1); - - AssetDatabase.addDeclaredAsset(%moduleDef, %tamlPath); - - //Refresh the browser - AssetBrowser.refresh(); - - //Rename it for convenience - AssetBrowser.performRenameAsset(%assetName, "New" @ %assetName); -} - -//not used -function AssetBrowser::importGameObjectAsset(%this, %assetId) -{ - -} - -function AssetBrowser::dragAndDropGameObjectAsset(%this, %assetDef, %dropTarget) -{ - if(!isObject(%dropTarget)) - return; - - if(%dropTarget.getId() == EWorldEditor.getId()) - { - if(isObject(%assetDef)) - { - %gameObject = %assetDef.createObject(); - - getScene(0).add(%gameObject); - - %pos = ObjectCreator.getCreateObjectPosition(); //LocalClientConnection.camera.position; - - %gameObject.position = %pos; - - EWorldEditor.clearSelection(); - EWorldEditor.selectObject(%gameObject); - } - else - { - error("WorldEditor::onControlDropped - unable to create GameObject"); - } - } -} - -function AssetBrowser::onGameObjectAssetEditorDropped(%this, %assetDef, %position) -{ - //echo("DROPPED A SHAPE ON THE EDITOR WINDOW!"); - - %targetPosition = EWorldEditor.unproject(%position SPC 1); - %camPos = LocalClientConnection.camera.getPosition(); - %rayResult = containerRayCast(%camPos, %targetPosition, -1); - - %pos = ObjectCreator.getCreateObjectPosition(); - - if(%rayResult != 0) - { - %pos = getWords(%rayResult, 1, 3); - } - - %gameObject = %assetDef.createObject(); - - getScene(0).add(%gameObject); - - %gameObject.position = %pos; - - EWorldEditor.clearSelection(); - EWorldEditor.selectObject(%gameObject); - - EWorldEditor.isDirty = true; - -} - -function AssetBrowser::renameGameObjectAsset(%this, %assetDef, %newAssetId, %originalName, %newName) -{ - %oldScriptFilePath = %assetDef.scriptFile; - %scriptFilePath = filePath(%assetDef.scriptFile); - %scriptExt = fileExt(%assetDef.scriptFile); - - %oldGOFilePath = %assetDef.TAMLFile; - - %filepath = AssetDatabase.getAssetFilePath(%assetDef.getAssetId()); - %path = makeRelativePath(filePath(%filepath)); - - %newScriptFileName = %path @ "/" @ %newName @ %scriptExt; - %newAssetFile = %path @ "/" @ %newName @ ".asset.taml"; - %newGOFile = %path @ "/" @ %newName @ ".taml"; - - %assetDef.gameObjectName = %newName; - %assetDef.scriptFile = %newScriptFileName; - %assetDef.TAMLFile = %newGOFile; - - TamlWrite(%assetDef, %newAssetFile); - fileDelete(%filepath); - - //Quick check, if we duplicated the asset to a new module, the old path may not line up so we'll want to update that to be relevent - if(filePath(%oldScriptFilePath) !$= %path) - { - %oldFileBase = fileName(%oldScriptFilePath); - %oldScriptFilePath = %path @ "/" @ %oldFileBase; - } - - %scriptFileCopySuccess = pathCopy(%oldScriptFilePath, %newScriptFileName); - fileDelete(%oldScriptFilePath); - - if(!%scriptFileCopySuccess) - error("AssetBrowser::renameGameObjectAsset - unable to copy scriptFile"); - - if(filePath(%oldGOFilePath) !$= %path) - { - %oldFileBase = fileName(%oldGOFilePath); - %oldGOFilePath = %path @ "/" @ %oldFileBase; - } - - %goFileCopySuccess = pathCopy(%oldGOFilePath, %newGOFile); - fileDelete(%oldGOFilePath); - - if(!%scriptFileCopySuccess) - error("AssetBrowser::renameGameObjectAsset - unable to copy gameObject"); - - //Go through our scriptfile and replace the old namespace with the new - %editedFileContents = ""; - - %file = new FileObject(); - if ( %file.openForRead( %newScriptFileName ) ) - { - while ( !%file.isEOF() ) - { - %line = %file.readLine(); - %line = trim( %line ); - - %editedFileContents = %editedFileContents @ strreplace(%line, %originalName, %newName) @ "\n"; - } - - %file.close(); - } - - if(%editedFileContents !$= "") - { - %file.openForWrite(%newScriptFileName); - - %file.writeline(%editedFileContents); - - %file.close(); - } - - exec(%newScriptFileName); - - %gameObj = TAMLRead(%newGOFile); - - %gameObj.className = %newName; - %gameObj.GameObject = %assetDef.getAssetId(); - - TAMLWrite(%gameObj, %newGOFile); -} - -//Deletes the asset -function AssetBrowser::deleteGameObjectAsset(%this, %assetDef) -{ - AssetDatabase.deleteAsset(%assetDef.getAssetId(), true); -} - -//Moves the asset to a new path/module -function AssetBrowser::moveGameObjectAsset(%this, %assetDef, %destination) -{ - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.scriptFile, %destination); - moveAssetLooseFile(%assetDef.TAMLFile, %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); -} - - -function AssetBrowser::buildGameObjectAssetPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.scriptFile; - %previewData.doubleClickCommand = "EditorOpenFileInTorsion( "@%previewData.assetPath@", 0 );"; - - %previewData.previewImage = "ToolsModule:gameObjectIcon_image"; - - %previewData.assetFriendlyName = %assetDef.gameObjectName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = "Asset Name: " @ %assetDef.gameObjectName @ "\nDefinition Path: " @ %assetDef.getFilename(); -} - -function GuiInspectorTypeGameObjectAssetPtr::onClick( %this, %fieldName ) -{ - //Get our data - %obj = %this.getInspector().getInspectObject(0); - - EditGameObjectAssetPopup.object = %obj; - - %assetId = %obj.getFieldValue(%fieldName); - - if(%assetId !$= "") - { - EditGameObjectAssetPopup.assetId = %assetId; - - - EditGameObjectAssetPopup.showPopup(Canvas); - } - else - { - //We've gotta be trying to create a GameObject, so kick that off - AssetBrowser.createGameObjectAsset(); - } -} diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/genericAsset.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/genericAsset.tscript new file mode 100644 index 000000000..1b7b569ac --- /dev/null +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/genericAsset.tscript @@ -0,0 +1,351 @@ +//This function registers the asset type, associated file extensions and human-readable name with the Asset Browser +//This is primarily so there's an easy hook-in point for the 'type' namespace, as well as registration for AB +//filter modes and file scanning +AssetBrowser::registerAssetType("GenericAsset", "", "", false); + +//This function is called when we want to have adjustable field information for a new asset +//This could be a secondary name or description, a 'preview image' or anything else beyond +//just the basic AssetName and AssetDescription files +function GenericAsset::setupCreateNew() +{ + echo("GenericAsset::setupCreateNew()"); +} + +//This is called when we actually finally decide to create the new asset itself +//We create the asset definition, supplemental files, save everything to disk and +//then register with the AssetDatabase so it's available for use +function GenericAsset::onCreateNew() +{ + echo("GenericAsset::onCreateNew()"); +} + +//This us called when we are creating a 'card' in the AssetBrowser for viewing +//when navigating. It packs whatever relevent information such as the preview image +//into the %previewData object that the AssetBrowser then uses to actually display +function GenericAsset::buildBrowserElement(%this, %previewData) +{ + %previewData.assetName = %this.assetName; + %previewData.assetPath = %this.getFileName(); + %previewData.doubleClickCommand = ""; + + %previewData.previewImage = "ToolsModule:genericAssetIcon_image"; + + %previewData.assetFriendlyName = %this.assetName; + %previewData.assetDesc = %this.description; + %previewData.tooltip = "Asset Name: " @ %this.assetName @ "\nDefinition Path: " @ %previewData.assetPath; +} + +//This is called when we specifically need to special-handle generation of a preview image +//Such as rendering a shape or material to a cached image file, rather than simply using a +//basic image to represent the type in the AssetBrowser +function GenericAsset::generatePreviewImage(%this, %previewButton, %forceRegenerate) +{ +} + +//Called when we rename the asset. The place we would change the asset definition name +//as well as update the name for any associated files +function GenericAsset::onRename(%this, %newAssetName) +{ + %assetPath = makeFullPath($CurrentAssetBrowser.getAssetFilePath(%this.getAssetId())); + %assetFilepath = filePath(%assetPath); + %assetFileExt = fileExt(%assetPath); + + %newAssetPath = %assetFilepath @ "/" @ %newAssetName @ ".asset.taml"; + + %copiedSuccess = pathCopy(%assetPath, %newAssetPath); + + if(!%copiedSuccess) + return ""; + + replaceInFile(%newAssetPath, %this.assetName, %newAssetName); + + %looseFilesList = AssetDatabase.getAssetLooseFiles(%this.getAssetId()); + + for(%i=0; %i < getFieldCount(%looseFilesList); %i++) + { + %looseFile = getField(%looseFilesList, %i); + + if(!isFile(%looseFile)) + { + errorf("GenericAsset::onMovePath() - could not find loose file: " @ %looseFile); + continue; + } + + %newLooseFileName = strReplace(fileName(%looseFile), %this.assetName, %newAssetName); + %looseFileExt = fileExt(%looseFile); + + echo("GenericAsset::onRename() - renamed loose file from: " @ %looseFile @ " to: " @ %assetPath @ "/" @ %newLooseFileName @ %looseFileExt); + + %looseFileNewPath = %assetPath @ "/" @ %newLooseFileName @ %looseFileExt; + %copiedSuccess = pathCopy(%looseFile, %looseFileNewPath); + if(!%copiedSuccess) + { + errorf("GenericAsset::onDuplicate() - failed to duplicate loose file: " @ %looseFile); + } + else + { + fileDelete(%looseFile); + replaceInFile(%looseFileNewPath, %this.assetName, %newAssetName); + } + } + + %module = getModuleFromAddress(%newAssetPath); + + //Add with the new file + $CurrentAssetBrowser.addDeclaredAsset(%module, %newAssetPath); + + GenericAsset::onDelete(%this); + + return %newAssetPath; +} + +//Called when duplicating the asset. A copy is made, and then we perform a rename action +//on the copy to ensure there's no name conflicts +function GenericAsset::onDuplicate(%this, %newAssetName) +{ + %assetPath = makeFullPath($CurrentAssetBrowser.getAssetFilePath(%this.getAssetId())); + %assetFilepath = filePath(%assetPath); + %assetFileExt = fileExt(%assetPath); + + %newAssetPath = %assetFilepath @ "/" @ %newAssetName @ ".asset.taml"; + + %copiedSuccess = pathCopy(%assetPath, %newAssetPath); + + if(!%copiedSuccess) + return ""; + + replaceInFile(%newAssetPath, %this.assetName, %newAssetName); + + %looseFilesList = AssetDatabase.getAssetLooseFiles(%this.getAssetId()); + + for(%i=0; %i < getFieldCount(%looseFilesList); %i++) + { + %looseFile = getField(%looseFilesList, %i); + + if(!isFile(%looseFile)) + { + errorf("GenericAsset::onMovePath() - could not find loose file: " @ %looseFile); + continue; + } + + %newLooseFileName = strReplace(fileName(%looseFile), %this.assetName, %newAssetName); + %looseFileExt = fileExt(%looseFile); + + echo("GenericAsset::onDuplicate() - renamed loose file from: " @ %looseFile @ " to: " @ %assetPath @ "/" @ %newLooseFileName @ %looseFileExt); + + %looseFileNewPath = %assetPath @ "/" @ %newLooseFileName @ %looseFileExt; + %copiedSuccess = pathCopy(%looseFile, %looseFileNewPath); + if(!%copiedSuccess) + { + errorf("GenericAsset::onDuplicate() - failed to duplicate loose file: " @ %looseFile); + } + else + { + replaceInFile(%looseFileNewPath, %this.assetName, %newAssetName); + } + } + + %module = getModuleFromAddress(%newAssetPath); + + //Add with the new file + $CurrentAssetBrowser.addDeclaredAsset(%module, %newAssetPath); + + $CurrentAssetBrowser.refresh(); + + return %newAssetPath; +} + +//Called when the asset is deleted. This would be where and associated files +//are also removed from the system +function GenericAsset::onDelete(%this) +{ + AssetDatabase.deleteAsset(%this.getAssetId(), true); + + $CurrentAssetBrowser.refresh(); +} + +//Called when the asset is moved from one file path to another. Associated files would be +//likewise moved +function GenericAsset::onMovePath(%this, %destinationPath) +{ + %assetPath = makeFullPath($CurrentAssetBrowser.getAssetFilePath(%this.getAssetId())); + + moveAssetFile(%this, %destinationPath); + + %looseFilesList = AssetDatabase.getAssetLooseFiles(%this.getAssetId()); + for(%i=0; %i < getFieldCount(%looseFilesList); %i++) + { + %looseFile = getField(%looseFilesList, %i); + + moveAssetLooseFile(%looseFile, %destinationPath); + } + + AssetDatabase.refreshAsset(%this.getAssetId()); + + $CurrentAssetBrowser.refresh(); +} + +function GenericAsset::onMoveModule(%this, %destinationPath) +{ + %assetPath = makeFullPath($CurrentAssetBrowser.getAssetFilePath(%this.getAssetId())); + + %newAssetPath = moveAssetFile(%this, %destinationPath); + + %looseFilesList = AssetDatabase.getAssetLooseFiles(%this.getAssetId()); + for(%i=0; %i < getFieldCount(%looseFilesList); %i++) + { + %looseFile = getField(%looseFilesList, %i); + + moveAssetLooseFile(%looseFile, %destinationPath); + } + + %targetModule = $CurrentAssetBrowser.dirHandler.getModuleFromAddress(%destinationPath); + + AssetDatabase.removeDeclaredAsset(%this.getAssetId()); + AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); + + $CurrentAssetBrowser.refresh(); +} + +//Called when there is an InspectorType field for this AssetType and a Asset preview +//has been dragged and dropped from the AssetBrowser onto this field in the inspector +//Generally this would see the field assigned with the dropped asset's ID +/*function GuiInspectorTypePtr::onControlDropped(%this, %payload, %position) +{ +}*/ + +//Called when the asset is edited. This can either open the asset in the respective +//editor(MaterialAsset opens MaterialEd, etc) or performs some other action, such as loading +//a LevelAsset in the editor or possibly opening an associated file in a system program for editing +function GenericAsset::onEdit(%this) +{ + echo("GenericAsset::onEdit() - " @ %this); +} + +//Called when the asset's Preview has been right-clicked to do a context popup menu +//Allows for special-menu population per-type if desired, as not all assets will or should +//offer the same 'actions' for editing and management +function GenericAsset::onShowActionMenu(%this) +{ + if( !isObject( EditAssetPopup ) ) + { + new PopupMenu( EditAssetPopup ) + { + superClass = "MenuBuilder"; + class = "EditorWorldMenu"; + + jumpFileName = ""; + jumpLineNumber = ""; + }; + } + + //Regen the menu so we're fully up and current with options and references + EditAssetPopup.clearItems(); + + EditAssetPopup.item[ 0 ] = "Edit Asset" TAB "" TAB $CurrentAssetBrowser @ ".editAsset();"; + EditAssetPopup.item[ 1 ] = "Rename Asset" TAB "" TAB $CurrentAssetBrowser @ ".renameAsset();"; + EditAssetPopup.item[ 2 ] = "Reload Asset" TAB "" TAB $CurrentAssetBrowser @ ".refreshAsset();"; + EditAssetPopup.item[ 3 ] = "Asset Properties" TAB "" TAB $CurrentAssetBrowser @ ".editAssetInfo();"; + EditAssetPopup.item[ 4 ] = "-"; + EditAssetPopup.item[ 5 ] = "Duplicate Asset" TAB "" TAB $CurrentAssetBrowser @ ".duplicateAsset();"; + EditAssetPopup.item[ 6 ] = "-"; + EditAssetPopup.item[ 7 ] = "Regenerate Preview Image" TAB "" TAB $CurrentAssetBrowser @ ".regeneratePreviewImage();"; + EditAssetPopup.item[ 8 ] = "-"; + EditAssetPopup.item[ 9 ] = "Re-Import Asset" TAB "" TAB $CurrentAssetBrowser @ ".reImportAsset();"; + EditAssetPopup.item[ 10 ] = "-"; + EditAssetPopup.item[ 11 ] = "Open File Location" TAB "" TAB $CurrentAssetBrowser @ ".openFileLocation();"; + EditAssetPopup.item[ 12 ] = "-"; + EditAssetPopup.item[ 13 ] = "Delete Asset" TAB "" TAB $CurrentAssetBrowser @ ".deleteAsset();"; + + %assetId = %this.getAssetId(); + %assetType = AssetDatabase.getAssetType(%assetId); + + EditAssetPopup.objectData = %assetId; + EditAssetPopup.objectType = %assetType; + + EditAssetPopup.reloadItems(); + + EditAssetPopup.showPopup(Canvas); + + $CurrentAssetBrowser.popupMenu = EditAssetPopup; +} + +//Called when editing the asset's properties, generally presented via an inspector +//This function allows for special type handling if just inspecting the Type's object +//is insufficient +function GenericAsset::onEditProperties(%this) +{ + Canvas.pushDialog(AssetBrowser_editAsset); + + AssetBrowser_editAssetWindow.text = "Asset Properties - " @ %this.getAssetId(); + + AssetEditInspector.tempAsset = %this.deepClone(); + + AssetEditInspector.inspect(AssetEditInspector.tempAsset); + AssetBrowser_editAsset.editedObjectData = %this.getAssetId(); + AssetBrowser_editAsset.editedObject = AssetEditInspector.tempAsset; + AssetBrowser_editAsset.editedObjectType = AssetDatabase.getAssetType(%this.getAssetId()); + + //remove some of the groups we don't need: + for(%i=0; %i < AssetEditInspector.getCount(); %i++) + { + %caption = AssetEditInspector.getObject(%i).caption; + + if(%caption $= "Ungrouped" || %caption $= "Object" || %caption $= "Editing" + || %caption $= "Persistence" || %caption $= "Dynamic Fields") + { + AssetEditInspector.remove(AssetEditInspector.getObject(%i)); + %i--; + } + } +} + +//Called when the AssetType has it's properties saved from the onEditProperties process +function GenericAsset::onSaveProperties(%this) +{ + %assetId = %this.getAssetId(); + %file = AssetDatabase.getAssetFilePath(%assetId); + %success = TamlWrite(AssetBrowser_editAsset.editedObject, %file); + + AssetDatabase.releaseAsset(%assetId); + + $CurrentAssetBrowser.reloadAsset(%assetId); + + $CurrentAssetBrowser.refresh(); + + %this.refreshAsset(); +} + +//Called when the asset's Preview has been dragged and dropped into the world editor +//This would usually spawn an associated instance, or a scene object that can utilize the +//asset in question(ie, Dropping a SoundAsset spawns a SoundEmitter) +function GenericAsset::onWorldEditorDropped(%this, %position) +{ + echo("GenericAsset::onWorldEditorDropped() - " @ %this @ ", " @ %position); +} + +//Called when the asset's Preview has been dragged and dropped into the GUI editor +//This would usually spawn an associated instance, or a gui object that can utilize the +//asset in question(ie, Dropping a SoundAsset spawns a guiAudioCtrl) +function GenericAsset::onGuiEditorDropped(%this, %position) +{ + echo("GenericAsset::onGuiEditorDropped() - " @ %this @ ", " @ %position); +} + +//An example case of handling other specialized editors, such as dropping a Datablock +//Preview into the DatablockEditor. This would be very case-by-case +/*function GenericAsset::onEditorDropped() +{ +}*/ + +//Called when the asset has been detected as having had files on the system changed. Allows +//for automatically responding to those changes, such as re-execing script files +function GenericAsset::onChanged(%this) +{ + echo("GenericAsset::onChanged() - " @ %this); +} + +function GenericAsset::onStatusChanged(%this, %newStstus) +{ + echo("GenericAsset::onStatusChanged() - " @ %this @ ", " @ %newStstus); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/gui.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/gui.tscript index ae78030f7..6d091fccc 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/gui.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/gui.tscript @@ -1,9 +1,12 @@ -function AssetBrowser::createGUIAsset(%this) +AssetBrowser::registerFileType("GUIFileType", "GUI Files", ".gui;.gui.dso", false); +AssetBrowser::registerAssetType("GUIAsset", "GUIs"); + +function GUIAsset::onCreateNew() { - %moduleName = AssetBrowser.newAssetSettings.moduleName; + %moduleName = $CurrentAssetBrowser.newAssetSettings.moduleName; %modulePath = "data/" @ %moduleName; - %assetName = AssetBrowser.newAssetSettings.assetName; + %assetName = $CurrentAssetBrowser.newAssetSettings.assetName; %assetPath = NewAssetTargetAddress.getText() @ "/"; @@ -24,7 +27,7 @@ function AssetBrowser::createGUIAsset(%this) %file = new FileObject(); %templateFile = new FileObject(); - %guiTemplateCodeFilePath = %this.templateFilesPath @ "guiFile.gui.template"; + %guiTemplateCodeFilePath = $CurrentAssetBrowser.templateFilesPath @ "guiFile.gui.template"; if(%file.openForWrite(%guipath) && %templateFile.openForRead(%guiTemplateCodeFilePath)) { @@ -45,10 +48,10 @@ function AssetBrowser::createGUIAsset(%this) %file.close(); %templateFile.close(); - warnf("CreateGUIAsset - Something went wrong and we couldn't write the GUI file!"); + warn("GUIAsset::onCreateNew() - Something went wrong and we couldn't write the GUI file!"); } - %scriptTemplateCodeFilePath = %this.templateFilesPath @ "guiFile." @ $TorqueScriptFileExtension @ ".template"; + %scriptTemplateCodeFilePath = $CurrentAssetBrowser.templateFilesPath @ "guiFile." @ $TorqueScriptFileExtension @ ".template"; if(%file.openForWrite(%scriptPath) && %templateFile.openForRead(%scriptTemplateCodeFilePath)) { @@ -69,7 +72,7 @@ function AssetBrowser::createGUIAsset(%this) %file.close(); %templateFile.close(); - warnf("CreateGUIAsset - Something went wrong and we couldn't write the GUI script file!"); + warn("GUIAsset::onCreateNew() - Something went wrong and we couldn't write the GUI script file!"); } //load the gui @@ -79,31 +82,17 @@ function AssetBrowser::createGUIAsset(%this) %moduleDef = ModuleDatabase.findModule(%moduleName, 1); AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath); - AssetBrowser.refresh(); + $CurrentAssetBrowser.refresh(); return %tamlpath; } -function AssetBrowser::inspectImportingGUIAsset(%this, %assetItem) +function GUIAsset::onEdit(%this) { - AssetImportCtrl-->NewAssetsInspector.startGroup("GUI"); - - AssetImportCtrl-->NewAssetsInspector.addField("GUIFile", "GUI File Path", "filename", "Intended usage case of this image. Used to map to material slots and set up texture profiles.", "", - "", %assetItem); - - //Make this a callback so that if it's set we can callback to a validator function - //This function(and others for other asset types) would check if the loosefile audit window is open, and if it is, remove the file from the list - AssetImportCtrl-->NewAssetsInspector.addField("ScriptFile", "Script File Path", "filename", "Intended usage case of this image. Used to map to material slots and set up texture profiles.", "", - "", %assetItem); - AssetImportCtrl-->NewAssetsInspector.endGroup(); -} - -function AssetBrowser::editGUIAsset(%this, %assetDef) -{ - if(!isObject(%assetDef.assetName)) + if(!isObject(%this.assetName)) { - exec(%assetDef.GUIFilePath); - exec(%assetDef.mScriptFilePath); + exec(%this.GUIFilePath); + exec(%this.mScriptFilePath); } if( EditorIsActive() && !GuiEditor.toggleIntoEditorGui ) @@ -112,63 +101,20 @@ function AssetBrowser::editGUIAsset(%this, %assetDef) if( !$InGuiEditor && !GuiEditorIsActive() ) GuiEditor.open(); - GuiEditContent(%assetDef.assetName); + GuiEditContent(%this.assetName); } -//Renames the asset -function AssetBrowser::renameGUIAsset(%this, %assetDef, %newAssetName) +function GUIAsset::buildBrowserElement(%this, %previewData) { - %newScriptLooseFilename = renameAssetLooseFile(%assetDef.scriptFile, %newAssetName); - - if(!%newScriptLooseFilename $= "") - return; - - %newGUILooseFilename = renameAssetLooseFile(%assetDef.guiFile, %newAssetName); - - if(!%newGUILooseFilename $= "") - return; - - %assetDef.scriptFile = %newScriptLooseFilename; - %assetDef.guiFile = %newGUILooseFilename; - %assetDef.saveAsset(); - - renameAssetFile(%assetDef, %newAssetName); -} - -//Deletes the asset -function AssetBrowser::deleteGUIAsset(%this, %assetDef) -{ - AssetDatabase.deleteAsset(%assetDef.getAssetId(), true); -} - -//Moves the asset to a new path/module -function AssetBrowser::moveGUIAsset(%this, %assetDef, %destination) -{ - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.getGUIPath(), %destination); - moveAssetLooseFile(%assetDef.getScriptPath(), %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); -} - - -function AssetBrowser::buildGUIAssetPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.GUIFilePath; + %previewData.assetName = %this.assetName; + %previewData.assetPath = %this.getGUIPath(); %previewData.doubleClickCommand = ""; %previewData.previewImage = "ToolsModule:guiIcon_image"; - %previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = "Asset Name: " @ %assetDef.assetName @ "\nDefinition Path: " @ %assetDef.getScriptPath(); -} + %previewData.assetFriendlyName = %this.assetName; + %previewData.assetDesc = %this.description; + %previewData.tooltip = "Asset Name: " @ %this.assetName @ + "\nGUI Path: " @ %this.getGUIPath() @ + "\nScript Path: " @ %this.getScriptPath(); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript index b92b65182..26f093dd0 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/image.tscript @@ -1,202 +1,33 @@ -function AssetBrowser::prepareImportImageAsset(%this, %assetItem) -{ - if((getAssetImportConfigValue("Images/GenerateMaterialOnImport", "1") == 1 && %assetItem.parentAssetItem $= "") || %assetItem.parentAssetItem !$= "") - { - //First, see if this already has a suffix of some sort based on our import config logic. Many content pipeline tools like substance automatically appends them - %foundSuffixType = parseImageSuffixes(%assetItem); - - if(%foundSuffixType $= "") - { - %noSuffixName = %assetItem.AssetName; - } - else - { - %suffixPos = strpos(strlwr(%assetItem.AssetName), strlwr(%assetItem.ImageType), 0); - %noSuffixName = getSubStr(%assetItem.AssetName, 0, %suffixPos); - } - - //Check if our material already exists - //First, lets double-check that we don't already have an - %materialAsset = ImportAssetWindow.findImportingAssetByName(%noSuffixName); - %cratedNewMaterial = false; - - //Sanity catch in the case we have some naming convention shenanigans in play - if(%materialAsset != 0 && %materialAsset.assetType !$= "MaterialAsset") - %materialAsset = 0; - - if(%materialAsset == 0) - { - %filePath = %assetItem.filePath; - if(%filePath !$= "") - %materialAsset = AssetBrowser.addImportingAsset("MaterialAsset", "", "", %noSuffixName); - - //%materialAsset.filePath = filePath(%assetItem.filePath) @ "/" @ %noSuffixName; - - ImportAssetItems.add(%materialAsset); - - %cratedNewMaterial = true; - } - - if(isObject(%materialAsset)) - { - if(%assetItem.parentAssetItem !$= "") - { - %parentIndex = %assetItem.parentAssetItem.childAssetItems.getIndexFromKey(%assetItem); - %assetItem.parentAssetItem.childAssetItems.erase(%parentIndex); - } - else - { - //if we didn't have a parent until now, we're going to pull from it from our ImportAssetItems list - %itemIndex = ImportAssetItems.getIndexFromKey(%assetItem); - ImportAssetItems.erase(%itemIndex); - } - - //Establish parentage - %materialAsset.childAssetItems.add(%assetItem); - %assetItem.parentAssetItem = %materialAsset; - - ImportAssetWindow.assetHeirarchyChanged = true; - } - - //Lets do some cleverness here. If we're generating a material we can parse like assets being imported(similar file names) but different suffixes - //if we find these, we'll just populate into the original's material - - //If we need to append the diffuse suffix and indeed didn't find a suffix on the name, do that here - if(%foundSuffixType $= "") - { - if(getAssetImportConfigValue("Images/UseDiffuseSuffixOnOriginImg", "1") == 1) - { - if(%foundSuffixType $= "") - { - %diffuseToken = getToken(getAssetImportConfigValue("Images/DiffuseTypeSuffixes", ""), ",", 0); - %assetItem.AssetName = %assetItem.AssetName @ %diffuseToken; - } - } - else - { - //We need to ensure that our image asset doesn't match the same name as the material asset, so if we're not trying to force the diffuse suffix - //we'll give it a generic one - if(%materialAsset.assetName $= %assetItem.assetName) - { - %assetItem.AssetName = %assetItem.AssetName @ "_image"; - } - } - - %foundSuffixType = "diffuse"; - } - - if(%foundSuffixType !$= "") - { - //otherwise, if we have some sort of suffix, we'll want to figure out if we've already got an existing material, and should append to it - - if(getAssetImportConfigValue("Materials/PopulateMaterialMaps", "1") == 1) - { - if(%foundSuffixType $= "diffuse") - %assetItem.ImageType = "Albedo"; - else if(%foundSuffixType $= "normal") - %assetItem.ImageType = "Normal"; - else if(%foundSuffixType $= "metalness") - %assetItem.ImageType = "metalness"; - else if(%foundSuffixType $= "roughness") - %assetItem.ImageType = "roughness"; - else if(%foundSuffixType $= "specular") - %assetItem.ImageType = "specular"; - else if(%foundSuffixType $= "AO") - %assetItem.ImageType = "AO"; - else if(%foundSuffixType $= "composite") - %assetItem.ImageType = "composite"; - } - } - - //If we JUST created this material, we need to do a process pass on it to do any other setup for it - /*if(%cratedNewMaterial) - { - AssetBrowser.prepareImportMaterialAsset(%materialAsset); - }*/ - } +AssetBrowser::registerAssetType("ImageAsset", "Images"); - %assetItem.processed = true; - - refreshImportAssetWindow(); -} - -function AssetBrowser::inspectImportingImageAsset(%this, %assetItem) -{ - AssetImportCtrl-->NewAssetsInspector.startGroup("Image"); - AssetImportCtrl-->NewAssetsInspector.addField("ImageType", "Image Type", "list", "Intended usage case of this image. Used to map to material slots and set up texture profiles.", "GUI", - "Albedo,Normal,Composite,Roughness,AO,Metalness,Glow,GUI,Particle,Decal", %assetItem); - - AssetImportCtrl-->NewAssetsInspector.endGroup(); -} - -function AssetBrowser::importImageAsset(%this, %assetItem) -{ - %moduleName = AssetImportTargetModule.getText(); - - %assetType = %assetItem.AssetType; - %filePath = %assetItem.filePath; - %assetName = %assetItem.assetName; - %assetImportSuccessful = false; - %assetId = %moduleName@":"@%assetName; - - %assetPath = NewAssetTargetAddress.getText() @ "/"; - - %assetFullPath = %assetPath @ "/" @ fileName(%filePath); - - %newAsset = new ImageAsset() - { - assetName = %assetName; - versionId = 1; - imageFile = makeFullPath(%filePath); - imageType = %assetItem.imageType; - }; - - %assetImportSuccessful = TAMLWrite(%newAsset, %assetPath @ "/" @ %assetName @ ".asset.taml"); - - //and copy the file into the relevent directory - %doOverwrite = !AssetBrowser.isAssetReImport; - if(!pathCopy(%filePath, %assetFullPath, %doOverwrite)) - { - error("Unable to import asset: " @ %filePath); - return; - } - - %moduleDef = ModuleDatabase.findModule(%moduleName,1); - - if(!AssetBrowser.isAssetReImport) - AssetDatabase.addDeclaredAsset(%moduleDef, %assetPath @ "/" @ %assetName @ ".asset.taml"); - else - AssetDatabase.refreshAsset(%assetId); -} - -function AssetBrowser::buildImageAssetPreview(%this, %assetDef, %previewData) +function ImageAsset::buildBrowserElement(%this, %previewData) { //%module = %this.dirHandler.getModuleFromAddress(makeRelativePath(filePath(%assetDef.getImagePath()))); %previewData.previewImage = %assetDef.isNamedTarget() ? "Core_Rendering:namedTarget_image" : "ToolsModule:genericAssetIcon_image"; %previewData.previewLoaded = %assetDef.isNamedTarget() ? true : false; //if image target we are loaded, else mark for loading later. - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.scriptFile; + %previewData.assetName = %this.assetName; + %previewData.assetPath = %this.scriptFile; - %previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; + %previewData.assetFriendlyName = %this.assetName; + %previewData.assetDesc = %this.description; //image info //%info = %assetDef.getImageInfo(); - %previewData.tooltip = "Asset Name: " @ %assetDef.assetName @ "\n" @ + %previewData.tooltip = "Asset Name: " @ %this.assetName @ "\n" @ "Asset Type: Image Asset\n" @ - "Asset Definition ID: " @ %assetDef @ "\n" @ - "Image Type: " @ %assetDef.imageType @ "\n" @ + "Asset Definition ID: " @ %this @ "\n" @ + "Image Type: " @ %this.imageType @ "\n" @ /* "Format: " @ getWord(%info, 0) @ "\n" @ "Height: " @ getWord(%info, 1) @ "\n" @ "Width: " @ getWord(%info, 2) @ "\n" @ "Depth: " @ getWord(%info, 3) @ "\n" @ */ - "Image File path: " @ %assetDef.getImagePath(); + "Image File path: " @ %this.getImagePath(); } -function AssetBrowser::generateImageAssetPreviewImage(%this, %previewButton, %forceRegenerate) +function ImageAsset::generatePreviewImage(%this, %previewButton, %forceRegenerate) { if(%forceRegenerate $= "") %forceRegenerate = false; @@ -205,24 +36,20 @@ function AssetBrowser::generateImageAssetPreviewImage(%this, %previewButton, %fo if(!IsDirectory(%previewPath)) { - %this.dirHandler.createFolder(%previewPath); + $CurrentAssetBrowser.dirHandler.createFolder(%previewPath); } - %assetId = %previewButton.moduleName @ ":" @ %previewButton.assetName; - - %assetDef = AssetDatabase.acquireAsset(%assetId); - - %previewFilePath = %previewPath @ %assetDef.assetName @ "_Preview.png"; - if(!isFile(%previewFilePath) || (compareFileTimes(%assetDef.getImagePath(), %previewFilePath) == 1)) + %previewFilePath = %previewPath @ %this.assetName @ "_Preview.png"; + if(!isFile(%previewFilePath) || (compareFileTimes(%this.getImagePath(), %previewFilePath) == 1)) { %generatePreview = true; } - %previewAssetName = %previewButton.moduleName @ "_" @ %assetDef.assetName @ "_PreviewImage"; + %previewAssetName = %previewButton.moduleName @ "_" @ %this.assetName @ "_PreviewImage"; if(%generatePreview || %forceRegenerate) { - %success = saveScaledImage(%assetDef.getImagePath(), %previewFilePath, EditorSettings.value("Assets/Browser/PreviewImageSize")); + %success = saveScaledImage(%this.getImagePath(), %previewFilePath, EditorSettings.value("Assets/Browser/PreviewImageSize")); if(%success) { @@ -248,79 +75,40 @@ function AssetBrowser::generateImageAssetPreviewImage(%this, %previewButton, %fo return false; //failed to register the preview image for some reason? } } - - %previewButton.bitmapAsset = %previewAssetName; - return true; + + %previewButton.bitmapAsset = %previewAssetName; + return true; + } + } + else + { + //just map the existing one then + if(AssetDatabase.isDeclaredAsset("ToolsModule:" @ %previewAssetName)) + { + %previewButton.bitmapAsset = "ToolsModule:" @ %previewAssetName; + return true; } - } - else - { - //just map the existing one then - if(AssetDatabase.isDeclaredAsset("ToolsModule:" @ %previewAssetName)) - { - %previewButton.bitmapAsset = "ToolsModule:" @ %previewAssetName; - return true; - } } return false; } -//Renames the asset -function AssetBrowser::renameImageAsset(%this, %assetDef, %newAssetName) +function ImageAsset::onShowActionMenu(%this) { - %newFilename = renameAssetLooseFile(%assetDef.getImagePath(), %newAssetName); - - if(!%newFilename $= "") - return; - - %assetDef.imageFile = %newFilename; - %assetDef.saveAsset(); - - renameAssetFile(%assetDef, %newAssetName); + GenericAsset::onShowActionMenu(%this); } -//Duplicates the asset -function AssetBrowser::duplicateImageAsset(%this, %assetDef, %newAssetName) +function ImageAsset::onEditProperties(%this) { - %duplicatedAsset = duplicateAssetFile(%assetDef, %newAssetName); - - %newFilename = duplicateAssetLooseFile(%assetDef.imageFile, %newAssetName); - - if(!%newFilename $= "") - return; - - %module = AssetBrowser.dirHandler.getModuleFromAddress(%duplicatedAsset); - - %dupAssetDef = AssetDatabase.acquireAsset(%module.ModuleId @ ":" @ %newAssetName); - - %dupAssetDef.imageFile = fileName(%newFilename); - %dupAssetDef.saveAsset(); + GenericAsset::onEditProperties(%this); } -//Deletes the asset -function AssetBrowser::deleteImageAsset(%this, %assetDef) +//Called when the AssetType has it's properties saved from the onEditProperties process +function ImageAsset::onSaveProperties(%this) { - AssetDatabase.deleteAsset(%assetDef.getAssetId(), true); + GenericAsset::onSaveProperties(%this); } - -//Moves the asset to a new path/module -function AssetBrowser::moveImageAsset(%this, %assetDef, %destination) -{ - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.getImagePath(), %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); -} - function GuiInspectorTypeImageAssetPtr::onControlDropped( %this, %payload, %position ) { Canvas.popDialog(EditorDragAndDropLayer); @@ -340,176 +128,4 @@ function GuiInspectorTypeImageAssetPtr::onControlDropped( %this, %payload, %posi } EWorldEditor.isDirty = true; -} - -function parseImageSuffixes(%assetItem) -{ - //diffuse - %suffixCount = getTokenCount(getAssetImportConfigValue("Images/DiffuseTypeSuffixes", ""), ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(getAssetImportConfigValue("Images/DiffuseTypeSuffixes", ""), ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %assetItem.AssetName)) - { - %assetItem.ImageType = %suffixToken; - return "diffuse"; - } - } - - //normal - %suffixCount = getTokenCount(getAssetImportConfigValue("Images/NormalTypeSuffixes", ""), ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(getAssetImportConfigValue("Images/NormalTypeSuffixes", ""), ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %assetItem.AssetName)) - { - %assetItem.ImageType = %suffixToken; - return "normal"; - } - } - - //roughness - %suffixCount = getTokenCount(getAssetImportConfigValue("Images/RoughnessTypeSuffixes", ""), ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(getAssetImportConfigValue("Images/RoughnessTypeSuffixes", ""), ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %assetItem.AssetName)) - { - %assetItem.ImageType = %suffixToken; - return "roughness"; - } - } - - //Ambient Occlusion - %suffixCount = getTokenCount(getAssetImportConfigValue("Images/AOTypeSuffixes", ""), ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(getAssetImportConfigValue("Images/AOTypeSuffixes", ""), ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %assetItem.AssetName)) - { - %assetItem.ImageType = %suffixToken; - return "AO"; - } - } - - //metalness - %suffixCount = getTokenCount(getAssetImportConfigValue("Images/MetalnessTypeSuffixes", ""), ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(getAssetImportConfigValue("Images/MetalnessTypeSuffixes", ""), ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %assetItem.AssetName)) - { - %assetItem.ImageType = %suffixToken; - return "metalness"; - } - } - - //composite - %suffixCount = getTokenCount(getAssetImportConfigValue("Images/CompositeTypeSuffixes", ""), ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(getAssetImportConfigValue("Images/CompositeTypeSuffixes", ""), ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %assetItem.AssetName)) - { - %assetItem.ImageType = %suffixToken; - return "composite"; - } - } - - //specular - /*%suffixCount = getTokenCount(ImportAssetWindow.activeImportConfig.SpecularTypeSuffixes, ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(ImportAssetWindow.activeImportConfig.SpecularTypeSuffixes, ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %assetItem.AssetName)) - { - %assetItem.imageSuffixType = %suffixToken; - return "specular"; - } - }*/ - - return ""; -} - -function parseImagePathSuffixes(%filePath) -{ - //diffuse - %diffuseSuffixes = getAssetImportConfigValue("Images/DiffuseTypeSuffixes", ""); - %suffixCount = getTokenCount(%diffuseSuffixes, ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(%diffuseSuffixes, ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %filePath)) - { - return "diffuse"; - } - } - - //normal - %suffixCount = getTokenCount(ImportAssetWindow.activeImportConfig.NormalTypeSuffixes, ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(ImportAssetWindow.activeImportConfig.NormalTypeSuffixes, ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %filePath)) - { - return "normal"; - } - } - - //roughness - %suffixCount = getTokenCount(ImportAssetWindow.activeImportConfig.RoughnessTypeSuffixes, ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(ImportAssetWindow.activeImportConfig.RoughnessTypeSuffixes, ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %filePath)) - { - return "roughness"; - } - } - - //Ambient Occlusion - %suffixCount = getTokenCount(ImportAssetWindow.activeImportConfig.AOTypeSuffixes, ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(ImportAssetWindow.activeImportConfig.AOTypeSuffixes, ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %filePath)) - { - return "AO"; - } - } - - //metalness - %suffixCount = getTokenCount(ImportAssetWindow.activeImportConfig.MetalnessTypeSuffixes, ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(ImportAssetWindow.activeImportConfig.MetalnessTypeSuffixes, ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %filePath)) - { - return "metalness"; - } - } - - //composite - %suffixCount = getTokenCount(ImportAssetWindow.activeImportConfig.CompositeTypeSuffixes, ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(ImportAssetWindow.activeImportConfig.CompositeTypeSuffixes, ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %filePath)) - { - return "composite"; - } - } - - //specular - %suffixCount = getTokenCount(ImportAssetWindow.activeImportConfig.SpecularTypeSuffixes, ",;"); - for(%sfx = 0; %sfx < %suffixCount; %sfx++) - { - %suffixToken = getToken(ImportAssetWindow.activeImportConfig.SpecularTypeSuffixes, ",;", %sfx); - if(strIsMatchExpr("*"@%suffixToken, %filePath)) - { - return "specular"; - } - } - - return ""; } \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/level.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/level.tscript index 268de61c0..015a798ae 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/level.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/level.tscript @@ -1,30 +1,20 @@ -function AssetBrowser::setupCreateNewLevelAsset(%this) +AssetBrowser::registerAssetType("LevelAsset", "Levels"); + +function LevelAsset::setupCreateNew() { NewAssetPropertiesInspector.startGroup("Level"); - NewAssetPropertiesInspector.addField("LevelName", "Level Name", "String", "Human-readable name of new level", "", "", %this.newAssetSettings); - NewAssetPropertiesInspector.addField("levelPreviewImage", "Level Preview Image", "Image", "Preview Image for the level", "", "", %this.newAssetSettings); + NewAssetPropertiesInspector.addField("LevelName", "Level Name", "String", "Human-readable name of new level", "", "", $CurrentAssetBrowser.newAssetSettings); + NewAssetPropertiesInspector.addField("levelPreviewImage", "Level Preview Image", "Image", "Preview Image for the level", "", "", $CurrentAssetBrowser.newAssetSettings); - //If we forcefully set it elsewhere, adhere - if($createLevelAssetIsSubScene == true) - %this.newAssetSettings.isSubScene = true; - else - %this.newAssetSettings.isSubScene = false; - - NewAssetPropertiesInspector.addField("isSubScene", "Is SubScene", "bool", "Is this levelAsset intended as a subScene", %this.newAssetSettings.isSubScene, "", %this.newAssetSettings); - NewAssetPropertiesInspector.endGroup(); } -function AssetImporter::importLevelAsset(%this, %assetItem) +function LevelAsset::onCreateNew(%this) { -} - -function AssetBrowser::createLevelAsset(%this) -{ - %moduleName = AssetBrowser.newAssetSettings.moduleName; + %moduleName = $CurrentAssetBrowser.newAssetSettings.moduleName; %modulePath = "data/" @ %moduleName; - %assetName = AssetBrowser.newAssetSettings.assetName; + %assetName = $CurrentAssetBrowser.newAssetSettings.assetName; %assetPath = NewAssetTargetAddress.getText() @ "/"; @@ -43,10 +33,10 @@ function AssetBrowser::createLevelAsset(%this) PostFXPresetFile = %assetName @ ".postfxpreset." @ $TorqueScriptFileExtension; ForestFile = %assetName @ ".forest"; NavmeshFile = %assetName @ ".nav"; - LevelName = AssetBrowser.newAssetSettings.levelName; - AssetDescription = AssetBrowser.newAssetSettings.description; - PreviewImage = AssetBrowser.newAssetSettings.levelPreviewImage; - isSubScene = AssetBrowser.newAssetSettings.isSubScene; + LevelName = $CurrentAssetBrowser.newAssetSettings.levelName; + AssetDescription = $CurrentAssetBrowser.newAssetSettings.description; + PreviewImage = $CurrentAssetBrowser.newAssetSettings.levelPreviewImage; + isSubScene = $CurrentAssetBrowser.newAssetSettings.isSubScene; }; TamlWrite(%asset, %tamlpath); @@ -90,219 +80,42 @@ function AssetBrowser::createLevelAsset(%this) if(!%addSuccess) { - error("AssetBrowser::createLevelAsset() - failed to add declared asset: " @ %tamlpath @ " for module: " @ %moduleDef); + error("LevelAsset::onCreateNew() - failed to add declared asset: " @ %tamlpath @ " for module: " @ %moduleDef); } - AssetBrowser.refresh(); + $CurrentAssetBrowser.refresh(); + + if(%addSuccess && isObject($createAndAssignField)) + { + $createAndAssignField.apply(%moduleName @ ":" @ %assetName); + $createAndAssignField = ""; + } return %tamlpath; } -//============================================================================== -//SubScene derivative -//============================================================================== -function AssetBrowser::setupCreateNewSubScene(%this) +function LevelAsset::onEdit(%this) { - %this.newAssetSettings.isSubScene = true; - %this.newAssetSettings.assetType = "LevelAsset"; + schedule( 1, 0, "EditorOpenMission", %this); } -//============================================================================== - -function AssetBrowser::editLevelAsset(%this, %assetDef) +function LevelAsset::buildBrowserElement(%this, %previewData) { - echo("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); - echo(%assetDef @ ".isSubScene = " @ %assetDef.isSubScene); - if(!%assetDef.isSubScene) - schedule( 1, 0, "EditorOpenMission", %assetDef); -} - -//Renames the asset -function AssetBrowser::renameLevelAsset(%this, %assetDef, %newAssetName) -{ - %newFilename = renameAssetLooseFile(%assetDef.LevelFile, %newAssetName); + %previewData.assetName = %this.assetName; + %previewData.assetPath = %this.getLevelPath(); + %previewData.doubleClickCommand = "schedule( 1, 0, \"EditorOpenMission\", "@%this@");"; - if(!%newFilename $= "") - return; - - //TODO the other loose files - - %assetDef.LevelFile = %newFilename; - %assetDef.saveAsset(); - - renameAssetFile(%assetDef, %newAssetName); -} - -//Duplicates the asset -function AssetBrowser::duplicateLevelAsset(%this, %assetDef, %newAssetName) -{ - %duplicatedAsset = duplicateAssetFile(%assetDef, %newAssetName); - - %newFilename = duplicateAssetLooseFile(%assetDef.LevelFile, %newAssetName); - - if(!%newFilename $= "") - return; - - %module = AssetBrowser.dirHandler.getModuleFromAddress(%duplicatedAsset); - - %dupAssetDef = AssetDatabase.acquireAsset(%module.ModuleId @ ":" @ %newAssetName); - - %dupAssetDef.LevelFile = fileName(%newFilename); - %dupAssetDef.saveAsset(); -} - -//Deletes the asset -function AssetBrowser::deleteLevelAsset(%this, %assetDef) -{ - AssetDatabase.deleteAsset(%assetDef.getAssetId(), true); -} - -//Moves the asset to a new path/module -function AssetBrowser::moveLevelAsset(%this, %assetDef, %destination) -{ - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.getLevelPath(), %destination); - moveAssetLooseFile(%assetDef.getPreviewImagePath(), %destination); - moveAssetLooseFile(%assetDef.getPostFXPresetPath(), %destination); - moveAssetLooseFile(%assetDef.getDecalsPath(), %destination); - moveAssetLooseFile(%assetDef.getForestPath(), %destination); - moveAssetLooseFile(%assetDef.getNavmeshPath(), %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); -} - -function AssetBrowser::buildLevelAssetPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.getLevelPath(); - - if(%this.selectMode || %assetDef.isSubScene) - { - %previewData.doubleClickCommand = "AssetBrowser.selectAsset( AssetBrowser.selectedAsset );"; - } - else - { - %previewData.doubleClickCommand = "schedule( 1, 0, \"EditorOpenMission\", "@%assetDef@");"; - } - - %levelPreviewImage = %assetDef.PreviewImage; + %levelPreviewImage = %this.PreviewImage; if(isFile(%levelPreviewImage)) %previewData.previewImage = %levelPreviewImage; else %previewData.previewImage = "ToolsModule:levelIcon_image"; - %previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = "Asset Name: " @ %assetDef.assetName @ "\n" @ + %previewData.assetFriendlyName = %this.assetName; + %previewData.assetDesc = %this.description; + %previewData.tooltip = "Asset Name: " @ %this.assetName @ "\n" @ "Asset Type: Level Asset\n" @ - "Asset Definition ID: " @ %assetDef @ "\n" @ - "Level File path: " @ %assetDef.getLevelPath(); -} - -function createAndAssignLevelAsset(%moduleName, %assetName) -{ - if(AssetDatabase.isDeclaredAsset(%moduleName)) - $createAndAssignField.apply(%moduleName); - else - $createAndAssignField.apply(%moduleName @ ":" @ %assetName); -} - -function EWorldEditor::createSelectedAsSubScene( %this, %object ) -{ - //create new level asset here - AssetBrowser.setupCreateNewAsset("SubScene", AssetBrowser.selectedModule, "finishCreateSelectedAsSubScene"); - %this.contextActionObject = %object; -} - -function finishCreateSelectedAsSubScene(%assetId) -{ - echo("finishCreateSelectedAsSubScene"); - - %subScene = new SubScene() { - levelAsset = %assetId; - }; - - %levelAssetDef = AssetDatabase.acquireAsset(%assetId); - %levelFilePath = %levelAssetDef.getLevelPath(); - - //write out to file - EWorldEditor.contextActionObject.save(%levelFilePath); - - AssetDatabase.releaseAsset(%assetId); - - getRootScene().add(%subScene); - - EWorldEditor.contextActionObject.delete(); - - %subScene.load(); - - %subScene.recalculateBounds(); - - %scalar = $SubScene::createScalar; - if(%scalar $= "") - %scalar = 1.5; - - //pad for loading boundary - %subScene.scale = VectorScale(%subScene.scale, %scalar); -} - -function GuiInspectorTypeLevelAssetPtr::onControlDropped( %this, %payload, %position ) -{ - Canvas.popDialog(EditorDragAndDropLayer); - - // Make sure this is a color swatch drag operation. - if( !%payload.parentGroup.isInNamespaceHierarchy( "AssetPreviewControlType_AssetDrop" ) ) - return; - - %assetType = %payload.assetType; - %module = %payload.moduleName; - %assetName = %payload.assetName; - - if(%assetType $= "LevelAsset") - { - %cmd = %this @ ".apply(\""@ %module @ ":" @ %assetName @ "\");"; - eval(%cmd); - } - - EWorldEditor.isDirty = true; -} - -function AssetBrowser::onLevelAssetEditorDropped(%this, %assetDef, %position) -{ - %assetId = %assetDef.getAssetId(); - - if(!%assetDef.isSubScene) - { - errorf("Cannot drag-and-drop LevelAsset into WorldEditor"); - return; - } - - %newSubScene = new SubScene() - { - position = %position; - levelAsset = %assetId; - }; - - getScene(0).add(%newSubScene); - - %newSubScene.load(); - %newSubScene.recalculateBounds(); - - EWorldEditor.clearSelection(); - EWorldEditor.selectObject(%newSubScene); - - EWorldEditor.dropSelection(); - - EWorldEditor.isDirty = true; - - MECreateUndoAction::submit(%newSubScene ); + "Asset Definition ID: " @ %this @ "\n" @ + "Level File path: " @ %this.getLevelPath(); } \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/looseFiles.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/looseFiles.tscript index 2c036c064..8d719c1da 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/looseFiles.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/looseFiles.tscript @@ -1,14 +1,17 @@ -function AssetBrowser::buildLooseFilePreview(%this, %assetDef, %previewData) +AssetBrowser::registerFileType("NonAssetLooseFile", "Loose Files", "-"); + +function NonAssetLooseFile::buildBrowserElement(%filePath, %previewData) { - %fullPath = %assetDef.dirPath @ "/" @ %assetDef.assetName; - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %fullPath; + %fileName = fileName(%filePath); + + %previewData.assetName = %fileName; + %previewData.assetPath = %filePath; %previewData.previewImage = "ToolsModule:looseFileIcon_image"; //%previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = %fullPath; + %previewData.assetDesc = %filePath; + %previewData.tooltip = %filePath; //%previewData.doubleClickCommand = "AssetBrowser.schedule(10, \"navigateTo\",\""@ %assetDef.dirPath @ "/" @ %assetDef.assetName @"\");";//browseTo %assetDef.dirPath / %assetDef.assetName - %previewData.doubleClickCommand = "AssetBrowser.autoImportFile(\"" @ %fullPath @ "\");"; + //%previewData.doubleClickCommand = "AssetBrowser.autoImportFile(\"" @ %fullPath @ "\");"; } \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript index 0846beaa4..05cada34d 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/material.tscript @@ -1,4 +1,6 @@ -function AssetBrowser::createMaterialAsset(%this) +AssetBrowser::registerAssetType("MaterialAsset", "Materials"); + +function MaterialAsset::createMaterialAsset(%this) { %assetName = AssetBrowser.newAssetSettings.assetName; @@ -33,15 +35,15 @@ function AssetBrowser::createMaterialAsset(%this) return %tamlpath; } -function AssetBrowser::editMaterialAsset(%this, %assetDef) +function MaterialAsset::onEdit(%this) { - %assetDef.materialDefinitionName.reload(); + %this.materialDefinitionName.reload(); EditorGui.setEditor(MaterialEditorPlugin); - MaterialEditorGui.currentMaterialAsset = %assetDef.getAssetId(); - MaterialEditorGui.currentMaterial = %assetDef.materialDefinitionName; - MaterialEditorGui.setActiveMaterial( %assetDef.materialDefinitionName ); + MaterialEditorGui.currentMaterialAsset = %this.getAssetId(); + MaterialEditorGui.currentMaterial = %this.materialDefinitionName; + MaterialEditorGui.setActiveMaterial( %this.materialDefinitionName ); AssetBrowser.hideDialog(); } @@ -60,451 +62,82 @@ function AssetBrowser::renameMaterialAsset(%this, %assetDef, %newAssetName) renameAssetFile(%assetDef, %newAssetName); } -//Deletes the asset -function AssetBrowser::deleteMaterialAsset(%this, %assetDef) -{ - AssetDatabase.deleteAsset(%assetDef.getAssetId(), true); -} - -//Moves the asset to a new path/module -function AssetBrowser::moveMaterialAsset(%this, %assetDef, %destination) -{ - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.getScriptPath(), %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); -} - -function AssetBrowser::prepareImportMaterialAsset(%this, %assetItem) -{ - ImportActivityLog.add("Preparing Material for Import: " @ %assetItem.assetName); - - //Iterate over to find appropriate images for - - //Fetch just the fileBase name - %fileDir = filePath(%assetItem.filePath); - %fileName = fileBase(%assetItem.filePath); - %fileExt = fileExt(%assetItem.filePath); - - %assetItem.generatedAsset = true; - - //Check if we need to filter this material out or not - if(getAssetImportConfigValue("Materials/IgnoreMaterials", "") !$= "") - { - %ignoredMatNamesCount = getTokenCount(getAssetImportConfigValue("Materials/IgnoreMaterials", ""), ",;"); - for(%i=0; %i < %ignoredMatNamesCount; %i++) - { - %ignoreName = getToken(getAssetImportConfigValue("Materials/IgnoreMaterials", ""), ",;", %i); - - if(strIsMatchExpr(%ignoreName, %fileName)) - { - //We fit the bill, ignore this material and skip it - %assetItem.skip = true; - - ImportActivityLog.add(%assetItem.assetName @ " has been ignored due to config Materials/IgnoreMaterials settings"); - - return; - } - } - } - - if(getAssetImportConfigValue("Materials/PopulateMaterialMaps", "1") == 1) - { - ImportActivityLog.add("Attempting to Auto-Populate Material Maps"); - - for(%i=0; %i < %assetItem.childAssetItems.count(); %i++) - { - %childAssetItem = %assetItem.childAssetItems.getKey(%i); - - if(!isObject(%childAssetItem) || %childAssetItem.skip || %childAssetItem.processed == true || %childAssetItem.assetType !$= "ImageAsset") - return; - - if(%childAssetItem.imageType $= "Albedo") - { - %assetItem.diffuseImageAsset = %childAssetItem; - } - } - - /*%materialItemId = ImportAssetTree.findItemByObjectId(%assetItem); - - if(%assetItem.diffuseImageAsset $= "") - { - %diffuseTypeSuffixes = getAssetImportConfigValue("Images/DiffuseTypeSuffixes", ""); - - %targetFilePath = %this.findMaterialMapFileWSuffix(%fileDir, %fileName, %fileExt, %diffuseTypeSuffixes); - - if(%targetFilePath !$= "") - { - ImportActivityLog.add("Auto-Populated Diffuse Map Image Asset via file: " @ %targetFilePath); - - %diffuseAsset = AssetBrowser.addImportingAsset("ImageAsset", %targetFilePath, %assetItem); - %assetItem.diffuseImageAsset = %diffuseAsset; - } - } - - //Now, iterate over our comma-delimited suffixes to see if we have any matches. We'll use the first match in each case, if any. - if(%assetItem.normalImageAsset $= "") - { - %normalTypeSuffixes = getAssetImportConfigValue("Images/NormalTypeSuffixes", ""); - - //First, normal map - %targetFilePath = %this.findMaterialMapFileWSuffix(%fileDir, %fileName, %fileExt, %normalTypeSuffixes); - - if(%targetFilePath !$= "") - { - ImportActivityLog.add("Auto-Populated Normal Map Image Asset via file: " @ %targetFilePath); - - %normalAsset = AssetBrowser.addImportingAsset("ImageAsset", %targetFilePath, %assetItem); - %assetItem.normalImageAsset = %normalAsset; - } - } - - if(%assetItem.metalImageAsset $= "") - { - %metalnessTypeSuffixes = getAssetImportConfigValue("Images/MetalnessTypeSuffixes", ""); - - %targetFilePath = %this.findMaterialMapFileWSuffix(%fileDir, %fileName, %fileExt, %metalnessTypeSuffixes); - - if(%targetFilePath !$= "") - { - ImportActivityLog.add("Auto-Populated Metalness Map Image Asset via file: " @ %targetFilePath); - - %metalAsset = AssetBrowser.addImportingAsset("ImageAsset", %targetFilePath, %assetItem); - %assetItem.metalImageAsset = %metalAsset; - } - } - - if(%assetItem.roughnessImageAsset $= "") - { - %roughnessTypeSuffixes = getAssetImportConfigValue("Images/RoughnessTypeSuffixes", ""); - - %targetFilePath = %this.findMaterialMapFileWSuffix(%fileDir, %fileName, %fileExt, %roughnessTypeSuffixes); - - if(%targetFilePath !$= "") - { - ImportActivityLog.add("Auto-Populated Roughness Map Image Asset via file: " @ %targetFilePath); - - %roughnessAsset = AssetBrowser.addImportingAsset("ImageAsset", %targetFilePath, %assetItem); - %assetItem.roughnessImageAsset = %roughnessAsset; - } - } - - if(%assetItem.smoothnessImageAsset $= "") - { - %smoothnessTypeSuffixes = getAssetImportConfigValue("Images/SmoothnessTypeSuffixes", ""); - - %targetFilePath = %this.findMaterialMapFileWSuffix(%fileDir, %fileName, %fileExt, %smoothnessTypeSuffixes); - - if(%targetFilePath !$= "") - { - ImportActivityLog.add("Auto-Populated Smoothness Map Image Asset via file: " @ %targetFilePath); - - %smoothnessAsset = AssetBrowser.addImportingAsset("ImageAsset", %targetFilePath, %assetItem); - %assetItem.SmoothnessImageAsset = %smoothnessAsset; - } - } - - if(%assetItem.AOImageAsset $= "") - { - %aoTypeSuffixes = getAssetImportConfigValue("Images/AOTypeSuffixes", ""); - - %targetFilePath = %this.findMaterialMapFileWSuffix(%fileDir, %fileName, %fileExt, %aoTypeSuffixes); - - if(%targetFilePath !$= "") - { - ImportActivityLog.add("Auto-Populated AO Map Image Asset via file: " @ %targetFilePath); - - %AOAsset = AssetBrowser.addImportingAsset("ImageAsset", %targetFilePath, %assetItem); - %assetItem.AOImageAsset = %AOAsset; - } - } - - if(%assetItem.compositeImageAsset $= "") - { - %compositeTypeSuffixes = getAssetImportConfigValue("Images/CompositeTypeSuffixes", ""); - - %targetFilePath = %this.findMaterialMapFileWSuffix(%fileDir, %fileName, %fileExt, %compositeTypeSuffixes); - - if(%targetFilePath !$= "") - { - ImportActivityLog.add("Auto-Populated Composite Map Image Asset via file: " @ %targetFilePath); - - %compositeAsset = AssetBrowser.addImportingAsset("ImageAsset", %targetFilePath, %assetItem); - %assetItem.compositeImageAsset = %compositeAsset; - } - } - - //If after the above we didn't find any, check to see if we should be generating one - if(%assetItem.compositeImageAsset $= "" && - (%assetItem.roughnessImageAsset !$= "" || %assetItem.AOImageAsset !$= "" || %assetItem.metalnessImageAsset !$= "") && - getAssetImportConfigValue("Materials/CreateComposites", "1") == 1) - { - %assetItem.roughnessImageAsset.skip = true; - %assetItem.AOImageAsset.skip = true; - %assetItem.metalnessImageAsset.skip = true; - - %compositeAssetPath = AssetBrowser.dirHandler.currentAddress @ "/"; - %saveAsPath = %compositeAssetPath @ "/" @ %assetItem.assetName @ "_composite.png"; - - ImportActivityLog.add("Auto-Generated Composite Map from ORM maps"); - - %compositeAsset = AssetBrowser.addImportingAsset("ImageAsset", "", %assetItem, %assetItem.assetName @ "_composite"); - %compositeAsset.generatedAsset = true; - %compositeAsset.filePath = %saveAsPath; - - %assetItem.compositeImageAsset = %compositeAsset; - }*/ - } - - %assetItem.processed = true; - - refreshImportAssetWindow(); -} - -function AssetBrowser::findMaterialMapFileWSuffix(%this, %fileDir, %filename, %fileExt, %suffixesList) -{ - %listCount = getTokenCount(%suffixesList, ",;"); - - %foundFile = 0; - %filePath = ""; - for(%i=0; %i < %listCount; %i++) - { - %entryText = getToken(%suffixesList, ",;", %i); - - if(%fileExt $= "") - { - %filePath = findFirstFile(%fileDir @ "/" @ %filename @ %entryText @ ".*"); - %foundFile = isFile(%filePath); - } - else - { - %filePath = %fileDir @ "/" @ %filename @ %entryText @ %fileExt; - %foundFile = isFile(%filePath); - } - - if(%foundFile) - { - return %filePath; - } - } - - return ""; -} - -function AssetBrowser::importMaterialAsset(%this, %assetItem) -{ - %moduleName = AssetImportTargetModule.getText(); - - %assetType = %assetItem.AssetType; - %filePath = %assetItem.filePath; - %assetName = %assetItem.assetName; - %assetImportSuccessful = false; - %assetId = %moduleName@":"@%assetName; - - %assetPath = NewAssetTargetAddress.getText() @ "/"; - %tamlpath = %assetPath @ %assetName @ ".asset.taml"; - %sgfPath = %assetPath @ %assetName @ ".sgf"; - %scriptPath = %assetPath @ %assetName @ "." @ $TorqueScriptFileExtension; - - %newAsset = new MaterialAsset() - { - assetName = %assetName; - versionId = 1; - shaderGraph = %sgfPath; - scriptFile = %assetName @ "." @ $TorqueScriptFileExtension; - materialDefinitionName = %assetName; - }; - - //No point in indicating the original path data if it was imported in-place - %mainPath = getMainDotCsDir(); - if(!startsWith(makeFullPath(%filePath), getMainDotCsDir())) - { - %newAsset.originalFilePath = %filePath; - } - - //check dependencies - %dependencySlotId = 0; - for(%i=0; %i < %assetItem.childAssetItems.count(); %i++) - { - %childAssetItem = %assetItem.childAssetItems.getKey(%i); - - if(!isObject(%childAssetItem) || %childAssetItem.skip || %childAssetItem.processed == false) - continue; - - %depAssetType = %childAssetItem.assetType; - if(%depAssetType $= "ImageAsset") - { - %matSet = "%newAsset.imageMap"@%dependencySlotId@"=\"@asset="@%moduleName@":"@%childAssetItem.assetName@"\";"; - eval(%matSet); - %dependencySlotId++; - } - } - - %assetImportSuccessful = TamlWrite(%newAsset, %tamlpath); - - //if we're set to save a composite image, we do that first - if(getAssetImportConfigValue("Materials/CreateComposites", "1") == 1) - { - //don't save a composite if we've already got one bound - if(%assetItem.compositeImageAsset !$= "" && %assetItem.compositeImageAsset.generatedAsset) - { - if(%assetItem.roughnessImageAsset !$= "" || %assetItem.AOImageAsset !$= "" || %assetItem.metalnessImageAsset !$= "") - { - %channelKey = "0 1 2 3"; - - saveCompositeTexture(%assetItem.AOImageAsset.filePath, - %assetItem.roughnessImageAsset.filePath, - %assetItem.metalnessImageAsset.filePath,"", - %channelKey, - %assetItem.compositeImageAsset.filePath); - - %compositeAssetId = %moduleName @ ":" @ assetItem.compositeImageAsset.assetName; - AssetDatabase.refreshAsset(%compositeAssetId); - } - } - } - - %file = new FileObject(); - - if(%file.openForWrite(%scriptPath)) - { - %file.writeline("//--- OBJECT WRITE BEGIN ---"); - %file.writeline("singleton Material(" @ %assetName @ ") {"); - - //TODO: pass along the shape's target material for this just to be sure - %file.writeLine(" mapTo = \"" @ %assetName @ "\";"); - - //now we re-iterate back over our child items so we can map them correctly - for(%i=0; %i < %assetItem.childAssetItems.count(); %i++) - { - %childAssetItem = %assetItem.childAssetItems.getKey(%i); - - if(!isObject(%childAssetItem) || %childAssetItem.skip || %childAssetItem.processed == false) - continue; - - if(%childAssetItem.assetType $= "ImageAsset") - { - %mapFieldName = ""; - if(%childAssetItem.imageType $= "Albedo") - %mapFieldName = "DiffuseMap"; - else if(%childAssetItem.imageType $= "Normal") - %mapFieldName = "NormalMap"; - else if(%childAssetItem.imageType $= "Metalness") - %mapFieldName = "MetalMap"; - else if(%childAssetItem.imageType $= "Roughness") - %mapFieldName = "RoughnessMap"; - else if(%childAssetItem.imageType $= "AO") - %mapFieldName = "AOMap"; - else if(%childAssetItem.imageType $= "Composite") - %mapFieldName = "ORMConfigMap"; - - %path = fileName(%childAssetItem.filePath); - %file.writeline(" "@ %mapFieldName @ "[0] = \"" @ %path @"\";"); - %file.writeline(" "@ %mapFieldName @ "Asset[0] = \"" @ %moduleName @ ":" @ %childAssetItem.assetName @"\";"); - } - } - %file.writeline("};"); - %file.writeline("//--- OBJECT WRITE END ---"); - - %file.close(); - } - - %moduleDef = ModuleDatabase.findModule(%moduleName,1); - - if(!AssetBrowser.isAssetReImport) - AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath); - else - AssetDatabase.refreshAsset(%assetId); -} - -function AssetBrowser::buildMaterialAssetPreview(%this, %assetDef, %previewData, %forcePreviewRegenerate) +function MaterialAsset::buildBrowserElement(%this, %previewData) { %previewData.previewImage = "ToolsModule:genericAssetIcon_image"; %previewData.previewLoaded = false; //this marks it for loading progressively later - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.scriptFile; + %previewData.assetName = %this.assetName; + %previewData.assetPath = %this.scriptFile; - %previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; + %previewData.assetFriendlyName = %this.assetName; + %previewData.assetDesc = %this.description; if(%this.selectMode) - %previewData.doubleClickCommand = "AssetBrowser.selectAsset( AssetBrowser.selectedAsset );"; + %previewData.doubleClickCommand = $CurrentAssetBrowser @ ".selectAsset( " @ $CurrentAssetBrowser @ ".selectedAsset );"; else - %previewData.doubleClickCommand = "AssetBrowser.editAsset( "@%assetDef@" );"; + %previewData.doubleClickCommand = $CurrentAssetBrowser @ ".editAsset( "@%this@" );"; - %definitionPath = %assetDef.getScriptPath(); + %definitionPath = %this.getScriptPath(); if(%definitionPath $= "") - %definitionPath = %assetDef.getFilename(); + %definitionPath = %this.getFilename(); - %previewData.tooltip = "Asset Name: " @ %assetDef.assetName @ + %previewData.tooltip = "Asset Name: " @ %this.assetName @ "\nAsset Type: Material Asset" @ - "\nAsset Definition ID: " @ %assetDef @ + "\nAsset Definition ID: " @ %this @ "\nDefinition Path: " @ %definitionPath; - if(!%this.selectMode) + if(!$CurrentAssetBrowser.selectMode) { - %previewData.doubleClickCommand = "AssetBrowser.editAsset( "@%assetDef@" );"; + %previewData.doubleClickCommand = $CurrentAssetBrowser @ ".editAsset( "@%this@" );"; } } -function AssetBrowser::generateMaterialAssetPreviewImage(%this, %previewButton, %forceRegenerate) +function MaterialAsset::generatePreviewImage(%this, %previewButton, %forceRegenerate) { if(%forceRegenerate $= "") %forceRegenerate = false; - %assetId = %previewButton.moduleName @ ":" @ %previewButton.assetName; - - %assetDef = AssetDatabase.acquireAsset(%assetId); - - %module = %this.dirHandler.getModuleFromAddress(makeRelativePath(filePath(AssetDatabase.getAssetFilePath(%assetDef.getAssetId())))); + %module = $CurrentAssetBrowser.dirHandler.getModuleFromAddress(makeRelativePath(filePath(AssetDatabase.getAssetFilePath(%this.getAssetId())))); %previewPath = "tools/resources/previewCache/" @ %module.moduleId @ "/"; if(!IsDirectory(%previewPath)) { - %this.dirHandler.createFolder(%previewPath); + $CurrentAssetBrowser.dirHandler.createFolder(%previewPath); } %generatePreview = false; - %previewFilePath = %previewPath @ %assetDef.assetName @ "_Preview.dds"; + %previewFilePath = %previewPath @ %this.assetName @ "_Preview.dds"; if(!isFile(%previewFilePath)) { %generatePreview = true; } else { - if(isObject(%assetDef.materialDefinitionName)) + if(isObject(%this.materialDefinitionName)) { - if(compareFileTimes(%assetDef.materialDefinitionName.getDiffuseMap(0), %previewFilePath) == 1 || - compareFileTimes(%assetDef.materialDefinitionName.getFilename(), %previewFilePath) == 1) + if(compareFileTimes(%this.materialDefinitionName.getDiffuseMap(0), %previewFilePath) == 1 || + compareFileTimes(%this.materialDefinitionName.getFilename(), %previewFilePath) == 1) %generatePreview = true; } } - %previewAssetName = %module.moduleId @ "_" @ %assetDef.assetName @ "_PreviewImage"; + %previewAssetName = %module.moduleId @ "_" @ %this.assetName @ "_PreviewImage"; if(%generatePreview || %forceRegenerate) { - if(isObject(%assetDef.materialDefinitionName)) + if(isObject(%this.materialDefinitionName)) { //real fast, we'll be 100% sure that the image resource we need is loaded - %diffuseMapAssetId = %assetDef.materialDefinitionName.getDiffuseMapAsset(0); + %diffuseMapAssetId = %this.materialDefinitionName.getDiffuseMapAsset(0); if(AssetDatabase.isDeclaredAsset(%diffuseMapAssetId)) { %diffuseMapAsset = AssetDatabase.acquireAsset(%diffuseMapAssetId); AssetDatabase.releaseAsset(%diffuseMapAssetId); } %previewShapeDef = AssetDatabase.acquireAsset("ToolsModule:previewSphereShape"); - %generatedFilePath = %previewShapeDef.generateCachedPreviewImage(256, %assetDef.materialDefinitionName); + %generatedFilePath = %previewShapeDef.generateCachedPreviewImage(256, %this.materialDefinitionName); pathCopy(%generatedFilePath, %previewFilePath, false); fileDelete(%generatedFilePath); @@ -548,7 +181,7 @@ function AssetBrowser::generateMaterialAssetPreviewImage(%this, %previewButton, return false; } -function AssetBrowser::onMaterialAssetEditorDropped(%this, %assetDef, %position) +function MaterialAsset::onWorldEditorDropped(%this, %position) { //echo("DROPPED A SHAPE ON THE EDITOR WINDOW!"); //first, see if we hit a static shape @@ -558,26 +191,24 @@ function AssetBrowser::onMaterialAssetEditorDropped(%this, %assetDef, %position) %camPos = LocalClientConnection.camera.getPosition(); %rayResult = materialRayCast(%camPos, %targetPosition, -1, 0, false); - %validTarget = false; if(%rayResult != 0) { %obj = getWord(%rayResult, 0); if(%obj.isMemberOfClass("TSStatic")) { //oh, cool a valid target! - %obj.materialSlot0 = %assetDef.getAssetId(); - echo("MaterialSlot0 set to " @ %assetDef.getAssetId()); + %obj.materialSlot0 = %this.getAssetId(); + //echo("MaterialSlot0 set to " @ %this.getAssetId()); } else if(%obj.isField("materialAsset")) { - %obj.materialAsset = %assetDef.getAssetId(); - echo("materialAsset set to " @ %assetDef.getAssetId()); + %obj.materialAsset = %this.getAssetId(); + //echo("materialAsset set to " @ %this.getAssetId()); } %obj.inspectPostApply(); + + EWorldEditor.isDirty = true; } - - EWorldEditor.isDirty = true; - } function GuiInspectorTypeMaterialAssetPtr::onControlDropped( %this, %payload, %position ) diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/particle.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/particle.tscript deleted file mode 100644 index e69de29bb..000000000 diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/postFX.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/postFX.tscript index 3d684bf47..4933a06e0 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/postFX.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/postFX.tscript @@ -1,8 +1,10 @@ -function AssetBrowser::createPostEffectAsset(%this) +AssetBrowser::registerAssetType("PostEffectAsset", "Post Effects"); + +function PostEffectAsset::onCreateNew() { - %moduleName = AssetBrowser.newAssetSettings.moduleName; + %moduleName = $CurrentAssetBrowser.newAssetSettings.moduleName; - %assetName = AssetBrowser.newAssetSettings.assetName; + %assetName = $CurrentAssetBrowser.newAssetSettings.assetName; %assetPath = NewAssetTargetAddress.getText() @ "/"; %tamlpath = %assetPath @ %assetName @ ".asset.taml"; @@ -27,7 +29,7 @@ function AssetBrowser::createPostEffectAsset(%this) %file = new FileObject(); %templateFile = new FileObject(); - %postFXTemplateCodeFilePath = %this.templateFilesPath @ "postFXFile." @ $TorqueScriptFileExtension @ ".template"; + %postFXTemplateCodeFilePath = $CurrentAssetBrowser.templateFilesPath @ "postFXFile." @ $TorqueScriptFileExtension @ ".template"; if(%file.openForWrite(%scriptPath) && %templateFile.openForRead(%postFXTemplateCodeFilePath)) { @@ -37,7 +39,7 @@ function AssetBrowser::createPostEffectAsset(%this) %line = strreplace( %line, "@@", %assetName ); %file.writeline(%line); - echo(%line); + //echo(%line); } %file.close(); @@ -48,11 +50,11 @@ function AssetBrowser::createPostEffectAsset(%this) %file.close(); %templateFile.close(); - warnf("CreatePostFXAsset - Something went wrong and we couldn't write the PostFX script file!"); + warn("PostEffectAsset::onCreateNew() - Something went wrong and we couldn't write the PostFX script file!"); } //hlsl shader - %postFXTemplateCodeFilePath = %this.templateFilesPath @ "postFXFileP.hlsl.template"; + %postFXTemplateCodeFilePath = $CurrentAssetBrowser.templateFilesPath @ "postFXFileP.hlsl.template"; if(%file.openForWrite(%hlslPath) && %templateFile.openForRead(%postFXTemplateCodeFilePath)) { @@ -62,7 +64,7 @@ function AssetBrowser::createPostEffectAsset(%this) %line = strreplace( %line, "@@", %assetName ); %file.writeline(%line); - echo(%line); + //echo(%line); } %file.close(); @@ -73,11 +75,11 @@ function AssetBrowser::createPostEffectAsset(%this) %file.close(); %templateFile.close(); - warnf("CreatePostFXAsset - Something went wrong and we couldn't write the PostFX hlsl file!"); + warn("PostEffectAsset::onCreateNew() - Something went wrong and we couldn't write the PostFX hlsl file!"); } //glsl shader - %postFXTemplateCodeFilePath = %this.templateFilesPath @ "postFXFileP.glsl.template"; + %postFXTemplateCodeFilePath = $CurrentAssetBrowser.templateFilesPath @ "postFXFileP.glsl.template"; if(%file.openForWrite(%glslPath) && %templateFile.openForRead(%postFXTemplateCodeFilePath)) { @@ -87,7 +89,7 @@ function AssetBrowser::createPostEffectAsset(%this) %line = strreplace( %line, "@@", %assetName ); %file.writeline(%line); - echo(%line); + //echo(%line); } %file.close(); @@ -98,72 +100,80 @@ function AssetBrowser::createPostEffectAsset(%this) %file.close(); %templateFile.close(); - warnf("CreatePostFXAsset - Something went wrong and we couldn't write the PostFX glsl file!"); + warn("PostEffectAsset::onCreateNew() - Something went wrong and we couldn't write the PostFX glsl file!"); } return %tamlpath; } -//Renames the asset -function AssetBrowser::renamePostEffectAsset(%this, %assetDef, %newAssetName) +function PostEffectAsset::buildBrowserElement(%this, %previewData) { - %newScriptFilename = renameAssetLooseFile(%assetDef.scriptPath, %newAssetName); - - if(!%newScriptFilename $= "") - return; - - %newHLSLFilename = renameAssetLooseFile(%assetDef.hlslShader, %newAssetName); - - if(!%newHLSLFilename $= "") - return; - - %newGLSLFilename = renameAssetLooseFile(%assetDef.glslShader, %newAssetName); - - if(!%newGLSLFilename $= "") - return; - - %assetDef.scriptPath = %newScriptFilename; - %assetDef.hlslShader = %newHLSLFilename; - %assetDef.glslShader = %newGLSLFilename; - %assetDef.saveAsset(); - - renameAssetFile(%assetDef, %newAssetName); -} - -//Deletes the asset -function AssetBrowser::deletePostEffectAsset(%this, %assetDef) -{ - AssetDatabase.deleteAsset(%assetDef.getAssetId(), true); -} - -//Moves the asset to a new path/module -function AssetBrowser::movePostEffectAsset(%this, %assetDef, %destination) -{ - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.getScriptPath(), %destination); - moveAssetLooseFile(%assetDef.getHLSLShaderPath(), %destination); - moveAssetLooseFile(%assetDef.getGLSLShaderPath(), %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); -} - -function AssetBrowser::buildPostEffectAssetPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.scriptFilePath; + %previewData.assetName = %this.assetName; + %previewData.assetPath = %this.scriptFilePath; %previewData.doubleClickCommand = ""; %previewData.previewImage = "ToolsModule:postEffectIcon_image"; - %previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = "Asset Name: " @ %assetDef.assetName @ "\nDefinition Path: " @ %assetDef.getFilename(); + %previewData.assetFriendlyName = %this.assetName; + %previewData.assetDesc = %this.description; + %previewData.tooltip = "Asset Name: " @ %this.assetName @ + "\nDefinition Path: " @ %this.getFilename(); +} + +function PostEffectAsset::onShowActionMenu(%this) +{ + GenericAsset::onShowActionMenu(%this); + + if( !isObject( EditPostFXAssetSubmenuPopup ) ) + { + new PopupMenu( EditPostFXAssetSubmenuPopup ) + { + superClass = "MenuBuilder"; + class = "EditorWorldMenu"; + + jumpFileName = ""; + jumpLineNumber = ""; + }; + } + + //Regen the menu so we're fully up and current with options and references + EditPostFXAssetSubmenuPopup.clearItems(); + + EditPostFXAssetSubmenuPopup.item[ 0 ] = "Script file" TAB "" TAB %this @ ".onEditScriptFile();"; + EditPostFXAssetSubmenuPopup.item[ 1 ] = "HLSL file" TAB "" TAB %this @ ".onEditHLSLFile();"; + EditPostFXAssetSubmenuPopup.item[ 2 ] = "GLSL file" TAB "" TAB %this @ ".onEditHLSLFile();"; + + EditPostFXAssetSubmenuPopup.reloadItems(); + + EditAssetPopup.item[ 0 ] = "Edit PostFX Asset Files" TAB EditPostFXAssetSubmenuPopup; + + EditAssetPopup.reloadItems(); + + EditAssetPopup.showPopup(Canvas); + + $CurrentAssetBrowser.popupMenu = EditAssetPopup; +} + +function PostEffectAsset::onEditScriptFile(%this) +{ + if(isFunction("systemCommand")) + eval("systemCommand(\"start \\\"\\\" \\\"" @ %this.getScriptPath() @ "\\\"\");"); + else + warn("PostEffectAsset::onEditScriptFile() - systemCommand function disabled in this build. Unable to launch application to edit file."); +} + +function PostEffectAsset::onEditHLSLFile(%this) +{ + if(isFunction("systemCommand")) + eval("systemCommand(\"start \\\"\\\" \\\"" @ %this.getHLSLShaderPath() @ "\\\"\");"); + else + warn("PostEffectAsset::onEditHLSLFile() - systemCommand function disabled in this build. Unable to launch application to edit file."); +} + +function PostEffectAsset::onEditGLSLFile(%this) +{ + if(isFunction("systemCommand")) + eval("systemCommand(\"start \\\"\\\" \\\"" @ %this.getGLSLShaderPath() @ "\\\"\");"); + else + warn("PostEffectAsset::onEditGLSLFile() - systemCommand function disabled in this build. Unable to launch application to edit file."); } \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/prefab.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/prefab.tscript index dba63f846..08a8cf393 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/prefab.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/prefab.tscript @@ -1,9 +1,11 @@ -function AssetBrowser::createPrefab(%this) +AssetBrowser::registerFileType("PrefabFileType", "Prefabs", ".prefab"); + +function PrefabFileType::onCreateNew() { - %moduleName = AssetBrowser.newAssetSettings.moduleName; + %moduleName = $CurrentAssetBrowser.newAssetSettings.moduleName; %modulePath = "data/" @ %moduleName; - %assetName = AssetBrowser.newAssetSettings.assetName; + %assetName = $CurrentAssetBrowser.newAssetSettings.assetName; %assetPath = NewAssetTargetAddress.getText() @ "/"; @@ -13,46 +15,32 @@ function AssetBrowser::createPrefab(%this) EWorldEditor.makeSelectionPrefab( %prefabFilePath ); EditorTree.buildVisibleTree( true ); + + $CurrentAssetBrowser.refresh(); } -function AssetBrowser::buildPrefabPreview(%this, %assetDef, %previewData) +function PrefabFileType::buildBrowserElement(%filePath, %previewData) { - %fullPath = %assetDef.dirPath @ "/" @ %assetDef.assetName; - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %fullPath; + %previewData.assetName = fileName(%filePath); + %previewData.assetPath = %filePath; + + echo("PrefabFileType::buildBrowserElement() - name, path: " @ %previewData.assetName @ ", " @ %filePath); %previewData.previewImage = "ToolsModule:prefabIcon_image"; //%previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = %fullPath; + %previewData.assetDesc = %filePath; + %previewData.tooltip = %filePath; //%previewData.doubleClickCommand = "AssetBrowser.schedule(10, \"navigateTo\",\""@ %assetDef.dirPath @ "/" @ %assetDef.assetName @"\");";//browseTo %assetDef.dirPath / %assetDef.assetName - %previewData.doubleClickCommand = "AssetBrowser.autoImportFile(\"" @ %fullPath @ "\");"; + %previewData.doubleClickCommand = "AssetBrowser.autoImportFile(\"" @ %filePath @ "\");"; } -function AssetBrowser::onPrefabEditorDropped(%this, %assetDef, %position) +function PrefabFileType::onWorldEditorDropped(%filePath, %position) { - //echo("DROPPED A SHAPE ON THE EDITOR WINDOW!"); - - %targetPosition = EWorldEditor.unproject(%position SPC 1); - %camPos = LocalClientConnection.camera.getPosition(); - %rayResult = containerRayCast(%camPos, %targetPosition, -1); - - %pos = ObjectCreator.getCreateObjectPosition(); - - if(%rayResult != 0) - { - %pos = getWords(%rayResult, 1, 3); - } - else - { - %pos = "0 0 0"; - } - %newPrefab = new Prefab() { - position = %pos; - fileName = %assetDef; + position = %position; + fileName = %filePath; }; getScene(0).add(%newPrefab); diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/script.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/script.tscript index cc93fcdc1..2d9d2fcbe 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/script.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/script.tscript @@ -1,9 +1,12 @@ -function AssetBrowser::createScriptAsset(%this) +AssetBrowser::registerFileType("ScriptFileType", "Script Files", ".tscript;.cs;.dso;.tscript.dso;.cs.dso", false); +AssetBrowser::registerAssetType("ScriptAsset", "Scripts"); + +function ScriptAsset::onCreateNew() { - %moduleName = AssetBrowser.newAssetSettings.moduleName; + %moduleName = $CurrentAssetBrowser.newAssetSettings.moduleName; %modulePath = "data/" @ %moduleName; - %assetName = AssetBrowser.newAssetSettings.assetName; + %assetName = $CurrentAssetBrowser.newAssetSettings.assetName; %assetPath = NewAssetTargetAddress.getText() @ "/"; @@ -32,97 +35,122 @@ function AssetBrowser::createScriptAsset(%this) return %tamlpath; } -function AssetBrowser::editScriptAsset(%this, %assetDef) +function ScriptAsset::onEdit(%this) { - %scriptFile = %assetDef.scriptFile; + %scriptFile = %this.scriptFile; - //EditorOpenFileInTorsion(makeFullPath(%scriptFile), 0); + if(isFunction("systemCommand")) + eval("systemCommand(\"start \\\"\\\" \\\"" @ %this.fileName @ "\\\"\");"); + else + warn("ScriptAsset::onEdit() - systemCommand function disabled in this build. Unable to launch application to edit file."); } -function AssetBrowser::duplicateScriptAsset(%this, %assetDef, %targetModule) +function ScriptAsset::buildBrowserElement(%this, %previewData) { -} - -function AssetBrowser::importScriptAsset(%this, %assetId) -{ -} - -function AssetBrowser::onScriptAssetEditorDropped(%this, %assetDef, %position) -{ - -} - -//Renames the asset -function AssetBrowser::renameScriptAsset(%this, %assetDef, %newAssetName) -{ - %newFilename = renameAssetLooseFile(%assetDef.scriptFile, %newAssetName); + %previewData.assetName = %this.assetName; + %previewData.assetPath = %this.fileName; - if(!%newFilename $= "") - return; - - %assetDef.scriptFile = %newFilename; - %assetDef.saveAsset(); - - renameAssetFile(%assetDef, %newAssetName); -} - -//Deletes the asset -function AssetBrowser::deleteScriptAsset(%this, %assetDef) -{ - AssetDatabase.deleteAsset(%assetDef.getAssetId(), true); -} - -//Moves the asset to a new path/module -function AssetBrowser::moveScriptAsset(%this, %assetDef, %destination) -{ - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.getScriptPath(), %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); -} - -function AssetBrowser::buildScriptAssetPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.scriptFile; - //%previewData.doubleClickCommand = "EditorOpenFileInTorsion( \""@%previewData.assetPath@"\", 0 );"; - - if(%assetDef.isServerSide) + if(%this.isServerSide) %previewData.previewImage = "ToolsModule:serverScriptIcon_image"; else %previewData.previewImage = "ToolsModule:clientScriptIcon_image"; - %previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = "Asset Name: " @ %assetDef.assetName @ "\nDefinition Path: " @ %assetDef.getFilename(); -} - -function AssetBrowser::buildTScriptPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.scriptFile; - //%previewData.doubleClickCommand = "EditorOpenFileInTorsion( \""@%previewData.assetPath@"\", 0 );"; - - if(%assetDef.isServerSide) - %previewData.previewImage = "ToolsModule:serverScriptIcon_image"; - else - %previewData.previewImage = "ToolsModule:clientScriptIcon_image"; - - %previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = "Asset Name: " @ %assetDef.assetName @ "\nDefinition Path: " @ %assetDef.getFilename(); + %previewData.assetFriendlyName = %this.assetName; + %previewData.assetDesc = %this.fileName; + %previewData.tooltip = "Script Asset: " @ %this.getAssetId() @ "\n" @ + "File path: " @ %this.fileName; } function GuiInspectorTypeScriptAssetPtr::onClick( %this, %fieldName ) { //Get our data %obj = %this.getInspector().getInspectObject(0); +} + +//============================================================================== +// Handling for random script files in the browser +//============================================================================== +function ScriptFileType::buildBrowserElement(%filePath, %previewData) +{ + %previewData.assetName = fileName(%filePath); + %previewData.assetPath = %filePath; + %previewData.doubleClickCommand = "systemCommand(\"start \\\"\\\" \\\"" @ %filePath @ "\\\"\");"; + + /*if(%assetDef.isServerSide) + %previewData.previewImage = "ToolsModule:serverScriptIcon_image"; + else + %previewData.previewImage = "ToolsModule:clientScriptIcon_image";*/ + %previewData.previewImage = "ToolsModule:clientScriptIcon_image"; + + %previewData.assetFriendlyName = %previewData.assetName; + %previewData.assetDesc = %filePath; + %previewData.tooltip = "Script File: " @ %filePath; +} + +function ScriptAssetType::onEdit(%filePath) +{ + if(isFunction("systemCommand")) + eval("systemCommand(\"start \\\"\\\" \\\"" @ %filePath @ "\\\"\");"); + else + warn("ScriptAssetType::onEdit() - systemCommand function disabled in this build. Unable to launch application to edit file."); +} + +function ScriptFileType::onShowActionMenu(%filePath) +{ + if( !isObject( EditScriptFileTypePopup ) ) + { + new PopupMenu( EditScriptFileTypePopup ) + { + superClass = "MenuBuilder"; + class = "EditorWorldMenu"; + + jumpFileName = ""; + jumpLineNumber = ""; + }; + } + + //Regen the menu so we're fully up and current with options and references + EditScriptFileTypePopup.clearItems(); + + EditScriptFileTypePopup.item[ 0 ] = "Edit File" TAB "" TAB $CurrentAssetBrowser @ ".editAsset();"; + EditScriptFileTypePopup.item[ 1 ] = "Rename File" TAB "" TAB $CurrentAssetBrowser @ ".renameAsset();"; + EditScriptFileTypePopup.item[ 2 ] = "-"; + EditScriptFileTypePopup.item[ 3 ] = "Duplicate File" TAB "" TAB $CurrentAssetBrowser @ ".duplicateAsset();"; + EditScriptFileTypePopup.item[ 4 ] = "-"; + EditScriptFileTypePopup.item[ 5 ] = "Open File Location" TAB "" TAB $CurrentAssetBrowser @ ".openFileLocation();"; + EditScriptFileTypePopup.item[ 6 ] = "-"; + EditScriptFileTypePopup.item[ 7 ] = "Delete File" TAB "" TAB $CurrentAssetBrowser @ ".deleteAsset();"; + EditScriptFileTypePopup.item[ 8 ] = "-"; + EditScriptFileTypePopup.item[ 9 ] = "File Properties" TAB "" TAB $CurrentAssetBrowser @ ".editAssetInfo();"; + + EditScriptFileTypePopup.objectData = %filePath; + EditScriptFileTypePopup.objectType = "ScriptFileType"; + + EditScriptFileTypePopup.reloadItems(); + + EditScriptFileTypePopup.showPopup(Canvas); + + $CurrentAssetBrowser.popupMenu = EditScriptFileTypePopup; +} + +function ScriptFileType::onEditProperties(%filePath) +{ + Canvas.pushDialog(AssetBrowser_editAsset); + + AssetBrowser_editAssetWindow.text = "Script File Properties - " @ %filePath; + + AssetBrowser_editAsset.editedObjectData = %filePath; + //AssetBrowser_editAsset.editedObject = SpecialAssetEditInspector.tempAsset; + AssetBrowser_editAsset.editedObjectType = "ScriptFileType"; + + AssetEditInspector.startGroup("Script File Properties"); + AssetEditInspector.addField("$ScriptFileType::ExecutionMode", "Execution Mode", "list", "How should this script file be executed by the module", "Server", "Client;Server;Shared;None"); + AssetEditInspector.addField("$ScriptFileType::ExecutionOverride", "Do Execution Override", "bool", "Should this execution override files that share the same name?", "false"); + AssetEditInspector.addField("$ScriptFileType::ExecutionConditions", "Execution Conditional", "command", "Does the execution of this script file have special conditionals?", ""); + AssetEditInspector.endGroup("Script File Properties"); +} + +function ScriptFileType::onSaveProperties(%filePath) +{ + //Do voodoo here } \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript index c333903a2..6749c688f 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shape.tscript @@ -1,285 +1,60 @@ -function AssetBrowser::createShapeAsset(%this) +AssetBrowser::registerAssetType("ShapeAsset", "Shapes"); + +function ShapeAsset::onEdit(%this) { - %moduleName = AssetBrowser.newAssetSettings.moduleName; - %modulePath = "data/" @ %moduleName; - - %assetName = AssetBrowser.newAssetSettings.assetName; - - %assetPath = NewAssetTargetAddress.getText() @ "/"; - - %tamlpath = %assetPath @ %assetName @ ".asset.taml"; - %shapeFilePath = %assetPath @ %assetName @ ".dae"; - - %asset = new ShapeAsset() + if(EditorSettings.value("Assets/Browser/doubleClickAction", "Edit Asset") $= "Edit Asset") { - AssetName = %assetName; - versionId = 1; - friendlyName = AssetBrowser.newAssetSettings.friendlyName; - description = AssetBrowser.newAssetSettings.description; - fileName = %assetName @ ".dae"; - }; - - TamlWrite(%asset, %tamlpath); - - Canvas.popDialog(AssetBrowser_newComponentAsset); - - %moduleDef = ModuleDatabase.findModule(%moduleName, 1); - AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath); - - AssetBrowser.refresh(); - - return %tamlpath; -} - -function AssetBrowser::editShapeAsset(%this, %assetDef) -{ - %this.hideDialog(); - EditorGui.setEditor( ShapeEditorPlugin ); - ShapeEditorPlugin.openShapeAsset(%assetDef); -} - -function AssetBrowser::onShapeAssetChanged(%this, %assetDef) -{ -} - -function AssetBrowser::deleteShapeAsset(%this, %assetDef) -{ - -} - -function AssetBrowser::moveShapeAsset(%this, %assetDef, %destination) -{ - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.getShapePath(), %destination); - moveAssetLooseFile(%assetDef.getShapeConstructorFilePath(), %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); -} - -function AssetBrowser::prepareImportShapeAsset(%this, %assetItem) -{ - ImportActivityLog.add("Preparing Shape for Import: " @ %assetItem.assetName); - - %fileExt = fileExt(%assetItem.filePath); - - if(!isObject(%assetItem.shapeInfo)) - { - %shapeInfo = new GuiTreeViewCtrl(); - if(%fileExt $= ".dae") - { - enumColladaForImport(%assetItem.filePath, %shapeInfo, false); - } - else if(%fileExt $= ".dts") - { - %shapeInfo.insertItem(0, "Shape", 1); - %shapeInfo.insertItem(0, "Animations", 0); - } - else - { - GetShapeInfo(%assetItem.filePath, %shapeInfo, false); - } - - %assetItem.shapeInfo = %shapeInfo; + $CurrentAssetBrowser.hideDialog(); + EditorGui.setEditor( ShapeEditorPlugin ); + ShapeEditorPlugin.openShapeAsset(%this); } - - %shapeCount = %assetItem.shapeInfo._meshCount; - %shapeItem = %assetItem.shapeInfo.findItemByName("Meshes"); - - //%shapeId = ImportAssetTree.findItemByObjectId(%assetItem); - - if(getAssetImportConfigValue("Meshes/ImportMesh", "1") == 1 && %shapeCount > 0) + else { - } - - %animCount = %assetItem.shapeInfo._animCount; - %animItem = %assetItem.shapeInfo.findItemByName("Animations"); - - if(getAssetImportConfigValue("Animations/ImportAnimations", "1") == 1 && %animCount > 0) - { - } - - %matCount = %assetItem.shapeInfo._materialCount; - %matItem = %assetItem.shapeInfo.findItemByName("Materials"); - - ImportActivityLog.add(" Shape Info: Mesh Count: " @ %shapeCount @ " | Material Count: " @ %matCount @ " | Anim Count: " @ %animCount); - - if(getAssetImportConfigValue("Materials/ImportMaterials", "1") == 1 && %matCount > 0) - { - %materialItem = %assetItem.shapeInfo.getChild(%matItem); - processShapeMaterialInfo(%assetItem, %materialItem); - - %materialItem = %assetItem.shapeInfo.getNextSibling(%materialItem); - while(%materialItem != 0) - { - processShapeMaterialInfo(%assetItem, %materialItem); - - %materialItem = %assetItem.shapeInfo.getNextSibling(%materialItem); - } - } -} - -function AssetBrowser::importShapeAsset(%this, %assetItem) -{ - %moduleName = AssetImportTargetModule.getText(); - - %assetType = %assetItem.AssetType; - %filePath = %assetItem.filePath; - %assetName = %assetItem.assetName; - %assetImportSuccessful = false; - %assetId = %moduleName@":"@%assetName; - - %assetPath = NewAssetTargetAddress.getText() @ "/"; - %assetFullPath = %assetPath @ fileName(%filePath); - - %newAsset = new ShapeAsset() - { - assetName = %assetName; - versionId = 1; - fileName = fileName(%filePath); - isNewShape = true; - }; - - //No point in indicating the original path data if it was imported in-place - if(!startsWith(makeFullPath(%filePath), getMainDotCsDir())) - { - %newAsset.originalFilePath = %filePath; - } - - //check dependencies - %dependencySlotId = 0; - for(%i=0; %i < %assetItem.childAssetItems.count(); %i++) - { - %childAssetItem = %assetItem.childAssetItems.getKey(%i); - - if(!isObject(%childAssetItem) || %childAssetItem.skip || %childAssetItem.processed == false) - continue; - - %depAssetType = %childAssetItem.assetType; - if(%childAssetItem.assetType $= "MaterialAsset") - { - %matSet = "%newAsset.materialSlot"@%dependencySlotId@"=\"@asset="@%moduleName@":"@%childAssetItem.assetName@"\";"; - eval(%matSet); - %dependencySlotId++; - } - else if(%depAssetType $= "AnimationAsset") - { - %matSet = "%newAsset.animationSequence"@%dependencySlotId@"=\"@asset="@%moduleName@":"@%childAssetItem.assetName@"\";"; - eval(%matSet); - %dependencySlotId++; - } - } - - %assetImportSuccessful = TAMLWrite(%newAsset, %assetPath @ %assetName @ ".asset.taml"); - - //and copy the file into the relevent directory - if(filePath(%filePath) !$= filePath(%assetFullPath)) - { - %doOverwrite = !AssetBrowser.isAssetReImport; - if(!pathCopy(%filePath, %assetFullPath, %doOverwrite)) - { - error("Unable to import asset: " @ %filePath); - } - } - - %constructor = ShapeEditor.findConstructor( %assetFullPath ); - - if(!isObject(%constructor)) - %constructor = ShapeEditor.createConstructor(%assetFullPath); - - //We'll update any relevent bits to the ShapeConstructor here - $TSShapeConstructor::neverImportMat = ""; - - if(getAssetImportConfigValue("Materials/IgnoreMaterials", "") !$= "") - { - %ignoreMaterialList = getAssetImportConfigValue("Materials/IgnoreMaterials", ""); - %ignoredMatNamesCount = getTokenCount(%ignoreMaterialList, ",;"); - for(%i=0; %i < %ignoredMatNamesCount; %i++) - { - if(%i==0) - $TSShapeConstructor::neverImportMat = getToken(%ignoreMaterialList, ",;", %i); - else - $TSShapeConstructor::neverImportMat = $TSShapeConstructor::neverImportMat TAB getToken(%ignoreMaterialList, ",;", %i); - } + %this.onWorldEditorDropped(); } - - if(getAssetImportConfigValue("Materials/DoUpAxisOverride", "") $= "1") - %constructor.upAxis = getAssetImportConfigValue("Meshes/UpAxisOverride", "Z_AXIS"); - - if(getAssetImportConfigValue("Meshes/DoScaleOverride", "0") $= "1") - %constructor.unit = getAssetImportConfigValue("Meshes/ScaleOverride", "1"); - else - %constructor.unit = -1; - - %constructor.lodType = getAssetImportConfigValue("Meshes/LODType", "0"); - //%constructor.singleDetailSize = getAssetImportConfigValue("Meshes/convertLeftHanded", "0"); - %constructor.alwaysImport = getAssetImportConfigValue("Meshes/AlwaysImportedNodes", ""); - %constructor.neverImport = getAssetImportConfigValue("Meshes/AlwaysIgnoreNodes", ""); - %constructor.alwaysImportMesh = getAssetImportConfigValue("Meshes/AlwaysImportMeshes", ""); - %constructor.neverImportMesh = getAssetImportConfigValue("Meshes/AlwaysIgnoreMeshes", ""); - %constructor.ignoreNodeScale = getAssetImportConfigValue("Meshes/IgnoreNodeScale", "0"); - %constructor.adjustCenter = getAssetImportConfigValue("Meshes/AdjustCenter", "0"); - %constructor.adjustFloor = getAssetImportConfigValue("Meshes/AdjustFloor", "0"); - - %constructor.convertLeftHanded = getAssetImportConfigValue("Meshes/convertLeftHanded", "0"); - %constructor.calcTangentSpace = getAssetImportConfigValue("Meshes/calcTangentSpace", "0"); - %constructor.genUVCoords = getAssetImportConfigValue("Meshes/genUVCoords", "0"); - %constructor.flipUVCoords = getAssetImportConfigValue("Meshes/flipUVCoords", "0"); - %constructor.findInstances = getAssetImportConfigValue("Meshes/findInstances", "0"); - %constructor.limitBoneWeights = getAssetImportConfigValue("Meshes/limitBoneWeights", "0"); - %constructor.joinIdenticalVerts = getAssetImportConfigValue("Meshes/joinIdenticalVerts", "0"); - %constructor.reverseWindingOrder = getAssetImportConfigValue("Meshes/reverseWindingOrder", "0"); - %constructor.invertNormals = getAssetImportConfigValue("Meshes/invertNormals", "0"); - %constructor.removeRedundantMats = getAssetImportConfigValue("Meshes/removeRedundantMats", "0"); - %constructor.animTiming = getAssetImportConfigValue("Animations/animTiming", "Seconds"); - %constructor.animFPS = getAssetImportConfigValue("Animations/animFPS", "2"); - - %constructor.neverImportMat = $TSShapeConstructor::neverImportMat; - ShapeEditor.saveConstructor( %constructor ); - - //now, force-load the file if it's collada - /*%fileExt = fileExt(%assetFullPath); - if(isSupportedFormat(getSubStr(%fileExt,1))) - { - %tempShape = new TSStatic() - { - shapeName = %assetFullPath; - }; - - %tempShape.delete(); - }*/ - - %moduleDef = ModuleDatabase.findModule(%moduleName,1); - - if(!AssetBrowser.isAssetReImport) - AssetDatabase.addDeclaredAsset(%moduleDef, %assetPath @ %assetName @ ".asset.taml"); - else - AssetDatabase.refreshAsset(%assetId); } -function AssetBrowser::buildShapeAssetPreview(%this, %assetDef, %previewData, %forcePreviewRegenerate) +function ShapeAsset::onShowActionMenu(%assetDef) +{ + GenericAsset::onShowActionMenu(%assetDef); +} + +function ShapeAsset::onChanged(%this) +{ + echo("ShapeAsset::onChanged() - asset " @ %this.assetId @ " has changed!"); +} + +function ShapeAsset::onDelete(%this) +{ + //Special handle the cache preview image + %module = $CurrentAssetBrowser.dirHandler.getModuleFromAddress(makeRelativePath(filePath(%this.getShapePath()))); + %previewPath = "tools/resources/previewCache/" @ %module.moduleId @ "/" @ %this.assetName @ "_Preview.dds"; + + if(isFile(%previewPath)) + { + $CurrentAssetBrowser.dirHandler.deleteFile(%previewPath); + } + + //then just let the Generic function handle the rest + GenericAsset::onDelete(%this); +} + +function ShapeAsset::buildBrowserElement(%this, %previewData) { %previewData.previewImage = "ToolsModule:genericAssetIcon_image"; %previewData.previewLoaded = false; //this marks it for loading progressively later - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.fileName; + %previewData.assetName = %this.assetName; + %previewData.assetPath = %this.fileName; - %previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = "Asset Name: " @ %assetDef.assetName @ "\n" @ + %previewData.assetFriendlyName = %this.assetName; + %previewData.assetDesc = %this.description; + %previewData.tooltip = "Asset Name: " @ %this.assetName @ "\n" @ "Asset Type: Shape Asset\n" @ - "Asset Definition ID: " @ %assetDef @ "\n" @ - "Shape File path: " @ %assetDef.getShapePath(); + "Asset Definition ID: " @ %this @ "\n" @ + "Shape File path: " @ %this.getShapePath(); - if(%this.selectMode) + /*if(%this.selectMode) { %previewData.doubleClickCommand = "AssetBrowser.selectAsset( AssetBrowser.selectedAsset );"; } @@ -293,41 +68,39 @@ function AssetBrowser::buildShapeAssetPreview(%this, %assetDef, %previewData, %f { %previewData.doubleClickCommand = "AssetBrowser.onShapeAssetEditorDropped( "@%assetDef@" );"; } - } + }*/ } -function AssetBrowser::generateShapeAssetPreviewImage(%this, %previewButton, %forceRegenerate) +function ShapeAsset::generatePreviewImage(%this, %previewButton, %forceRegenerate) { if(%forceRegenerate $= "") %forceRegenerate = false; - %assetId = %previewButton.moduleName @ ":" @ %previewButton.assetName; - - %assetDef = AssetDatabase.acquireAsset(%assetId); - - %module = %this.dirHandler.getModuleFromAddress(makeRelativePath(filePath(%assetDef.getShapePath()))); + %assetId = %this.getAssetId(); + + %module = %previewButton.assetBrowser.dirHandler.getModuleFromAddress(makeRelativePath(filePath(%this.getShapePath()))); %previewPath = "tools/resources/previewCache/" @ %module.moduleId @ "/"; if(!IsDirectory(%previewPath)) { - %this.dirHandler.createFolder(%previewPath); + %previewButton.assetBrowser.dirHandler.createFolder(%previewPath); } %generatePreview = false; - %previewFilePath = %previewPath @ %assetDef.assetName @ "_Preview.dds"; - if(!isFile(%previewFilePath) || (compareFileTimes(%assetDef.getShapePath(), %previewFilePath) == 1)) + %previewFilePath = %previewPath @ %this.assetName @ "_Preview.dds"; + if(!isFile(%previewFilePath) || (compareFileTimes(%this.getShapePath(), %previewFilePath) == 1)) { %generatePreview = true; } - %previewAssetName = %module.moduleId @ "_" @ %assetDef.assetName @ "_PreviewImage"; + %previewAssetName = %module.moduleId @ "_" @ %this.assetName @ "_PreviewImage"; if(%generatePreview || %forceRegenerate) { //real fast, we'll be 100% sure that the image resource we need is loaded - %matSlot0AssetId = %assetDef.materialSlot0; + %matSlot0AssetId = %this.materialSlot0; if(AssetDatabase.isDeclaredAsset(%matSlot0AssetId)) { %matAsset = AssetDatabase.acquireAsset(%matSlot0AssetId); @@ -337,7 +110,7 @@ function AssetBrowser::generateShapeAssetPreviewImage(%this, %previewButton, %fo //This is slightly hacky, but we're going to utilize the imposter/last detail system //to generate our previews for us and then clean up the unneeded bits - %filePath = %assetDef.generateCachedPreviewImage(); + %filePath = %this.generateCachedPreviewImage(); pathCopy(%filePath, %previewFilePath, false); fileDelete(%filePath); //cleanup @@ -380,7 +153,7 @@ function AssetBrowser::generateShapeAssetPreviewImage(%this, %previewButton, %fo return false; } -function AssetBrowser::onShapeAssetEditorDropped(%this, %assetDef, %position) +function ShapeAsset::onWorldEditorDropped(%assetDef, %position) { %assetId = %assetDef.getAssetId(); @@ -402,6 +175,11 @@ function AssetBrowser::onShapeAssetEditorDropped(%this, %assetDef, %position) MECreateUndoAction::submit(%newStatic ); } +function ShapeAsset::onGUIEditorDropped(%assetDef, %position) +{ + +} + function GuiInspectorTypeShapeAssetPtr::onControlDropped( %this, %payload, %position ) { Canvas.popDialog(EditorDragAndDropLayer); diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shapeAnimation.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shapeAnimation.tscript index 2593599b5..d0aa7ac03 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shapeAnimation.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/shapeAnimation.tscript @@ -1,57 +1,16 @@ -function AssetBrowser::createShapeAnimationAsset(%this) -{ - %dlg = new OpenFileDialog() - { - Filters = "Animation Files(*.dae, *.cached.dts)|*.dae;*.cached.dts"; - DefaultPath = $Pref::WorldEditor::LastPath; - DefaultFile = ""; - ChangePath = false; - OverwritePrompt = true; - forceRelativePath = false; - //MultipleFiles = true; - }; +AssetBrowser::registerAssetType("ShapeAnimationAsset", "Shape Anims"); - %ret = %dlg.Execute(); - - if ( %ret ) - { - $Pref::WorldEditor::LastPath = filePath( %dlg.FileName ); - %fullPath = %dlg.FileName; - } - - %dlg.delete(); - - if ( !%ret ) - return; -} - -function AssetBrowser::editShapeAnimationAsset(%this, %assetDef) +function ShapeAnimationAsset::onEdit(%this) { - %this.hideDialog(); + $CurrentAssetBrowser.hideDialog(); EditorGui.setEditor( ShapeEditorPlugin ); - ShapeEditorPlugin.openShapeAsset(%assetDef); + ShapeEditorPlugin.openShapeAsset(%this); } -function AssetBrowser::moveShapeAnimationAsset(%this, %assetDef, %destination) +function ShapeAnimationAsset::buildBrowserElement(%this, %previewData) { - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.getAnimationPath(), %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); -} - -function AssetBrowser::buildShapeAnimationAssetPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.animationName; - %previewData.assetPath = %assetDef.scriptFile; + %previewData.assetName = %this.animationName; + %previewData.assetPath = %this.scriptFile; //Lotta prepwork /*%previewData.doubleClickCommand = %assetDef@".materialDefinitionName.reload(); " @@ -66,7 +25,9 @@ function AssetBrowser::buildShapeAnimationAssetPreview(%this, %assetDef, %previe %previewData.previewImage = "ToolsModule:animationIcon_image"; - %previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = %assetDef.friendlyName @ "\n" @ %assetDef @ "\nShape File path: " @ %assetDef.getShapePath(); + %previewData.assetFriendlyName = %this.assetName; + %previewData.assetDesc = %this.description; + %previewData.tooltip = %this.friendlyName @ "\n" + @ %this @ "\nShape File path: " + @ %this.getShapePath(); } \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/sound.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/sound.tscript index f5a072d5b..8ed6919bf 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/sound.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/sound.tscript @@ -1,61 +1,50 @@ -function AssetBrowser::editSoundAsset(%this, %assetDef) +AssetBrowser::registerAssetType("SoundAsset", "Sounds"); + +function SoundAsset::onEdit(%this) { if (isObject($PreviewSoundSource)) sfxStop($PreviewSoundSource); - $PreviewSoundSource = %assetDef.playSound(); + $PreviewSoundSource = %this.playSound(); } -function AssetBrowser::onSoundAssetChanged(%this, %assetDef) +function SoundAsset::onChanged(%this) { if (isObject($PreviewSoundSource)) sfxStop($PreviewSoundSource); } -function AssetBrowser::moveSoundAsset(%this, %assetDef, %destination) +function SoundAsset::buildBrowserElement(%this, %previewData) { - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.getSoundPath(), %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); -} - -function AssetBrowser::buildSoundAssetPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.soundFilePath; + %previewData.assetName = %this.assetName; + %previewData.assetPath = %this.soundFilePath; if(%this.selectMode) { - %previewData.doubleClickCommand = "AssetBrowser.selectAsset( AssetBrowser.selectedAsset );"; + %previewData.doubleClickCommand = $CurrentAssetBrowser @ ".selectAsset( " @ $CurrentAssetBrowser @ ".selectedAsset );"; } else { - if(EditorSettings.value("Assets/Browser/doubleClickAction", "Edit Asset") $= "Edit Asset") + %previewData.doubleClickCommand = $CurrentAssetBrowser @ ".editAsset( "@ %this @" );"; + + /*if(EditorSettings.value("Assets/Browser/doubleClickAction", "Edit Asset") $= "Edit Asset") { - %previewData.doubleClickCommand = "AssetBrowser.editAsset( "@%assetDef@" );"; + %previewData.doubleClickCommand = $CurrentAssetBrowser @ ".editAsset( "@ %this @" );"; } else { - %previewData.doubleClickCommand = "AssetBrowser.onSoundAssetEditorDropped( "@%assetDef@" );"; - } + %previewData.doubleClickCommand = $CurrentAssetBrowser @ ".onSoundAssetEditorDropped( "@ %this @" );"; + }*/ } %previewData.previewImage = "ToolsModule:soundIcon_image"; - %previewData.assetFriendlyName = %assetDef.assetName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = "Asset Name: " @ %assetDef.assetName @ "\nDefinition Path: " @ %assetDef.getFilename(); + %previewData.assetFriendlyName = %this.assetName; + %previewData.assetDesc = %this.description; + %previewData.tooltip = "Asset Name: " @ %this.assetName @ + "\nDefinition Path: " @ %this.getFilename(); } -function AssetBrowser::onSoundAssetEditorDropped(%this, %assetDef, %position) +function SoundAsset::onWorldEditorDropped(%this, %position) { %targetPosition = EWorldEditor.unproject(%position SPC 1); %camPos = LocalClientConnection.camera.getPosition(); @@ -72,14 +61,12 @@ function AssetBrowser::onSoundAssetEditorDropped(%this, %assetDef, %position) %pos = "0 0 0"; } - %assetId = %assetDef.getAssetId(); - %newSFXEmitter = new SFXEmitter() { position = %pos; - soundAsset = %assetDef.getAssetId(); - pitch = %assetDef.pitchAdjust; - volume = %assetDef.volumeAdjust; + soundAsset = %this.getAssetId(); + pitch = %this.pitchAdjust; + volume = %this.volumeAdjust; }; getScene(0).add(%newSFXEmitter); @@ -91,15 +78,15 @@ function AssetBrowser::onSoundAssetEditorDropped(%this, %assetDef, %position) } -function AssetBrowser::onSoundAssetGUIEditorDropped(%this, %assetDef, %position) +function SoundAsset::onGUIEditorDropped(%this, %position) { - %assetId = %assetDef.getAssetId(); + %assetId = %this.getAssetId(); %cmd = "new GuiAudioCtrl(){"; %cmd = %cmd @ "SoundAsset =\""@ %assetId @"\";"; %cmd = %cmd @ "position =\""@ %position @"\";"; %cmd = %cmd @ "};"; %ctrl = GuiEditCanvas.createObject(%cmd); - echo(%ctrl SPC "created"); + //echo(%ctrl SPC "created"); } function GuiInspectorTypeSoundAssetPtr::onControlDropped( %this, %payload, %position ) diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/stateMachine.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/stateMachine.tscript deleted file mode 100644 index 4234f6d28..000000000 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/stateMachine.tscript +++ /dev/null @@ -1,161 +0,0 @@ -function AssetBrowser::createStateMachineAsset(%this) -{ - %assetName = AssetBrowser.newAssetSettings.assetName; - %moduleName = AssetBrowser.selectedModule; - %assetPath = NewAssetTargetAddress.getText() @ "/"; - - %assetQuery = new AssetQuery(); - - %matchingAssetCount = AssetDatabase.findAssetName(%assetQuery, %assetName); - - %i=1; - while(%matchingAssetCount > 0) - { - %newAssetName = %assetName @ %i; - %i++; - - %matchingAssetCount = AssetDatabase.findAssetName(%assetQuery, %newAssetName); - } - - %assetName = %newAssetName; - - %assetQuery.delete(); - - %tamlpath = %assetPath @ %assetName @ ".asset.taml"; - %smFilePath = %assetPath @ %assetName @ ".xml"; - - %asset = new StateMachineAsset() - { - AssetName = %assetName; - versionId = 1; - stateMachineFile = %assetName @ ".xml"; - }; - - %xmlDoc = new SimXMLDocument(); - %xmlDoc.saveFile(%smFilePath); - %xmlDoc.delete(); - - TamlWrite(%asset, %tamlpath); - - //Now write our XML file - %xmlFile = new FileObject(); - %xmlFile.openForWrite(%smFilePath); - %xmlFile.writeLine(""); - %xmlFile.writeLine(""); - %xmlFile.close(); - - %moduleDef = ModuleDatabase.findModule(%moduleName, 1); - AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath); - - AssetBrowser.refresh(); - - return %tamlpath; -} - -function AssetBrowser::editStateMachineAsset(%this, %assetDef) -{ - eval("AssetBrowser.tempAsset = new " @ %assetDef.getClassName() @ "();"); - AssetBrowser.tempAsset.assignFieldsFrom(%assetDef); - - SMAssetEditInspector.inspect(AssetBrowser.tempAsset); - AssetBrowser_editAsset.editedAssetId = EditAssetPopup.assetId; - AssetBrowser_editAsset.editedAsset = AssetBrowser.tempAsset; - - //remove some of the groups we don't need: - for(%i=0; %i < SMAssetEditInspector.getCount(); %i++) - { - %caption = SMAssetEditInspector.getObject(%i).caption; - - if(%caption $= "Ungrouped" || %caption $= "Object" || %caption $= "Editing" - || %caption $= "Persistence" || %caption $= "Dynamic Fields") - { - SMAssetEditInspector.remove(SMAssetEditInspector.getObject(%i)); - %i--; - } - } - - Canvas.pushDialog(StateMachineEditor); - StateMachineEditor.loadStateMachineAsset(EditAssetPopup.assetId); - StateMachineEditor-->Window.text = "State Machine Editor ("@EditAssetPopup.assetId@")"; -} - -function AssetBrowser::duplicateStateMachineAsset(%this, %assetDef) -{ - // TODO: - %targetModule = ""; - - //Check if we have a target module, if not we need to select one - if(%targetModule $= "") - { - error("AssetBrowser::duplicateStateMachineAsset - No target module selected!"); - return; - } - - %assetId = %assetDef.getAssetId(); - %assetName = AssetDatabase.getAssetName(%assetId); - - //First step, copy the files - %modulePath = "data/" @ %targetModule @ "/stateMachines/"; - - if(!isDirectory(%modulePath)) - createPath(%modulePath); - - %assetFile = AssetDatabase.getAssetFilePath(%assetId); - %stateMachineFile = %assetDef.stateMachineFile; - - echo("AssetBrowser::duplicateGameObjectAsset - duplicating! " @ %assetId @ " to " @ %targetModule); - - %tamlPath = %modulePath @ fileName(%assetFile); - - pathCopy(%assetFile, %tamlPath); - pathCopy(%stateMachineFile, %modulePath @ fileName(%stateMachineFile)); - - echo("AssetBrowser::duplicateStateMachineAsset - duplicated!"); - - //Register the asset - %moduleDef = ModuleDatabase.findModule(%targetModule, 1); - - AssetDatabase.addDeclaredAsset(%moduleDef, %tamlPath); - - //Refresh the browser - AssetBrowser.refresh(); - - //Rename it for convenience - AssetBrowser.performRenameAsset(%assetName, "New" @ %assetName); -} - -function AssetBrowser::renameGameObjectAsset(%this, %assetDef, %newAssetId, %originalName, %newName) -{ - %assetPath = AssetDatabase.getAssetFilePath(%newAssetId); - - //rename the file to match - %path = filePath(%assetPath); - - %oldScriptFilePath = %assetDef.stateMachineFile; - %scriptFilePath = filePath(%assetDef.stateMachineFile); - %scriptExt = fileExt(%assetDef.stateMachineFile); - - %newScriptFileName = %scriptFilePath @ "/" @ %newName @ %scriptExt; - %newAssetFile = %path @ "/" @ %newName @ ".asset.taml"; - - %assetDef.stateMachineFile = %newScriptFileName; - - TamlWrite(%assetDef, %newAssetFile); - fileDelete(%assetPath); - - pathCopy(%oldScriptFilePath, %newScriptFileName); - fileDelete(%oldScriptFilePath); -} - -function AssetBrowser::buildStateMachineAssetPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.assetName; - %previewData.assetPath = %assetDef.scriptFile; - %previewData.doubleClickCommand = "AssetBrowser.editStateMachineAsset( "@%assetDef@" );"; - - %previewData.previewImage = "ToolsModule:stateMachineIcon_image"; - - %previewData.assetFriendlyName = %assetDef.friendlyName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = %assetDef.friendlyName @ "\n" @ %assetDef; -} \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/subScene.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/subScene.tscript new file mode 100644 index 000000000..bd72e7080 --- /dev/null +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/subScene.tscript @@ -0,0 +1,156 @@ +AssetBrowser::registerAssetType("SubSceneAsset", "SubScenes"); + +function SubSceneAsset::setupCreateNew() +{ + NewAssetPropertiesInspector.startGroup("SubScene"); + NewAssetPropertiesInspector.addField("LevelName", "SubScene Name", "String", "Human-readable name of new subScene", "", "", $CurrentAssetBrowser.newAssetSettings); + + NewAssetPropertiesInspector.endGroup(); +} + +function SubSceneAsset::onCreateNew(%this) +{ + %moduleName = $CurrentAssetBrowser.newAssetSettings.moduleName; + %modulePath = "data/" @ %moduleName; + + %assetName = $CurrentAssetBrowser.newAssetSettings.assetName; + + %assetPath = NewAssetTargetAddress.getText() @ "/"; + + %misExtension = ".subMis"; + + %tamlpath = %assetPath @ %assetName @ ".asset.taml"; + %levelPath = %assetPath @ %assetName @ %misExtension; + + %asset = new SubSceneAsset() + { + AssetName = %assetName; + versionId = 1; + LevelFile = %assetName @ %misExtension; + LevelName = $CurrentAssetBrowser.newAssetSettings.levelName; + AssetDescription = $CurrentAssetBrowser.newAssetSettings.description; + }; + + TamlWrite(%asset, %tamlpath); + + %fileObj = new FileObject(); + if (!%fileObj.openForWrite(%levelPath)) + { + echo("Unable to write subScene file!"); + } + else + { + %fileObj.writeLine(""); + %fileObj.close(); + %fileObj.delete(); + } + + %moduleDef = ModuleDatabase.findModule(%moduleName, 1); + %addSuccess = AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath); + + if(!%addSuccess) + { + error("SubSceneAsset::onCreateNew() - failed to add declared asset: " @ %tamlpath @ " for module: " @ %moduleDef); + } + + $CurrentAssetBrowser.refresh(); + + if(%addSuccess && isObject($createAndAssignField)) + { + $createAndAssignField.apply(%moduleName @ ":" @ %assetName); + $createAndAssignField = ""; + } + + return %tamlpath; +} + +function SubSceneAsset::buildBrowserElement(%this, %previewData) +{ + %previewData.assetName = %this.assetName; + %previewData.assetPath = %this.getLevelPath(); + %previewData.doubleClickCommand = "AssetBrowser.selectAsset(" @ %this @ ");"; + + %levelPreviewImage = %this.PreviewImage; + + if(isFile(%levelPreviewImage)) + %previewData.previewImage = %levelPreviewImage; + else + %previewData.previewImage = "ToolsModule:levelIcon_image"; + + %previewData.assetFriendlyName = %this.assetName; + %previewData.assetDesc = %this.description; + %previewData.tooltip = "Asset Name: " @ %this.assetName @ "\n" @ + "Asset Type: SubScene Asset\n" @ + "Asset Definition ID: " @ %this @ "\n" @ + "SubScene File path: " @ %this.getLevelPath(); +} + +function EWorldEditor::createSelectedAsSubScene( %this, %object ) +{ + //create new level asset here + AssetBrowser.setupCreateNewAsset("SubSceneAsset", AssetBrowser.selectedModule, "finishCreateSelectedAsSubScene"); + %this.contextActionObject = %object; +} + +function finishCreateSelectedAsSubScene(%assetId) +{ + //echo("finishCreateSelectedAsSubScene"); + + %subScene = new SubScene() { + levelAsset = %assetId; + }; + + %levelAssetDef = AssetDatabase.acquireAsset(%assetId); + %levelFilePath = %levelAssetDef.getLevelPath(); + + //write out to file + EWorldEditor.contextActionObject.save(%levelFilePath); + + AssetDatabase.releaseAsset(%assetId); + + getRootScene().add(%subScene); + + EWorldEditor.contextActionObject.delete(); + + %subScene.load(); + + %subScene.recalculateBounds(); + + %scalar = $SubScene::createScalar; + if(%scalar $= "") + %scalar = 1.5; + + //pad for loading boundary + %subScene.scale = VectorScale(%subScene.scale, %scalar); +} + +function SubSceneAsset::onWorldEditorDropped(%assetDef, %position) +{ + %assetId = %assetDef.getAssetId(); + + if(!%assetDef.isSubScene) + { + errorf("Cannot drag-and-drop LevelAsset into WorldEditor"); + return; + } + + %newSubScene = new SubScene() + { + position = %position; + levelAsset = %assetId; + }; + + getScene(0).add(%newSubScene); + + %newSubScene.load(); + %newSubScene.recalculateBounds(); + + EWorldEditor.clearSelection(); + EWorldEditor.selectObject(%newSubScene); + + EWorldEditor.dropSelection(); + + EWorldEditor.isDirty = true; + + MECreateUndoAction::submit(%newSubScene ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrain.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrain.tscript index 410360801..dd8e17524 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrain.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrain.tscript @@ -1,23 +1,25 @@ -function AssetBrowser::setupCreateNewTerrainAsset(%this) +AssetBrowser::registerAssetType("TerrainAsset", "Terrains"); + +function TerrainAsset::setupCreateNew() { NewAssetPropertiesInspector.startGroup("Terrain"); - NewAssetPropertiesInspector.addField("resolution", "Terrain Texture Resolution", "list", "Is this script used on the server?", "1024", "256,512,1024,2048,4096", %this.newAssetSettings); - NewAssetPropertiesInspector.addField("genWithNoise", "Generate Terrain With Noise", "bool", "Is this script used on the server?", "0", "2", %this.newAssetSettings); + NewAssetPropertiesInspector.addField("resolution", "Terrain Texture Resolution", "list", "Is this script used on the server?", "1024", "256,512,1024,2048,4096", $CurrentAssetBrowser.newAssetSettings); + NewAssetPropertiesInspector.addField("genWithNoise", "Generate Terrain With Noise", "bool", "Is this script used on the server?", "0", "2", $CurrentAssetBrowser.newAssetSettings); NewAssetPropertiesInspector.endGroup(); /*NewAssetPropertiesInspector.startGroup("Terrain - Import"); - NewAssetPropertiesInspector.addField("importDetails", "Import Heightmap", "button", "Import an existing heightmap", "", "Canvas.pushDialog( TerrainImportGui );", %this.newAssetSettings); + NewAssetPropertiesInspector.addField("importDetails", "Import Heightmap", "button", "Import an existing heightmap", "", "Canvas.pushDialog( TerrainImportGui );", $CurrentAssetBrowser.newAssetSettings); NewAssetPropertiesInspector.endGroup();*/ } -function AssetBrowser::createTerrainAsset(%this) +function TerrainAsset::onCreateNew() { - %moduleName = AssetBrowser.newAssetSettings.moduleName; + %moduleName = $CurrentAssetBrowser.newAssetSettings.moduleName; %modulePath = "data/" @ %moduleName; - %assetName = AssetBrowser.newAssetSettings.assetName; + %assetName = $CurrentAssetBrowser.newAssetSettings.assetName; - %assetType = AssetBrowser.newAssetSettings.assetType; + %assetType = $CurrentAssetBrowser.newAssetSettings.assetType; %assetPath = NewAssetTargetAddress.getText() @ "/"; //Ensure anything we generate goes into the right directory @@ -31,8 +33,8 @@ function AssetBrowser::createTerrainAsset(%this) AssetName = %assetName; versionId = 1; terrainFile = %assetName @ ".ter"; - resolution = %this.newAssetSettings.resolution; - genWithNoise = %this.newAssetSettings.genWithNoise; + resolution = $CurrentAssetBrowser.newAssetSettings.resolution; + genWithNoise = $CurrentAssetBrowser.newAssetSettings.genWithNoise; }; TamlWrite(%asset, %tamlpath); @@ -40,9 +42,9 @@ function AssetBrowser::createTerrainAsset(%this) %moduleDef = ModuleDatabase.findModule(%moduleName, 1); AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath); - AssetBrowser.refresh(); + $CurrentAssetBrowser.refresh(); - $createdTerrainBlock = TerrainBlock::createNew( %assetName, %this.newAssetSettings.resolution, "", %this.newAssetSettings.genWithNoise ); + $createdTerrainBlock = TerrainBlock::createNew( %assetName, $CurrentAssetBrowser.newAssetSettings.resolution, "", $CurrentAssetBrowser.newAssetSettings.genWithNoise ); MECreateUndoAction::submit($createdTerrainBlock); @@ -55,12 +57,12 @@ function AssetBrowser::createTerrainAsset(%this) // This will update an existing terrain with the name %terrainName, // or create a new one if %terrainName isn't a TerrainBlock $createdTerrainBlock = TerrainBlock::import( $createdTerrainBlock, - AssetBrowser.newAssetSettings.heightMapPng, - AssetBrowser.newAssetSettings.metersPerPixel, - AssetBrowser.newAssetSettings.heightScale, - AssetBrowser.newAssetSettings.opacityNames, - AssetBrowser.newAssetSettings.materialNames, - AssetBrowser.newAssetSettings.flipYAxis ); + $CurrentAssetBrowser.newAssetSettings.heightMapPng, + $CurrentAssetBrowser.newAssetSettings.metersPerPixel, + $CurrentAssetBrowser.newAssetSettings.heightScale, + $CurrentAssetBrowser.newAssetSettings.opacityNames, + $CurrentAssetBrowser.newAssetSettings.materialNames, + $CurrentAssetBrowser.newAssetSettings.flipYAxis ); if ( isObject( $createdTerrainBlock ) ) { @@ -130,87 +132,35 @@ function createTerrainBlock(%assetId) // } -function AssetBrowser::editTerrainAsset(%this, %assetDef) + +function TerrainAsset::onWorldEditorDropped(%this, %position) { + createTerrainBlock(%this.getAssetId()); } -function AssetBrowser::duplicateTerrainAsset(%this, %assetDef, %targetModule) +function TerrainAsset::buildBrowserElement(%this, %previewData) { -} - -function AssetBrowser::importTerrainAsset(%this, %assetDef) -{ -} - -function AssetBrowser::dragAndDropTerrainAsset(%this, %assetDef, %dropTarget) -{ - if(!isObject(%dropTarget)) - return; -} - -function AssetBrowser::onTerrainAssetEditorDropped(%this, %assetDef, %position) -{ - createTerrainBlock(%assetDef.getAssetId()); -} - -function AssetBrowser::renameTerrainAsset(%this, %assetDef, %newAssetId, %originalName, %newName) -{ -} - -function AssetBrowser::deleteTerrainAsset(%this, %assetDef) -{ -} - -function AssetBrowser::moveTerrainAsset(%this, %assetDef, %destination) -{ - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.getTerrainFilePath(), %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); -} - -function AssetBrowser::buildTerrainAssetPreview(%this, %assetDef, %previewData) -{ - %previewData.assetName = %assetDef.assetName; + %previewData.assetName = %this.assetName; %previewData.assetPath = ""; %previewData.previewImage = "ToolsModule:terrainIcon_image"; - %previewData.assetFriendlyName = %assetDef.gameObjectName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = "Asset Name: " @ %assetDef.assetName @ + %previewData.assetFriendlyName = %this.gameObjectName; + %previewData.assetDesc = %this.description; + %previewData.tooltip = "Asset Name: " @ %this.assetName @ "\nAsset Type: Terrain Asset" @ - "\nAsset Definition ID: " @ %assetDef @ - "\nDefinition Path: " @ %assetDef.getTerrainFilePath(); + "\nAsset Definition ID: " @ %this @ + "\nDefinition Path: " @ %this.getTerrainFilePath(); if(%this.selectMode) { - %previewData.doubleClickCommand = "AssetBrowser.selectAsset( AssetBrowser.selectedAsset );"; + %previewData.doubleClickCommand = $CurrentAssetBrowser @ ".selectAsset( " @ $CurrentAssetBrowser @ ".selectedAsset );"; } else { if(EditorSettings.value("Assets/Browser/doubleClickAction", "Edit Asset") $= "Edit Asset") %previewData.doubleClickCommand = ""; else - %previewData.doubleClickCommand = "createTerrainBlock(\""@%assetDef.getAssetId()@"\");"; + %previewData.doubleClickCommand = "createTerrainBlock(\""@%this.getAssetId()@"\");"; } -} - -function GuiInspectorTypeTerrainAssetPtr::onClick( %this, %fieldName ) -{ - //Get our data - %obj = %this.getInspector().getInspectObject(0); -} - -function GuiInspectorTypeTerrainAssetPtr::onControlDropped( %this, %payload, %position ) -{ - } \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrainMaterial.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrainMaterial.tscript index 2d5d096a1..a69cb0e10 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrainMaterial.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrainMaterial.tscript @@ -1,11 +1,13 @@ -function AssetBrowser::createTerrainMaterialAsset(%this) +AssetBrowser::registerAssetType("TerrainMaterialAsset", "Terrain Materials"); + +function TerrainMaterialAsset::onCreateNew() { - %moduleName = AssetBrowser.newAssetSettings.moduleName; + %moduleName = $CurrentAssetBrowser.newAssetSettings.moduleName; %modulePath = "data/" @ %moduleName; - %assetName = AssetBrowser.newAssetSettings.assetName; + %assetName = $CurrentAssetBrowser.newAssetSettings.assetName; - %assetType = AssetBrowser.newAssetSettings.assetType; + %assetType = $CurrentAssetBrowser.newAssetSettings.assetType; %assetPath = NewAssetTargetAddress.getText() @ "/"; %tamlpath = %assetPath @ %assetName @ ".asset.taml"; @@ -57,7 +59,7 @@ function AssetBrowser::createTerrainMaterialAsset(%this) AssetDatabase.acquireAsset("\"" @ %moduleName @ ":" @ %assetName @ "\""); - AssetBrowser.refresh(); + $CurrentAssetBrowser.refresh(); //If we've got the terrain mat editor open, go ahead and update it all TerrainMaterialDlg.onWake(); @@ -65,112 +67,70 @@ function AssetBrowser::createTerrainMaterialAsset(%this) return %tamlpath; } -function AssetBrowser::editTerrainMaterialAsset(%this, %assetDef) +function TerrainAssetMaterial::onEdit(%this) { TerrainMaterialDlg.show(0, 0, 0); - TerrainMaterialDlg.setActiveMaterial(%assetDef.assetName); + TerrainMaterialDlg.setActiveMaterial(%this.assetName); } -function AssetBrowser::duplicateTerrainMaterialAsset(%this, %assetDef, %targetModule) -{ -} - -function AssetBrowser::importTerrainMaterialAsset(%this, %assetDef) -{ -} - -function AssetBrowser::dragAndDropTerrainMaterialAsset(%this, %assetDef, %dropTarget) -{ - if(!isObject(%dropTarget)) - return; -} - -function AssetBrowser::renameTerrainMaterialAsset(%this, %assetDef, %newAssetId, %originalName, %newName) -{ -} - -function AssetBrowser::deleteTerrainMaterialAsset(%this, %assetDef) -{ -} - -function AssetBrowser::moveTerrainMaterialAsset(%this, %assetDef, %destination) -{ - %currentModule = AssetDatabase.getAssetModule(%assetDef.getAssetId()); - %targetModule = AssetBrowser.dirHandler.getModuleFromAddress(%destination); - - %newAssetPath = moveAssetFile(%assetDef, %destination); - - if(%newAssetPath $= "") - return false; - - moveAssetLooseFile(%assetDef.getScriptPath(), %destination); - - AssetDatabase.removeDeclaredAsset(%assetDef.getAssetId()); - AssetDatabase.addDeclaredAsset(%targetModule, %newAssetPath); -} - -function AssetBrowser::buildTerrainMaterialAssetPreview(%this, %assetDef, %previewData, %forcePreviewRegenerate) +function TerrainAssetMaterial::buildBrowserElement(%this, %previewData) { %previewData.previewImage = "ToolsModule:genericAssetIcon_image"; %previewData.previewLoaded = false; //this marks it for loading progressively later - %previewData.assetName = %assetDef.assetName; + %previewData.assetName = %this.assetName; %previewData.assetPath = ""; %previewData.doubleClickCommand = ""; - %previewData.assetFriendlyName = %assetDef.gameObjectName; - %previewData.assetDesc = %assetDef.description; - %previewData.tooltip = %assetDef.gameObjectName; + %previewData.assetFriendlyName = %this.gameObjectName; + %previewData.assetDesc = %this.description; + %previewData.tooltip = %this.gameObjectName; - %definitionPath = %assetDef.getScriptPath(); + %definitionPath = %this.getScriptPath(); if(%definitionPath $= "") - %definitionPath = %assetDef.getFilename(); + %definitionPath = %this.getFilename(); - %previewData.tooltip = "Asset Name: " @ %assetDef.assetName @ + %previewData.tooltip = "Asset Name: " @ %this.assetName @ "\nAsset Type: Terrain Material Asset" @ - "\nAsset Definition ID: " @ %assetDef @ + "\nAsset Definition ID: " @ %this @ "\nDefinition Path: " @ %definitionPath; } -function AssetBrowser::generateTerrainMaterialAssetPreviewImage(%this, %previewButton, %forceRegenerate) +function TerrainAssetMaterial::generatePreviewImage(%this, %previewButton, %forceRegenerate) { if(%forceRegenerate $= "") %forceRegenerate = false; - %assetId = %previewButton.moduleName @ ":" @ %previewButton.assetName; - - %assetDef = AssetDatabase.acquireAsset(%assetId); - - %module = %this.dirHandler.getModuleFromAddress(makeRelativePath(filePath(AssetDatabase.getAssetFilePath(%assetDef.getAssetId())))); + %module = $CurrentAssetBrowser.dirHandler.getModuleFromAddress(makeRelativePath(filePath(AssetDatabase.getAssetFilePath(%this.getAssetId())))); %previewPath = "tools/resources/previewCache/" @ %module.moduleId @ "/"; if(!IsDirectory(%previewPath)) { - %this.dirHandler.createFolder(%previewPath); + $CurrentAssetBrowser.dirHandler.createFolder(%previewPath); } %generatePreview = false; - %previewFilePath = %previewPath @ %assetDef.assetName @ "_Preview.dds"; + %previewFilePath = %previewPath @ %this.assetName @ "_Preview.dds"; if(!isFile(%previewFilePath)) { %generatePreview = true; } else { - if(isObject(%assetDef.materialDefinitionName)) + if(isObject(%this.materialDefinitionName)) { - if(compareFileTimes(%assetDef.materialDefinitionName.getDiffuseMap(), %previewFilePath) == 1 || - compareFileTimes(%assetDef.materialDefinitionName.getFilename(), %previewFilePath) == 1) + if(compareFileTimes(%this.materialDefinitionName.getDiffuseMap(), %previewFilePath) == 1 || + compareFileTimes(%this.materialDefinitionName.getFilename(), %previewFilePath) == 1) %generatePreview = true; } } - %previewAssetName = %module.moduleId @ "_" @ %assetDef.assetName @ "_PreviewImage"; + %previewAssetName = %module.moduleId @ "_" @ %this.assetName @ "_PreviewImage"; if(%generatePreview || %forceRegenerate) { - if(isObject(%assetDef.materialDefinitionName)) + if(isObject(%this.materialDefinitionName)) { %previewShapeDef = AssetDatabase.acquireAsset("ToolsModule:previewSphereShape"); %generatedFilePath = %previewShapeDef.generateCachedPreviewImage(256, DummyTerrMatPreview); @@ -178,7 +138,6 @@ function AssetBrowser::generateTerrainMaterialAssetPreviewImage(%this, %previewB pathCopy(%generatedFilePath, %previewFilePath); fileDelete(%generatedFilePath); - if(!AssetDatabase.isDeclaredAsset("ToolsModule:" @ %previewAssetName)) { %previewAsset = new ImageAsset() @@ -216,15 +175,4 @@ function AssetBrowser::generateTerrainMaterialAssetPreviewImage(%this, %previewB } return false; -} - -function GuiInspectorTypeTerrainMaterialAssetPtr::onClick( %this, %fieldName ) -{ - //Get our data - %obj = %this.getInspector().getInspectObject(0); -} - -function GuiInspectorTypeTerrainMaterialAssetPtr::onControlDropped( %this, %payload, %position ) -{ - } \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/directoryHandling.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/directoryHandling.tscript index 0df04615a..92ecd22e8 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/directoryHandling.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/directoryHandling.tscript @@ -179,6 +179,39 @@ function directoryHandler::getModuleFromAddress(%this, %address) return ""; } +function getModuleFromAddress(%address) +{ + %moduleList = ModuleDatabase.findModules(); + + for(%i=0; %i < getWordCount(%moduleList); %i++) + { + %module = getWord(%moduleList, %i); + %modulePath = makeRelativePath(%module.ModulePath); + + //We don't want to add stuff directly to the root core or tools modules + //if(%modulePath $= "Core" || %modulePath $= "Tools") + // continue; + + if(startsWith(%address, %modulePath)) + { + return %module; + } + } + /*//break down the address + %folderCount = getTokenCount(%address, "/"); + + for(%f=0; %f < %folderCount; %f++) + { + %folderName = getToken(%address, "/", %f); + + %module = ModuleDatabase.findModule(%folderName); + if(%module !$= "") + return %module; + }*/ + + return ""; +} + function directoryHandler::getFolderTreeItemFromAddress(%this, %address) { //break down the address diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/editAsset.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/editAsset.tscript index a88ed702b..092b64856 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/editAsset.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/editAsset.tscript @@ -1,67 +1,30 @@ function AssetBrowser_editAsset::saveAsset(%this) { - %file = AssetDatabase.getAssetFilePath(%this.editedAssetId); - %success = TamlWrite(AssetBrowser_editAsset.editedAsset, %file); + AssetBrowser_editAssetWindow.text = "Asset Properties"; - AssetBrowser.reloadAsset(%this.editedAssetId); - - AssetBrowser.refresh(); - - %assetType = AssetDatabase.getAssetType(%this.editedAssetId); - %assetDef = AssetDatabase.acquireAsset(%this.editedAssetId); - %assetDef.refreshAsset(); - - AssetBrowser.call("on" @ %assetType @ "Changed", %assetDef); - AssetDatabase.releaseAsset(%this.editedAssetId); + AssetBrowser.callAssetTypeFunc(%this.editedObjectType, "onSaveProperties", %this.editedObjectData); + AssetBrowser.callAssetTypeFunc(%this.editedObjectType, "onChanged", %this.editedObjectData); Canvas.popDialog(AssetBrowser_editAsset); } function AssetBrowser::editAsset(%this, %assetDef) { - //Find out what type it is - //If the passed-in definition param is blank, then we're likely called via a popup - if(%assetDef $= "") + if(%this.selectMode) { - if(AssetDatabase.isDeclaredAsset(EditAssetPopup.assetId)) - { - %assetDef = AssetDatabase.acquireAsset(EditAssetPopup.assetId); - } - else - { - //if it's not a valid asset at all, then it's probably a folder - %folder = strreplace(EditAssetPopup.assetId, ":", "/"); - if(isDirectory(%folder)) - { - AssetBrowser.navigateTo(%folder); - } - else - { - %object = getToken(EditAssetPopup.assetId, ":", 1); - if(isObject(%object)) - { - if(%object.isMemberOfClass("SimDatablock")) - { - DatablockEditorPlugin.openDatablock( %object ); - } - } - } - } + %this.selectAsset(%this.selectedAsset); } - else if(AssetDatabase.isDeclaredAsset(%assetDef)) + else { - //Turns out we were passed an assetid, not an asset definition. - //Grab the asset def from that - %assetDef = AssetDatabase.acquireAsset(%assetDef); - } - - if(%assetDef !$= "") - { - %assetType = %assetDef.getClassName(); - - //Build out the edit command - %buildCommand = %this @ ".edit" @ %assetType @ "(" @ %assetDef @ ");"; - eval(%buildCommand); + if(isObject(%assetDef)) + { + %assetType = AssetDatabase.getAssetType(%assetDef.getAssetId()); + %this.callAssetTypeFunc(%assetType, "onEdit", %assetDef); + } + else if(%this.popupMenu.objectType !$= "" && %this.popupMenu.objectData !$= "") + { + %this.callAssetTypeFunc(%this.popupMenu.objectType, "onEdit", %this.popupMenu.objectData); + } } } @@ -75,27 +38,9 @@ function AssetBrowser::appendSubLevel(%this) function AssetBrowser::editAssetInfo(%this) { - Canvas.pushDialog(AssetBrowser_editAsset); - - %assetDef = AssetDatabase.acquireAsset(EditAssetPopup.assetId); - - AssetBrowser.tempAsset = %assetDef.deepClone(); - - AssetEditInspector.inspect(AssetBrowser.tempAsset); - AssetBrowser_editAsset.editedAssetId = EditAssetPopup.assetId; - AssetBrowser_editAsset.editedAsset = AssetBrowser.tempAsset; - - //remove some of the groups we don't need: - for(%i=0; %i < AssetEditInspector.getCount(); %i++) + if(%this.popupMenu.objectType !$= "" && %this.popupMenu.objectData !$= "") { - %caption = AssetEditInspector.getObject(%i).caption; - - if(%caption $= "Ungrouped" || %caption $= "Object" || %caption $= "Editing" - || %caption $= "Persistence" || %caption $= "Dynamic Fields") - { - AssetEditInspector.remove(AssetEditInspector.getObject(%i)); - %i--; - } + %this.callAssetTypeFunc(%this.popupMenu.objectType, "onEditProperties", %this.popupMenu.objectData); } } @@ -127,17 +72,17 @@ function AssetBrowser::refreshAsset(%this, %assetId) //------------------------------------------------------------ function AssetBrowser::regeneratePreviewImage(%this) { - %assetDef = AssetDatabase.acquireAsset(EditAssetPopup.assetId); + %assetDef = AssetDatabase.acquireAsset(AssetBrowser.popupMenu.objectData); %dummyObj = new ScriptObject(); - %dummyObj.moduleName = AssetDatabase.getAssetModule(EditAssetPopup.assetId).moduleId; - %dummyObj.assetName = AssetDatabase.getAssetName(EditAssetPopup.assetId); - - %regenCommand = "AssetBrowser.generate" @ EditAssetPopup.assetType @ - "PreviewImage(" @ %dummyObj @ ", true);"; - eval(%regenCommand); + %dummyObj.moduleName = AssetDatabase.getAssetModule(AssetBrowser.popupMenu.objectData).moduleId; + %dummyObj.assetName = AssetDatabase.getAssetName(AssetBrowser.popupMenu.objectData); + + %assetType = AssetBrowser.popupMenu.objectType; + + AssetBrowser.callAssetTypeFunc(%assetType, "generatePreviewImage", %dummyObj, true); %dummyObj.delete(); - AssetDatabase.releaseAsset(EditAssetPopup.assetId); + AssetDatabase.releaseAsset(AssetBrowser.popupMenu.objectData); } //------------------------------------------------------------ @@ -344,8 +289,8 @@ function moveAssetLooseFile(%file, %destinationPath) function AssetBrowser::duplicateAsset(%this) { - %assetDef = AssetDatabase.acquireAsset(EditAssetPopup.assetId); - %assetType = AssetDatabase.getAssetType(EditAssetPopup.assetId); + %assetDef = AssetDatabase.acquireAsset(%this.popupMenu.objectData); + %assetType = %this.popupMenu.objectType; %trailingNum = getTrailingNumber(%assetDef.assetName); if(%trailingNum != -1) @@ -370,18 +315,16 @@ function AssetBrowser::duplicateAsset(%this) function AssetBrowser::doDuplicateAsset(%this) { - %assetDef = AssetDatabase.acquireAsset(EditAssetPopup.assetId); - %assetType = AssetDatabase.getAssetType(EditAssetPopup.assetId); + %assetType = %this.popupMenu.objectType; + %assetDef = AssetDatabase.acquireAsset(%this.popupMenu.objectData); if(AssetBrowser_assetNameEditTxt.text !$= "" && AssetBrowser_assetNameEditTxt.text !$= %assetDef.assetName) { - //this acts as a redirect based on asset type and will enact the appropriate function - //so for a GameObjectAsset, it'll become %this.duplicateGameObjectAsset(%assetDef, %targetModule); - //and call to the tools/assetBrowser/scripts/assetTypes/gameObject.tscript file for implementation - if(%this.isMethod("duplicate"@%assetType)) - eval(%this @ ".duplicate"@%assetType@"("@%assetDef@","@AssetBrowser_assetNameEditTxt.text@");"); - - AssetBrowser.refresh(); + AssetDatabase.releaseAsset(%this.popupMenu.objectData); + + %this.callAssetTypeFunc(%assetType, "onDuplicate", %this.popupMenu.objectData, AssetBrowser_assetNameEditTxt.text); + + %this.refresh(); } } @@ -440,31 +383,8 @@ function AssetBrowser::confirmDeleteAsset(%this) %currentSelectedItem = AssetBrowserFilterTree.getSelectedItem(); %currentItemParent = AssetBrowserFilterTree.getParentItem(%currentSelectedItem); - if(EditFolderPopup.visible) - { - if(EditFolderPopup.dirPath !$= "") - %folderPath = EditFolderPopup.dirPath; - else - %folderPath = AssetBrowserFilterTree.getItemValue(%currentSelectedItem) @ "/" @ AssetBrowserFilterTree.getItemText(%currentSelectedItem); - - if(%this.isMethod("deleteFolder")) - eval(%this @ ".deleteFolder(\""@%folderPath@"\");"); - } - else - { - %assetDef = AssetDatabase.acquireAsset(EditAssetPopup.assetId); - %assetType = AssetDatabase.getAssetType(EditAssetPopup.assetType); - - if(!isObject(%assetDef)) - return; - - //Do any cleanup required given the type - if(%this.isMethod("delete"@%assetType)) - eval(%this @ ".delete"@%assetType@"("@%assetDef@");"); - - AssetDatabase.deleteAsset(EditAssetPopup.assetId, true, false); - } - + %this.callAssetTypeFunc(%this.popupMenu.objectType, "onDelete", %this.popupMenu.objectData); + %this.refresh(); } @@ -522,21 +442,27 @@ function AssetBrowser::updateAssetReference(%this, %targetPath, %oldAssetId, %ne function AssetBrowser::openFileLocation(%this) { - %filePath = ""; - if(EditAssetPopup.assetId !$= "") + if(isFunction("systemCommand")) { - if(AssetDatabase.isDeclaredAsset(EditAssetPopup.assetId)) + warnf("AssetBrowser::openFileLocation() - systemCommand function disabled in this build. Unable to launch application to edit file."); + return; + } + + %filePath = ""; + if(%this.popuMenu.assetId !$= "") + { + if(AssetDatabase.isDeclaredAsset(%this.popuMenu.objectData)) { - %filePath = AssetDatabase.getAssetPath(EditAssetPopup.assetId); + %filePath = AssetDatabase.getAssetPath(%this.popuMenu.objectData); } else { //probably a file path - %pathSplit = strpos(EditAssetPopup.assetId, ":"); + %pathSplit = strpos(%this.popuMenu.objectData, ":"); if(%pathSplit != -1) { - %path = getSubStr(EditAssetPopup.assetId, 0, %pathSplit); - %file = getSubStr(EditAssetPopup.assetId, %pathSplit + 1); + %path = getSubStr(%this.popuMenu.objectData, 0, %pathSplit); + %file = getSubStr(%this.popuMenu.objectData, %pathSplit + 1); //datablocks pack the originator file in the parent path as-is, so check that if(fileExt(%path) !$= "") @@ -550,14 +476,6 @@ function AssetBrowser::openFileLocation(%this) } } } - else if(EditLevelAssetPopup.assetId !$= "") - { - %filePath = AssetDatabase.getAssetPath(EditAssetPopup.assetId); - } - else if(EditTerrainAssetPopup.assetId !$= "") - { - %filePath = AssetDatabase.getAssetPath(EditAssetPopup.assetId); - } if(isFile(%filePath) || isDirectory(%filePath)) { @@ -578,20 +496,27 @@ function AssetBrowser::openFileLocation(%this) } } -function AssetBrowser::openFolderLocation(%this) +function AssetBrowser::openFolderLocation(%this, %folderPath) { - %filePath = AssetBrowser.dirHandler.currentAddress; + if(!isFunction("systemCommand")) + { + warn("AssetBrowser::openFolderLocation() - systemCommand function disabled in this build. Unable to launch application to open this folder."); + return; + } - if(%filePath !$= "") + if(%folderPath $= "") + %folderPath = filePath(%this.dirHandler.currentAddress); + + if(%folderPath !$= "") { if($platform $= "windows") { - %cmd = "cd \"" @ makeFullPath(%filePath) @ "\" && start ."; + %cmd = "cd \"" @ makeFullPath(%folderPath) @ "\" && start ."; systemCommand(%cmd); } else { - %cmd = "open \"" @ makeFullPath(%filePath) @ "\""; + %cmd = "open \"" @ makeFullPath(%folderPath) @ "\""; systemCommand(%cmd); } } diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/newAsset.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/newAsset.tscript index feaf38688..ea05ecfb6 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/newAsset.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/newAsset.tscript @@ -119,11 +119,7 @@ function AssetBrowser::setupCreateNewAsset(%this, %assetType, %moduleName, %call NewAssetPropertiesInspector.addCallbackField("description", "Description", "Command", "Description of the new asset", "", "", "updateNewAssetField", %this.newAssetSettings); NewAssetPropertiesInspector.endGroup(); - if(%this.isMethod("setupCreateNew"@%assetType)) - { - %command = %this @ ".setupCreateNew"@%assetType @"();"; - eval(%command); - } + %this.callAssetTypeFunc(%assetType, "setupCreateNew"); NewAssetPropertiesInspector.refresh(); } @@ -255,7 +251,7 @@ function CreateNewAsset() return; } - %assetFilePath = eval(AssetBrowser @ ".create"@%assetType@"();"); + %assetFilePath = AssetBrowser.callAssetTypeFunc(%assetType, "onCreateNew"); Canvas.popDialog(AssetBrowser_newAsset); diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/popupMenus.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/popupMenus.tscript index 2df5bd3c7..b89365f22 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/popupMenus.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/popupMenus.tscript @@ -183,8 +183,6 @@ function AssetBrowser::buildPopupMenus(%this) item[12] = "View Loose Files" TAB "" TAB "AssetBrowser.importLooseFiles();"; Item[ 13 ] = "-"; item[ 14 ] = "Open Folder Location" TAB "" TAB "AssetBrowser.openFolderLocation();"; - - }; } @@ -266,13 +264,18 @@ function AssetBrowser::buildPopupMenus(%this) radioSelection = false; }; - AssetTypeListPopup.addItem(0, AssetFilterTypeList.getKey(0) TAB "" TAB "AssetBrowser.toggleAssetTypeFilter(" @ 0 @ ");"); + AssetTypeListPopup.addItem(0, "All" TAB "" TAB %this @ ".toggleAssetTypeFilter(0);"); AssetTypeListPopup.addItem(1, "-"); - for(%i=1; %i < AssetFilterTypeList.Count(); %i++) + %listIndex = 1; + for(%i=0; %i < ABAssetTypesList.Count(); %i++) { - %assetTypeName = AssetFilterTypeList.getKey(%i); - AssetTypeListPopup.addItem(%i+1, %assetTypeName TAB "" TAB "AssetBrowser.toggleAssetTypeFilter(" @ %i + 1 @ ");"); + %assetTypeData = ABAssetTypesList.getValue(%i); + if(getField(%assetTypeData, 3) != true) + continue; + + AssetTypeListPopup.addItem(%listIndex, getField(%assetTypeData,1) TAB "" TAB %this @ ".toggleAssetTypeFilter(" @ %listIndex @ ");"); + %listIndex++; } } @@ -315,44 +318,6 @@ function AssetBrowser::buildPopupMenus(%this) }; } - if( !isObject( EditGameObjectAssetPopup ) ) - { - new PopupMenu( EditGameObjectAssetPopup ) - { - superClass = "MenuBuilder"; - class = "EditorWorldMenu"; - //isPopup = true; - - item[ 0 ] = "Open GameObject Editor" TAB "" TAB "echo(\"Not yet implemented.\");"; - item[ 1 ] = "Edit GameObject Script" TAB "" TAB "AssetBrowser.editGameObjectAssetScript(AssetDatabase.acquireAsset(EditGameObjectAssetPopup.assetId));"; - item[ 2 ] = "-"; - item[ 3 ] = "Apply Instance to GameObject" TAB "" TAB "AssetBrowser.applyInstanceToGameObject(AssetDatabase.acquireAsset(EditGameObjectAssetPopup.assetId));"; - item[ 4 ] = "Reset Instance to GameObject" TAB "" TAB "echo(\"Not yet implemented.\");"; - item[ 5 ] = "-"; - item[ 6 ] = "Create Child GameObject" TAB "" TAB "echo(\"Not yet implemented.\");"; - }; - } - - //Asset Import Resolution menus - if( !isObject( ImportAssetResolutionsPopup ) ) - { - %this.ImportAssetResolutionsPopup = new PopupMenu( ImportAssetResolutionsPopup ) - { - superClass = "MenuBuilder"; - class = "EditorWorldMenu"; - - item[0] = "Use original Asset for duplicates" TAB "" TAB ""; - item[1] = "Override duplicate with new Asset" TAB "" TAB ""; - item[2] = "-"; - item[3] = "Rename Asset" TAB "" TAB ""; - item[4] = "-"; - item[5] = "Find missing file" TAB "" TAB "ImportAssetWindow.findMissingFile(ImportAssetResolutionsPopup.assetItem);"; - item[6] = "-"; - item[7] = "Edit Asset properties" TAB "" TAB ""; - - }; - } - // // Import Asset Actions // diff --git a/Templates/BaseGame/game/tools/gui/fieldTypes/listField.tscript b/Templates/BaseGame/game/tools/gui/fieldTypes/listField.tscript index c26f3638d..eb95ba633 100644 --- a/Templates/BaseGame/game/tools/gui/fieldTypes/listField.tscript +++ b/Templates/BaseGame/game/tools/gui/fieldTypes/listField.tscript @@ -87,11 +87,11 @@ function GuiInspectorVariableGroup::buildListField(%this, %fieldName, %fieldLabe eval(%setCommand); } - %listCount = getTokenCount(%fieldDataVals, ","); + %listCount = getTokenCount(%fieldDataVals, ",;"); for(%i=0; %i < %listCount; %i++) { - %entryText = getToken(%fieldDataVals, ",", %i); + %entryText = getToken(%fieldDataVals, ",;", %i); %editControl.add(%entryText); } diff --git a/Templates/BaseGame/game/tools/navEditor/NavEditorGui.gui b/Templates/BaseGame/game/tools/navEditor/NavEditorGui.gui index 92505f4e7..18646fe1a 100644 --- a/Templates/BaseGame/game/tools/navEditor/NavEditorGui.gui +++ b/Templates/BaseGame/game/tools/navEditor/NavEditorGui.gui @@ -485,7 +485,7 @@ $guiContent = new GuiNavEditorCtrl(NavEditorGui, EditorGuiGroup) { VertSizing = "bottom"; Extent = "90 18"; text = "Stop"; - command = "NavEditorGui.getPlayer().stop();"; + command = "NavEditorGui.stop();"; }; }; }; diff --git a/Templates/BaseGame/game/tools/navEditor/main.tscript b/Templates/BaseGame/game/tools/navEditor/main.tscript index 56739e3a6..3c2ef7aab 100644 --- a/Templates/BaseGame/game/tools/navEditor/main.tscript +++ b/Templates/BaseGame/game/tools/navEditor/main.tscript @@ -87,7 +87,7 @@ function NavEditorPlugin::onWorldEditorStartup(%this) // Add ourselves to the Editor Settings window. exec("./NavEditorSettingsTab.gui"); - //ESettingsWindow.addTabPage(ENavEditorSettingsPage); + ESettingsWindow.addTabPage(ENavEditorSettingsPage); ENavEditorSettingsPage.init(); // Add items to World Editor Creator @@ -104,6 +104,7 @@ function ENavEditorSettingsPage::init(%this) { // Initialises the settings controls in the settings dialog box. %this-->SpawnClassOptions.clear(); + %this-->SpawnClassOptions.add("Player"); %this-->SpawnClassOptions.add("AIPlayer"); %this-->SpawnClassOptions.setFirstSelected(); } diff --git a/Templates/BaseGame/game/tools/navEditor/navEditor.tscript b/Templates/BaseGame/game/tools/navEditor/navEditor.tscript index 8e2234646..7f7b01804 100644 --- a/Templates/BaseGame/game/tools/navEditor/navEditor.tscript +++ b/Templates/BaseGame/game/tools/navEditor/navEditor.tscript @@ -459,6 +459,14 @@ function NavEditorGui::onLinkSelected(%this, %flags) function NavEditorGui::onPlayerSelected(%this, %flags) { + if (!isObject(%this.getPlayer().aiController) && (!(%this.getPlayer().isMemberOfClass("AIPlayer")))) + { + %this.getPlayer().aiController = new AIController(){ ControllerData = %this.getPlayer().getDatablock().aiControllerData; }; + %this.getPlayer().setAIController(%this.getPlayer().aiController); + } + NavMeshIgnore(%this.getPlayer(), true); + %this.getPlayer().setDamageState("Enabled"); + updateLinkData(NavEditorOptionsWindow-->TestProperties, %flags); } @@ -526,7 +534,7 @@ function NavEditorGui::findCover(%this) %text = NavEditorOptionsWindow-->TestProperties->CoverPosition.getText(); if(%text !$= "") %pos = eval("return " @ %text); - %this.getPlayer().findCover(%pos, NavEditorOptionsWindow-->TestProperties->CoverRadius.getText()); + %this.getPlayer().getAIController().findCover(%pos, NavEditorOptionsWindow-->TestProperties->CoverRadius.getText()); } } @@ -547,10 +555,19 @@ function NavEditorGui::followObject(%this) toolsMessageBoxOk("Error", "Cannot find object" SPC %text); } if(isObject(%obj)) - %this.getPlayer().followObject(%obj, NavEditorOptionsWindow-->TestProperties->FollowRadius.getText()); + %this.getPlayer().getAIController().followObject(%obj, NavEditorOptionsWindow-->TestProperties->FollowRadius.getText()); } } +function NavEditorGui::stop(%this) +{ + if (isObject(%this.getPlayer().aiController)) + %this.getPlayer().aiController.stop(); + else + { + NavEditorGui.getPlayer().stop(); + } +} function NavInspector::inspect(%this, %obj) { %name = ""; diff --git a/Templates/BaseGame/game/tools/tools.tscript b/Templates/BaseGame/game/tools/tools.tscript index 47101f55a..04ce56cad 100644 --- a/Templates/BaseGame/game/tools/tools.tscript +++ b/Templates/BaseGame/game/tools/tools.tscript @@ -23,4 +23,13 @@ function ToolsModule::onCreate(%this) function ToolsModule::onDestroy(%this) { +} + +function ToolsModule::disconnect(%this) +{ + if ( isObject( Editor ) && Editor.isEditorEnabled() ) + { + EditorGui.saveAs = false; //whatever edits we were doing are irrelevent now + Editor.close(MainMenuGui); + } } \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/editor.ed.tscript b/Templates/BaseGame/game/tools/worldEditor/scripts/editor.ed.tscript index ff5696dd5..9f0bc5b77 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/editor.ed.tscript +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/editor.ed.tscript @@ -164,40 +164,3 @@ function toggleEditor(%make) //------------------------------------------------------------------------------ // The editor action maps are defined in editor.bind.tscript GlobalActionMap.bind(keyboard, "f11", fastLoadWorldEdit); - - -// The scenario: -// The editor is open and the user closes the level by any way other than -// the file menu ( exit level ), eg. typing disconnect() in the console. -// -// The problem: -// Editor::close() is not called in this scenario which means onEditorDisable -// is not called on objects which hook into it and also gEditingMission will no -// longer be valid. -// -// The solution: -// Override the stock disconnect() function which is in game scripts from here -// in tools so we avoid putting our code in there. -// -// Disclaimer: -// If you think of a better way to do this feel free. The thing which could -// be dangerous about this is that no one will ever realize this code overriding -// a fairly standard and core game script from a somewhat random location. -// If it 'did' have unforscene sideeffects who would ever find it? - -package EditorDisconnectOverride -{ - function disconnect() - { - if ( isObject( Editor ) && Editor.isEditorEnabled() ) - { - EditorGui.saveAs = false; //whatever edits we were doing are irrelevent now - %mainMenuGUI = ProjectSettings.value("UI/mainMenuName"); - if (isObject( %mainMenuGUI )) - Editor.close( %mainMenuGUI ); - } - - Parent::disconnect(); - } -}; -activatePackage( EditorDisconnectOverride ); diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript b/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript index cc7eeaa62..f5cfe67ca 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript @@ -721,32 +721,7 @@ function EditorExplodePrefab() } function makeSelectedAMesh(%assetId) -{ - - /*%dlg = new SaveFileDialog() - { - Filters = "Collada file (*.dae)|*.dae|"; - DefaultPath = $Pref::WorldEditor::LastPath; - DefaultFile = ""; - ChangePath = false; - OverwritePrompt = true; - }; - - %ret = %dlg.Execute(); - if ( %ret ) - { - $Pref::WorldEditor::LastPath = filePath( %dlg.FileName ); - %saveFile = %dlg.FileName; - } - - if( fileExt( %saveFile ) !$= ".dae" ) - %saveFile = %saveFile @ ".dae"; - - %dlg.delete(); - - if ( !%ret ) - return;*/ - +{ %assetDef = AssetDatabase.acquireAsset(%assetId); %assetPath = AssetDatabase.getAssetPath(%assetId); @@ -762,16 +737,12 @@ function makeSelectedAMesh(%assetId) AssetDatabase.refreshAsset(%assetId); if(%success) - { - //ok, cool it worked, so clear out the old - //First, get our center of the currently selected objects - %selectionCenter = EWorldEditor.getSelectionCentroid(); - + { //Next, for safety purposes(and convenience!) we'll make them a prefab aping off the filepath/name provided //TODO: Make this an editor option %prefabPath = %assetPath @ "/" @ %assetDef.AssetName @ ".prefab"; - EWorldEditor.makeSelectionPrefab(%prefabPath, true); - + EWorldEditor.makeSelectionPrefab(%prefabPath, false); + %selectionPos = EWorldEditor.getSelectedObject(0).getPosition(); //Next, nuke 'em EditorMenuEditDelete(); @@ -779,7 +750,7 @@ function makeSelectedAMesh(%assetId) %newStatic = new TSStatic() { shapeAsset = %assetId; - position = %selectionCenter; + position = %selectionPos; }; getRootScene().add(%newStatic);