Merge remote-tracking branch 'upstream/master' into osgshadow-test-vdsm

pull/541/head
AnyOldName3 6 years ago
commit b178e1868a

@ -275,9 +275,6 @@ if (APPLE)
"${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY) "${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY)
endif (APPLE) endif (APPLE)
# Set up DEBUG define
set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1)
if (NOT APPLE) if (NOT APPLE)
set(OPENMW_MYGUI_FILES_ROOT ${OpenMW_BINARY_DIR}) set(OPENMW_MYGUI_FILES_ROOT ${OpenMW_BINARY_DIR})
set(OPENMW_SHADERS_ROOT ${OpenMW_BINARY_DIR}) set(OPENMW_SHADERS_ROOT ${OpenMW_BINARY_DIR})
@ -607,7 +604,7 @@ if (WIN32)
if (USE_DEBUG_CONSOLE AND BUILD_OPENMW) if (USE_DEBUG_CONSOLE AND BUILD_OPENMW)
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE") set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE") set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE") set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_CONSOLE>)
elseif (BUILD_OPENMW) elseif (BUILD_OPENMW)
# Turn off debug console, debug output will be written to visual studio output instead # Turn off debug console, debug output will be written to visual studio output instead
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS") set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS")
@ -617,7 +614,6 @@ if (WIN32)
if (BUILD_OPENMW) if (BUILD_OPENMW)
# Release builds don't use the debug console # Release builds don't use the debug console
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_WINDOWS")
set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS") set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
endif() endif()

@ -7,7 +7,6 @@
#include "engine.hpp" #include "engine.hpp"
#if defined(_WIN32) #if defined(_WIN32)
// For OutputDebugString
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif

