From e047679595644c3ed61b9fd0936e79f141cb52c2 Mon Sep 17 00:00:00 2001 From: Allofich Date: Sat, 11 Feb 2017 19:59:42 +0900 Subject: [PATCH 1/4] Fix trying to access stats on non-actors --- apps/openmw/mwclass/creature.cpp | 4 ++-- apps/openmw/mwclass/npc.cpp | 4 ++-- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 7 +++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index dea078701..f5b62ca4a 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -328,7 +328,7 @@ namespace MWClass MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); // NOTE: 'object' and/or 'attacker' may be empty. - if (!attacker.isEmpty() && !stats.getAiSequence().isInCombat(attacker)) + if (!attacker.isEmpty() && attacker.getClass().isActor() && !stats.getAiSequence().isInCombat(attacker)) stats.setAttacked(true); // Self defense @@ -339,7 +339,7 @@ namespace MWClass setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); // Attacker and target store each other as hitattemptactor if they have no one stored yet - if (!attacker.isEmpty() && !ptr.isEmpty()) + if (!attacker.isEmpty() && attacker.getClass().isActor() && !ptr.isEmpty() && ptr.getClass().isActor()) { MWMechanics::CreatureStats& statsAttacker = attacker.getClass().getCreatureStats(attacker); // First handle the attacked actor diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 645cd799c..27d4643fa 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -661,14 +661,14 @@ namespace MWClass bool setOnPcHitMe = true; // NOTE: 'object' and/or 'attacker' may be empty. - if (!attacker.isEmpty() && !stats.getAiSequence().isInCombat(attacker)) + if (!attacker.isEmpty() && attacker.getClass().isActor() && !stats.getAiSequence().isInCombat(attacker)) { stats.setAttacked(true); setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); } // Attacker and target store each other as hitattemptactor if they have no one stored yet - if (!attacker.isEmpty() && !ptr.isEmpty()) + if (!attacker.isEmpty() && attacker.getClass().isActor() && !ptr.isEmpty() && ptr.getClass().isActor()) { MWMechanics::CreatureStats& statsAttacker = attacker.getClass().getCreatureStats(attacker); // First handle the attacked actor diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 735e7d267..ab75ef128 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1216,14 +1216,13 @@ namespace MWMechanics bool MechanicsManager::actorAttacked(const MWWorld::Ptr &target, const MWWorld::Ptr &attacker) { + if (target == getPlayer() || !attacker.getClass().isActor()) + return false; + std::list followersAttacker = getActorsSidingWith(attacker); - std::list followersTarget = getActorsSidingWith(target); MWMechanics::CreatureStats& statsTarget = target.getClass().getCreatureStats(target); - if (target == getPlayer()) - return false; - if (std::find(followersAttacker.begin(), followersAttacker.end(), target) != followersAttacker.end()) { statsTarget.friendlyHit(); From f2d4f290ccc9ed78eebc10b33d090b4a89a50fa4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Feb 2017 23:02:41 +0100 Subject: [PATCH 2/4] traceDown fix --- apps/openmw/mwphysics/physicssystem.cpp | 16 ++++++++-------- apps/openmw/mwphysics/trace.cpp | 5 ++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 7c8342707..c043c861e 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -56,6 +56,7 @@ namespace MWPhysics static const float sStepSizeUp = 34.0f; static const float sStepSizeDown = 62.0f; static const float sMinStep = 10.f; + static const float sGroundOffset = 1.0f; // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. static const int sMaxIterations = 8; @@ -237,13 +238,12 @@ namespace MWPhysics public: - static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, osg::Vec3f position, Actor* actor, btCollisionWorld* collisionWorld, float maxHeight) + static osg::Vec3f traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, Actor* actor, btCollisionWorld* collisionWorld, float maxHeight) { osg::Vec3f offset = actor->getCollisionObjectPosition() - ptr.getRefData().getPosition().asVec3(); - position += offset; ActorTracer tracer; - tracer.findGround(actor, position, position-osg::Vec3f(0,0,maxHeight), collisionWorld); + tracer.findGround(actor, position + offset, position + offset - osg::Vec3f(0,0,maxHeight), collisionWorld); if(tracer.mFraction >= 1.0f) { actor->setOnGround(false); @@ -266,18 +266,18 @@ namespace MWPhysics collisionWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit() && - ( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length2() > 35*35 + ( (toOsg(resultCallback1.m_hitPointWorld) - (tracer.mEndPos-offset)).length2() > 35*35 || !isWalkableSlope(tracer.mPlaneNormal))) { actor->setOnSlope(!isWalkableSlope(resultCallback1.m_hitNormalWorld)); - return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, 1.f); + return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, sGroundOffset); } else { actor->setOnSlope(!isWalkableSlope(tracer.mPlaneNormal)); } - return tracer.mEndPos; + return tracer.mEndPos-offset + osg::Vec3f(0.f, 0.f, sGroundOffset); } } @@ -448,7 +448,7 @@ namespace MWPhysics { osg::Vec3f from = newPosition; osg::Vec3f to = newPosition - (physicActor->getOnGround() ? - osg::Vec3f(0,0,sStepSizeDown+2.f) : osg::Vec3f(0,0,2.f)); + osg::Vec3f(0,0,sStepSizeDown + 2*sGroundOffset) : osg::Vec3f(0,0,2*sGroundOffset)); tracer.doTrace(colobj, from, to, collisionWorld); if(tracer.mFraction < 1.0f && tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor) @@ -461,7 +461,7 @@ namespace MWPhysics if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water) physicActor->setWalkingOnWater(true); if (!isFlying) - newPosition.z() = tracer.mEndPos.z() + 1.0f; + newPosition.z() = tracer.mEndPos.z() + sGroundOffset; isOnGround = true; diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp index 10d22ec7f..14a5dac48 100644 --- a/apps/openmw/mwphysics/trace.cpp +++ b/apps/openmw/mwphysics/trace.cpp @@ -92,8 +92,8 @@ void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& star void ActorTracer::findGround(const Actor* actor, const osg::Vec3f& start, const osg::Vec3f& end, const btCollisionWorld* world) { - const btVector3 btstart(start.x(), start.y(), start.z()+1.0f); - const btVector3 btend(end.x(), end.y(), end.z()+1.0f); + const btVector3 btstart(start.x(), start.y(), start.z()); + const btVector3 btend(end.x(), end.y(), end.z()); const btTransform &trans = actor->getCollisionObject()->getWorldTransform(); btTransform from(trans.getBasis(), btstart); @@ -112,7 +112,6 @@ void ActorTracer::findGround(const Actor* actor, const osg::Vec3f& start, const mFraction = newTraceCallback.m_closestHitFraction; mPlaneNormal = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); mEndPos = (end-start)*mFraction + start; - mEndPos[2] += 1.0f; } else { From 5a1240743640fab4a8ea5946ea029aa5782ce84b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 10 Feb 2017 23:03:14 +0100 Subject: [PATCH 3/4] Revert "Rearranged check for better performance" This reverts commit 332ceb51a25c40caba4444174216794652094be8. --- apps/openmw/mwmechanics/actors.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9376beb2d..418f53422 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -300,10 +300,6 @@ namespace MWMechanics if (!actor1.getClass().isMobile(actor1)) return; - // Stop here if target is unreachable - if (!MWMechanics::canFight(actor1, actor2)) - return; - // If this is set to true, actor1 will start combat with actor2 if the awareness check at the end of the method returns true bool aggressive = false; @@ -379,6 +375,10 @@ namespace MWMechanics } } + // Stop here if target is unreachable + if (!MWMechanics::canFight(actor1, actor2)) + return; + // Do aggression check if actor2 is the player or a player follower or escorter if (!aggressive) { From 03a10f217aa69a63936f388f228f26a0dfddba60 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 11 Feb 2017 13:39:26 +0100 Subject: [PATCH 4/4] Catch exceptions in AiSequence::execute --- apps/openmw/mwmechanics/aisequence.cpp | 38 ++++++++++++++++---------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 1bd2f98b3..520bacf5a 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -1,6 +1,7 @@ #include "aisequence.hpp" #include +#include #include @@ -229,26 +230,33 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac } } - if (package->execute (actor,characterController,state,duration)) + try { - // Put repeating noncombat AI packages on the end of the stack so they can be used again - if (isActualAiPackage(packageTypeId) && (mRepeat || package->getRepeat())) + if (package->execute (actor,characterController,state,duration)) { - package->reset(); - mPackages.push_back(package->clone()); + // Put repeating noncombat AI packages on the end of the stack so they can be used again + if (isActualAiPackage(packageTypeId) && (mRepeat || package->getRepeat())) + { + package->reset(); + mPackages.push_back(package->clone()); + } + // To account for the rare case where AiPackage::execute() queued another AI package + // (e.g. AiPursue executing a dialogue script that uses startCombat) + std::list::iterator toRemove = + std::find(mPackages.begin(), mPackages.end(), package); + mPackages.erase(toRemove); + delete package; + if (isActualAiPackage(packageTypeId)) + mDone = true; + } + else + { + mDone = false; } - // To account for the rare case where AiPackage::execute() queued another AI package - // (e.g. AiPursue executing a dialogue script that uses startCombat) - std::list::iterator toRemove = - std::find(mPackages.begin(), mPackages.end(), package); - mPackages.erase(toRemove); - delete package; - if (isActualAiPackage(packageTypeId)) - mDone = true; } - else + catch (std::exception& e) { - mDone = false; + std::cerr << "Error during AiSequence::execute: " << e.what() << std::endl; } } }