@ -29,14 +29,13 @@ namespace MWMechanics
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
if (target == MWWorld::Ptr() || // Stop if the target doesn't exist
!target.getRefData().getCount() || !target.getRefData().isEnabled() // Really we should check whether the target is currently registered // Really we should be checking whether the target is currently registered with the MechanicsManager
// with the MechanicsManager if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
) return true;
return true; //Target doesn't exist
//Set the target destination for the actor //Set the target destination for the actor
const auto dest = target.getRefData().getPosition().asVec3(); const osg::Vec3f dest = target.getRefData().getPosition().asVec3();
if (pathTo(actor, dest, duration, MWBase::Environment::get().getWorld()->getMaxActivationDistance())) //Stop when you get in activation range if (pathTo(actor, dest, duration, MWBase::Environment::get().getWorld()->getMaxActivationDistance())) //Stop when you get in activation range
{ {

@ -26,9 +26,9 @@ bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterContro
{ {
if (actorClass.getNpcStats(actor).getTimeToStartDrowning() < fHoldBreathTime / 2) if (actorClass.getNpcStats(actor).getTimeToStartDrowning() < fHoldBreathTime / 2)
{ {
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; actorClass.getMovementSettings(actor).mPosition[1] = 1;
smoothTurn(actor, -180, 0); smoothTurn(actor, -180, 0);
return false; return false;

@ -83,24 +83,13 @@ namespace MWMechanics
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false); actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false);
const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mTargetActorRefId, false); const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mTargetActorRefId, false);
const float* const leaderPos = actor.getRefData().getPosition().pos; const osg::Vec3f leaderPos = actor.getRefData().getPosition().asVec3();
const float* const followerPos = follower.getRefData().getPosition().pos; const osg::Vec3f followerPos = follower.getRefData().getPosition().asVec3();
double differenceBetween[3];
for (short counter = 0; counter < 3; counter++) if ((leaderPos - followerPos).length2() <= mMaxDist * mMaxDist)
differenceBetween[counter] = (leaderPos[counter] - followerPos[counter]);
double distanceBetweenResult =
(differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] *
differenceBetween[2]);
if (distanceBetweenResult <= mMaxDist * mMaxDist)
{ {
ESM::Pathgrid::Point point(static_cast<int>(mX), static_cast<int>(mY), static_cast<int>(mZ)); const osg::Vec3f dest(mX, mY, mZ);
point.mAutogenerated = 0; if (pathTo(actor, dest, duration)) //Returns true on path complete
point.mConnectionNum = 0;
point.mUnknown = 0;
if (pathTo(actor, osg::Vec3f(mX, mY, mZ), duration)) //Returns true on path complete
{ {
mRemainingDuration = mDuration; mRemainingDuration = mDuration;
return true; return true;

@ -74,12 +74,12 @@ AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow)
bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
{ {
MWWorld::Ptr target = getTarget(); const MWWorld::Ptr target = getTarget();
if (target.isEmpty() || !target.getRefData().getCount() || !target.getRefData().isEnabled() // Really we should be checking whether the target is currently registered // Target is not here right now, wait for it to return
// with the MechanicsManager // Really we should be checking whether the target is currently registered with the MechanicsManager
) if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
return false; // Target is not here right now, wait for it to return return false;
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
@ -94,6 +94,10 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
return false; return false;
} }
const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
const osg::Vec3f targetPos(target.getRefData().getPosition().asVec3());
const osg::Vec3f targetDir = targetPos - actorPos;
// AiFollow requires the target to be in range and within sight for the initial activation // AiFollow requires the target to be in range and within sight for the initial activation
if (!mActive) if (!mActive)
{ {
@ -101,9 +105,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
if (storage.mTimer < 0) if (storage.mTimer < 0)
{ {
if ((actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length2() if (targetDir.length2() < 500*500 && MWBase::Environment::get().getWorld()->getLOS(actor, target))
< 500*500
&& MWBase::Environment::get().getWorld()->getLOS(actor, target))
mActive = true; mActive = true;
storage.mTimer = 0.5f; storage.mTimer = 0.5f;
} }
@ -111,8 +113,6 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
if (!mActive) if (!mActive)
return false; return false;
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
// The distances below are approximations based on observations of the original engine. // The distances below are approximations based on observations of the original engine.
// If only one actor is following the target, it uses 186. // If only one actor is following the target, it uses 186.
// If there are multiple actors following the same target, they form a group with each group member at 313 + (130 * i) distance to the target. // If there are multiple actors following the same target, they form a group with each group member at 313 + (130 * i) distance to the target.
@ -145,9 +145,8 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
} }
} }
if ((pos.pos[0]-mX)*(pos.pos[0]-mX) + osg::Vec3f finalPos(mX, mY, mZ);
(pos.pos[1]-mY)*(pos.pos[1]-mY) + if ((actorPos-finalPos).length2() < followDistance*followDistance) //Close-ish to final position
(pos.pos[2]-mZ)*(pos.pos[2]-mZ) < followDistance*followDistance) //Close-ish to final position
{ {
if (actor.getCell()->isExterior()) //Outside? if (actor.getCell()->isExterior()) //Outside?
{ {
@ -162,8 +161,6 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
} }
} }
//Set the target destination from the actor
const auto dest = target.getRefData().getPosition().asVec3();
short baseFollowDistance = followDistance; short baseFollowDistance = followDistance;
short threshold = 30; // to avoid constant switching between moving/stopping short threshold = 30; // to avoid constant switching between moving/stopping
@ -172,15 +169,9 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
else else
followDistance += threshold; followDistance += threshold;
osg::Vec3f targetPos(target.getRefData().getPosition().asVec3()); if (targetDir.length2() <= followDistance * followDistance)
osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
osg::Vec3f dir = targetPos - actorPos;
float targetDistSqr = dir.length2();
if (targetDistSqr <= followDistance * followDistance)
{ {
float faceAngleRadians = std::atan2(dir.x(), dir.y()); float faceAngleRadians = std::atan2(targetDir.x(), targetDir.y());
if (!zTurn(actor, faceAngleRadians, osg::DegreesToRadians(45.f))) if (!zTurn(actor, faceAngleRadians, osg::DegreesToRadians(45.f)))
{ {
@ -191,16 +182,14 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
return false; return false;
} }
storage.mMoving = !pathTo(actor, dest, duration, baseFollowDistance); // Go to the destination storage.mMoving = !pathTo(actor, targetPos, duration, baseFollowDistance); // Go to the destination
if (storage.mMoving) if (storage.mMoving)
{ {
//Check if you're far away //Check if you're far away
float dist = distance(dest, pos.asVec3()); if (targetDir.length2() > 450 * 450)
if (dist > 450)
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshold else if (targetDir.length2() < 325 * 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshold
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
} }

@ -101,11 +101,11 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
{ {
mTimer += duration; //Update timer mTimer += duration; //Update timer
const auto position = actor.getRefData().getPosition().asVec3(); //position of the actor const osg::Vec3f position = actor.getRefData().getPosition().asVec3(); //position of the actor
const auto world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
{ {
const auto halfExtents = world->getHalfExtents(actor); const osg::Vec3f halfExtents = world->getHalfExtents(actor);
world->updateActorPath(actor, mPathFinder.getPath(), halfExtents, position, dest); world->updateActorPath(actor, mPathFinder.getPath(), halfExtents, position, dest);
} }
@ -139,7 +139,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
{ {
if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path
{ {
const auto playerHalfExtents = world->getHalfExtents(world->getPlayerPtr()); const osg::Vec3f playerHalfExtents = world->getHalfExtents(getPlayer()); // Using player half extents for better performance
mPathFinder.buildPath(actor, position, dest, actor.getCell(), getPathGridGraph(actor.getCell()), mPathFinder.buildPath(actor, position, dest, actor.getCell(), getPathGridGraph(actor.getCell()),
playerHalfExtents, getNavigatorFlags(actor)); playerHalfExtents, getNavigatorFlags(actor));
mRotateOnTheRunChecks = 3; mRotateOnTheRunChecks = 3;
@ -161,7 +161,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
if (!mPathFinder.getPath().empty()) //Path has points in it if (!mPathFinder.getPath().empty()) //Path has points in it
{ {
const auto& lastPos = mPathFinder.getPath().back(); //Get the end of the proposed path const osg::Vec3f& lastPos = mPathFinder.getPath().back(); //Get the end of the proposed path
if(distance(dest, lastPos) > 100) //End of the path is far from the destination if(distance(dest, lastPos) > 100) //End of the path is far from the destination
mPathFinder.addPointToPath(dest); //Adds the final destination to the path, to try to get to where you want to go mPathFinder.addPointToPath(dest); //Adds the final destination to the path, to try to get to where you want to go
@ -171,9 +171,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
mTimer = 0; mTimer = 0;
} }
const auto pointTolerance = std::min(actor.getClass().getSpeed(actor), DEFAULT_TOLERANCE); const float pointTolerance = std::min(actor.getClass().getSpeed(actor), DEFAULT_TOLERANCE);
mPathFinder.update(position, pointTolerance, destTolerance); mPathFinder.update(position, pointTolerance, DEFAULT_TOLERANCE);
if (isDestReached || mPathFinder.checkPathCompleted()) // if path is finished if (isDestReached || mPathFinder.checkPathCompleted()) // if path is finished
{ {
@ -223,7 +223,7 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor)
void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor)
{ {
const auto world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
static float distance = world->getMaxActivationDistance(); static float distance = world->getMaxActivationDistance();
const MWWorld::Ptr door = getNearbyDoor(actor, distance); const MWWorld::Ptr door = getNearbyDoor(actor, distance);
@ -296,11 +296,7 @@ bool MWMechanics::AiPackage::shortcutPath(const osg::Vec3f& startPoint, const os
bool MWMechanics::AiPackage::checkWayIsClearForActor(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::Ptr& actor) bool MWMechanics::AiPackage::checkWayIsClearForActor(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::Ptr& actor)
{ {
const auto world = MWBase::Environment::get().getWorld(); if (canActorMoveByZAxis(actor))
const bool actorCanMoveByZ = (actor.getClass().canSwim(actor) && world->isSwimming(actor))
|| world->isFlying(actor);
if (actorCanMoveByZ)
return true; return true;
const float actorSpeed = actor.getClass().getSpeed(actor); const float actorSpeed = actor.getClass().getSpeed(actor);
@ -309,18 +305,17 @@ bool MWMechanics::AiPackage::checkWayIsClearForActor(const osg::Vec3f& startPoin
const float offsetXY = distToTarget > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2; const float offsetXY = distToTarget > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2;
const bool isClear = checkWayIsClear(startPoint, endPoint, offsetXY);
// update shortcut prohibit state // update shortcut prohibit state
if (isClear) if (checkWayIsClear(startPoint, endPoint, offsetXY))
{ {
if (mShortcutProhibited) if (mShortcutProhibited)
{ {
mShortcutProhibited = false; mShortcutProhibited = false;
mShortcutFailPos = osg::Vec3f(); mShortcutFailPos = osg::Vec3f();
} }
return true;
} }
if (!isClear) else
{ {
if (mShortcutFailPos == osg::Vec3f()) if (mShortcutFailPos == osg::Vec3f())
{ {
@ -329,7 +324,7 @@ bool MWMechanics::AiPackage::checkWayIsClearForActor(const osg::Vec3f& startPoin
} }
} }
return isClear; return false;
} }
bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const MWWorld::CellStore* currentCell) bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const MWWorld::CellStore* currentCell)
@ -399,7 +394,7 @@ bool MWMechanics::AiPackage::isReachableRotatingOnTheRun(const MWWorld::Ptr& act
DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld::Ptr& actor) const DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld::Ptr& actor) const
{ {
const auto& actorClass = actor.getClass(); const MWWorld::Class& actorClass = actor.getClass();
DetourNavigator::Flags result = DetourNavigator::Flag_none; DetourNavigator::Flags result = DetourNavigator::Flag_none;
if (actorClass.isPureWaterCreature(actor) || (getTypeId() != TypeIdWander && actorClass.canSwim(actor))) if (actorClass.isPureWaterCreature(actor) || (getTypeId() != TypeIdWander && actorClass.canSwim(actor)))
@ -416,7 +411,6 @@ DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld::
bool MWMechanics::AiPackage::canActorMoveByZAxis(const MWWorld::Ptr& actor) const bool MWMechanics::AiPackage::canActorMoveByZAxis(const MWWorld::Ptr& actor) const
{ {
const auto world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
const auto& actorClass = actor.getClass(); return (actor.getClass().canSwim(actor) && world->isSwimming(actor)) || world->isFlying(actor);
return (actorClass.canSwim(actor) && world->isSwimming(actor)) || world->isFlying(actor);
} }

@ -35,27 +35,27 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); //The target to follow const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); //The target to follow
if(target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled() // Really we should be checking whether the target is currently registered // Stop if the target doesn't exist
// with the MechanicsManager // Really we should be checking whether the target is currently registered with the MechanicsManager
) if (target == MWWorld::Ptr() || !target.getRefData().getCount() || !target.getRefData().isEnabled())
return true; //Target doesn't exist return true;
if (isTargetMagicallyHidden(target)) if (isTargetMagicallyHidden(target))
return true; return true;
if(target.getClass().getCreatureStats(target).isDead()) if (target.getClass().getCreatureStats(target).isDead())
return true; return true;
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
//Set the target desition from the actor //Set the target destination
const auto dest = target.getRefData().getPosition().asVec3(); const osg::Vec3f dest = target.getRefData().getPosition().asVec3();
ESM::Position aPos = actor.getRefData().getPosition(); const osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3();
float pathTolerance = 100.0; const float pathTolerance = 100.f;
if (pathTo(actor, dest, duration, pathTolerance) && if (pathTo(actor, dest, duration, pathTolerance) &&
std::abs(dest.z() - aPos.pos[2]) < pathTolerance) // check the true distance in case the target is far away in Z-direction std::abs(dest.z() - actorPos.z()) < pathTolerance) // check the true distance in case the target is far away in Z-direction
{ {
target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached
return true; return true;

@ -21,8 +21,8 @@ bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2)
{ {
// Maximum travel distance for vanilla compatibility. // Maximum travel distance for vanilla compatibility.
// Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well. // Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well.
// We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways. // The specific range below is configurable, but its limit is currently 7168 units. Anything greater will break shoddily-written content (*cough* MW *cough*) in bizarre ways.
bool aiDistance = MWBase::Environment::get().getMechanicsManager()->getActorsProcessingRange(); float aiDistance = MWBase::Environment::get().getMechanicsManager()->getActorsProcessingRange();
return (pos1 - pos2).length2() <= aiDistance*aiDistance; return (pos1 - pos2).length2() <= aiDistance*aiDistance;
} }
@ -47,18 +47,19 @@ namespace MWMechanics
bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
{ {
ESM::Position pos = actor.getRefData().getPosition(); const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
const osg::Vec3f targetPos(mX, mY, mZ);
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false); actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false);
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), pos.asVec3())) if (!isWithinMaxRange(targetPos, actorPos))
return false; return false;
// Unfortunately, with vanilla assets destination is sometimes blocked by other actor. // Unfortunately, with vanilla assets destination is sometimes blocked by other actor.
// If we got close to target, check for actors nearby. If they are, finish AI package. // If we got close to target, check for actors nearby. If they are, finish AI package.
int destinationTolerance = 64; int destinationTolerance = 64;
if (distance(pos.asVec3(), osg::Vec3f(mX, mY, mZ)) <= destinationTolerance) if (distance(actorPos, targetPos) <= destinationTolerance)
{ {
std::vector<MWWorld::Ptr> targetActors; std::vector<MWWorld::Ptr> targetActors;
std::pair<MWWorld::Ptr, osg::Vec3f> result = MWBase::Environment::get().getWorld()->getHitContact(actor, destinationTolerance, targetActors); std::pair<MWWorld::Ptr, osg::Vec3f> result = MWBase::Environment::get().getWorld()->getHitContact(actor, destinationTolerance, targetActors);
@ -70,7 +71,7 @@ namespace MWMechanics
} }
} }
if (pathTo(actor, osg::Vec3f(mX, mY, mZ), duration)) if (pathTo(actor, targetPos, duration))
{ {
actor.getClass().getMovementSettings(actor).mPosition[1] = 0; actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
return true; return true;

@ -124,14 +124,13 @@ namespace MWMechanics
*/ */
bool AiWander::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) bool AiWander::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
{ {
// get or create temporary storage
AiWanderStorage& storage = state.get<AiWanderStorage>();
const MWWorld::CellStore*& currentCell = storage.mCell;
MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor); MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor);
if(cStats.isDead() || cStats.getHealth().getCurrent() <= 0) if (cStats.isDead() || cStats.getHealth().getCurrent() <= 0)
return true; // Don't bother with dead actors return true; // Don't bother with dead actors
// get or create temporary storage
AiWanderStorage& storage = state.get<AiWanderStorage>();
const MWWorld::CellStore*& currentCell = storage.mCell;
bool cellChange = currentCell && (actor.getCell() != currentCell); bool cellChange = currentCell && (actor.getCell() != currentCell);
if(!currentCell || cellChange) if(!currentCell || cellChange)
{ {
@ -159,8 +158,7 @@ namespace MWMechanics
} }
else else
{ {
const auto world = MWBase::Environment::get().getWorld(); const osg::Vec3f playerHalfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(getPlayer()); // Using player half extents for better performance
const auto playerHalfExtents = world->getHalfExtents(world->getPlayerPtr());
mPathFinder.buildPath(actor, pos.asVec3(), mDestination, actor.getCell(), mPathFinder.buildPath(actor, pos.asVec3(), mDestination, actor.getCell(),
getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor)); getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor));
} }
@ -279,9 +277,7 @@ namespace MWMechanics
if (mHasDestination) if (mHasDestination)
return mDestination; return mDestination;
const ESM::Pathgrid::Point currentPosition = actor.getRefData().getPosition().pos; return actor.getRefData().getPosition().asVec3();
const osg::Vec3f currentPositionVec3f = osg::Vec3f(currentPosition.mX, currentPosition.mY, currentPosition.mZ);
return currentPositionVec3f;
} }
bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage) bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage)
@ -314,18 +310,17 @@ namespace MWMechanics
const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection); const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection);
const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection); const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection);
const float destinationZ = mInitialActorPosition.z(); const float destinationZ = mInitialActorPosition.z();
const osg::Vec3f destinationPosition(destinationX, destinationY, destinationZ);
mDestination = osg::Vec3f(destinationX, destinationY, destinationZ); mDestination = osg::Vec3f(destinationX, destinationY, destinationZ);
// Check if land creature will walk onto water or if water creature will swim onto land // Check if land creature will walk onto water or if water creature will swim onto land
if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) || if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) ||
(isWaterCreature && !destinationThroughGround(currentPosition, mDestination))) (isWaterCreature && !destinationThroughGround(currentPosition, mDestination)))
{ {
const auto world = MWBase::Environment::get().getWorld();; // Using player half extents for better performance
const auto playerHalfExtents = world->getHalfExtents(world->getPlayerPtr()); const osg::Vec3f playerHalfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(getPlayer());
mPathFinder.buildPath(actor, currentPosition, destinationPosition, actor.getCell(), mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(),
getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor)); getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor));
mPathFinder.addPointToPath(destinationPosition); mPathFinder.addPointToPath(mDestination);
if (mPathFinder.isPathConstructed()) if (mPathFinder.isPathConstructed())
{ {
@ -520,9 +515,9 @@ namespace MWMechanics
// Only say Idle voices when player is in LOS // Only say Idle voices when player is in LOS
// A bit counterintuitive, likely vanilla did this to reduce the appearance of // A bit counterintuitive, likely vanilla did this to reduce the appearance of
// voices going through walls? // voices going through walls?
const ESM::Position& pos = actor.getRefData().getPosition(); const osg::Vec3f playerPos(player.getRefData().getPosition().asVec3());
if (roll < x && (player.getRefData().getPosition().asVec3() - pos.asVec3()).length2() const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
< 3000 * 3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead if (roll < x && (playerPos - actorPos).length2() < 3000 * 3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead
&& MWBase::Environment::get().getWorld()->getLOS(player, actor)) && MWBase::Environment::get().getWorld()->getLOS(player, actor))
MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
} }
@ -541,13 +536,12 @@ namespace MWMechanics
MWWorld::Ptr player = getPlayer(); MWWorld::Ptr player = getPlayer();
osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); osg::Vec3f playerPos(player.getRefData().getPosition().asVec3());
osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
float playerDistSqr = (playerPos - actorPos).length2();
int& greetingTimer = storage.mGreetingTimer; int& greetingTimer = storage.mGreetingTimer;
AiWanderStorage::GreetingState& greetingState = storage.mSaidGreeting; AiWanderStorage::GreetingState& greetingState = storage.mSaidGreeting;
if (greetingState == AiWanderStorage::Greet_None) if (greetingState == AiWanderStorage::Greet_None)
{ {
if ((playerDistSqr <= helloDistance*helloDistance) && if ((playerPos - actorPos).length2() <= helloDistance*helloDistance &&
!player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor) !player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor)
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor)) && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor))
greetingTimer++; greetingTimer++;
@ -583,7 +577,7 @@ namespace MWMechanics
if (greetingState == AiWanderStorage::Greet_Done) if (greetingState == AiWanderStorage::Greet_Done)
{ {
float resetDist = 2 * helloDistance; float resetDist = 2 * helloDistance;
if (playerDistSqr >= resetDist*resetDist) if ((playerPos - actorPos).length2() >= resetDist*resetDist)
greetingState = AiWanderStorage::Greet_None; greetingState = AiWanderStorage::Greet_None;
} }
} }
@ -605,10 +599,10 @@ namespace MWMechanics
ToWorldCoordinates(dest, storage.mCell->getCell()); ToWorldCoordinates(dest, storage.mCell->getCell());
// actor position is already in world coordinates // actor position is already in world coordinates
const auto start = actorPos.asVec3(); const osg::Vec3f start = actorPos.asVec3();
// don't take shortcuts for wandering // don't take shortcuts for wandering
const auto destVec3f = PathFinder::makeOsgVec3(dest); const osg::Vec3f destVec3f = PathFinder::makeOsgVec3(dest);
mPathFinder.buildPathByPathgrid(start, destVec3f, actor.getCell(), getPathGridGraph(actor.getCell())); mPathFinder.buildPathByPathgrid(start, destVec3f, actor.getCell(), getPathGridGraph(actor.getCell()));
if (mPathFinder.isPathConstructed()) if (mPathFinder.isPathConstructed())

@ -1,40 +0,0 @@
find_path(RecastNavigation_INCLUDE_DIR
NAMES Recast.h
HINTS $ENV{RecastNavigation_ROOT}
${RecastNavigation_ROOT}
PATH_SUFFIXES include
)
mark_as_advanced(RecastNavigation_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
set(RecastNavigation_LIBRARIES "")
foreach(COMPONENT ${RecastNavigation_FIND_COMPONENTS})
if(NOT RecastNavigation_${COMPONENT}_FOUND)
find_library(RecastNavigation_${COMPONENT}_LIBRARY
HINTS $ENV{RecastNavigation_ROOT}
${RecastNavigation_ROOT}
NAMES ${COMPONENT}
PATH_SUFFIXES lib
)
find_package_handle_standard_args(RecastNavigation_${COMPONENT} DEFAULT_MSG
RecastNavigation_${COMPONENT}_LIBRARY
RecastNavigation_INCLUDE_DIR
)
mark_as_advanced(RecastNavigation_${COMPONENT}_LIBRARY)
if(RecastNavigation_${COMPONENT}_FOUND)
list(APPEND RecastNavigation_LIBRARIES ${RecastNavigation_${COMPONENT}_LIBRARY})
endif()
endif()
endforeach()
mark_as_advanced(RecastNavigation_LIBRARIES)
find_package_handle_standard_args(RecastNavigation DEFAULT_MSG
RecastNavigation_LIBRARIES
RecastNavigation_INCLUDE_DIR
)
if(RecastNavigation_FOUND)
set(RecastNavigation_INCLUDE_DIRS ${RecastNavigation_INCLUDE_DIR})
endif()

@ -44,6 +44,10 @@ namespace Debug
}; };
#if defined(_WIN32) && defined(_DEBUG) #if defined(_WIN32) && defined(_DEBUG)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif // !WIN32_LEAN_AND_MEAN
#include <Windows.h>
class DebugOutput : public DebugOutputBase class DebugOutput : public DebugOutputBase
{ {
public: public:

@ -38,19 +38,25 @@ namespace Misc
class ScopeGuarded class ScopeGuarded
{ {
public: public:
ScopeGuarded() = default; ScopeGuarded()
: mMutex()
, mValue()
{}
ScopeGuarded(const T& value) ScopeGuarded(const T& value)
: mValue(value) : mMutex()
, mValue(value)
{} {}
ScopeGuarded(T&& value) ScopeGuarded(T&& value)
: mValue(std::move(value)) : mMutex()
, mValue(std::move(value))
{} {}
template <class ... Args> template <class ... Args>
ScopeGuarded(Args&& ... args) ScopeGuarded(Args&& ... args)
: mValue(std::forward<Args>(args) ...) : mMutex()
, mValue(std::forward<Args>(args) ...)
{} {}
ScopeGuarded(const ScopeGuarded& other) ScopeGuarded(const ScopeGuarded& other)
@ -83,7 +89,7 @@ namespace Misc
{ {
public: public:
SharedGuarded() SharedGuarded()
: mMutex(std::make_shared<std::mutex>()) : mMutex(std::make_shared<std::mutex>()), mValue()
{} {}
SharedGuarded(std::shared_ptr<T> value) SharedGuarded(std::shared_ptr<T> value)

Loading…
Cancel
Save