mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-29 03:26:38 +00:00 
			
		
		
		
	Base GetColliding script functions on collisions detected by the movement solver
This commit is contained in:
		
							parent
							
								
									6b35ee68e1
								
							
						
					
					
						commit
						467220e6d7
					
				
					 7 changed files with 64 additions and 19 deletions
				
			
		|  | @ -61,6 +61,7 @@ | |||
|     Bug #7034: Misc items defined in one content file are not treated as keys if another content file uses them as such | ||||
|     Bug #7042: Weapon follow animations that immediately follow the hit animations cause multiple hits | ||||
|     Bug #7044: Changing a class' services does not affect autocalculated NPCs | ||||
|     Bug #7053: Running into objects doesn't trigger GetCollidingPC | ||||
|     Bug #7054: Quests aren't sorted by name | ||||
|     Bug #7064: NPCs don't report crime if the player is casting offensive spells on them while sneaking | ||||
|     Bug #7077: OpenMW fails to load certain particle effects in .osgt format | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ | |||
| #include "collisiontype.hpp" | ||||
| #include "constants.hpp" | ||||
| #include "contacttestwrapper.h" | ||||
| #include "object.hpp" | ||||
| #include "physicssystem.hpp" | ||||
| #include "projectile.hpp" | ||||
| #include "projectileconvexcallback.hpp" | ||||
|  | @ -243,12 +244,21 @@ namespace MWPhysics | |||
|             float hitHeight = tracer.mHitPoint.z() - tracer.mEndPos.z() + actor.mHalfExtentsZ; | ||||
|             osg::Vec3f oldPosition = newPosition; | ||||
|             bool usedStepLogic = false; | ||||
|             if (hitHeight < Constants::sStepSizeUp && !isActor(tracer.mHitObject)) | ||||
|             if (!isActor(tracer.mHitObject)) | ||||
|             { | ||||
|                 if (hitHeight < Constants::sStepSizeUp) | ||||
|                 { | ||||
|                     // Try to step up onto it.
 | ||||
|                     // NOTE: this modifies newPosition and velocity on its own if successful
 | ||||
|                     usedStepLogic = stepper.step(newPosition, velocity, remainingTime, seenGround, iterations == 0); | ||||
|                 } | ||||
|                 auto* ptrHolder = static_cast<PtrHolder*>(tracer.mHitObject->getUserPointer()); | ||||
|                 if (Object* hitObject = dynamic_cast<Object*>(ptrHolder)) | ||||
|                 { | ||||
|                     hitObject->addCollision( | ||||
|                         actor.mIsPlayer ? ScriptedCollisionType_Player : ScriptedCollisionType_Actor); | ||||
|                 } | ||||
|             } | ||||
|             if (usedStepLogic) | ||||
|             { | ||||
|                 if (actor.mIsAquatic && newPosition.z() + actor.mHalfExtentsZ > actor.mWaterlevel) | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ namespace MWPhysics | |||
|         , mPosition(ptr.getRefData().getPosition().asVec3()) | ||||
|         , mRotation(rotation) | ||||
|         , mTaskScheduler(scheduler) | ||||
|         , mCollidedWith(ScriptedCollisionType_None) | ||||
|     { | ||||
|         mCollisionObject = BulletHelpers::makeCollisionObject(mShapeInstance->mCollisionShape.get(), | ||||
|             Misc::Convert::toBullet(mPosition), Misc::Convert::toBullet(rotation)); | ||||
|  | @ -166,4 +167,20 @@ namespace MWPhysics | |||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     bool Object::collidedWith(ScriptedCollisionType type) const | ||||
|     { | ||||
|         return mCollidedWith & type; | ||||
|     } | ||||
| 
 | ||||
|     void Object::addCollision(ScriptedCollisionType type) | ||||
|     { | ||||
|         std::unique_lock<std::mutex> lock(mPositionMutex); | ||||
|         mCollidedWith |= type; | ||||
|     } | ||||
| 
 | ||||
|     void Object::resetCollisions() | ||||
|     { | ||||
|         mCollidedWith = ScriptedCollisionType_None; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -18,6 +18,14 @@ namespace MWPhysics | |||
| { | ||||
|     class PhysicsTaskScheduler; | ||||
| 
 | ||||
|     enum ScriptedCollisionType : char | ||||
|     { | ||||
|         ScriptedCollisionType_None = 0, | ||||
|         ScriptedCollisionType_Actor = 1, | ||||
|         // Note that this isn't 3, colliding with a player doesn't count as colliding with an actor
 | ||||
|         ScriptedCollisionType_Player = 2 | ||||
|     }; | ||||
| 
 | ||||
|     class Object final : public PtrHolder | ||||
|     { | ||||
|     public: | ||||
|  | @ -38,6 +46,9 @@ namespace MWPhysics | |||
|         /// @brief update object shape
 | ||||
|         /// @return true if shape changed
 | ||||
|         bool animateCollisionShapes(); | ||||
|         bool collidedWith(ScriptedCollisionType type) const; | ||||
|         void addCollision(ScriptedCollisionType type); | ||||
|         void resetCollisions(); | ||||
| 
 | ||||
|     private: | ||||
|         osg::ref_ptr<Resource::BulletShapeInstance> mShapeInstance; | ||||
|  | @ -50,6 +61,7 @@ namespace MWPhysics | |||
|         bool mTransformUpdatePending = false; | ||||
|         mutable std::mutex mPositionMutex; | ||||
|         PhysicsTaskScheduler* mTaskScheduler; | ||||
|         char mCollidedWith; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -673,12 +673,13 @@ namespace MWPhysics | |||
|             // Slow fall reduces fall speed by a factor of (effect magnitude / 200)
 | ||||
|             const float slowFall | ||||
|                 = 1.f - std::clamp(effects.getOrDefault(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f, 0.f, 1.f); | ||||
|             const bool godmode = ptr == world->getPlayerConstPtr() && world->getGodModeState(); | ||||
|             const bool isPlayer = ptr == world->getPlayerConstPtr(); | ||||
|             const bool godmode = isPlayer && world->getGodModeState(); | ||||
|             const bool inert = stats.isDead() | ||||
|                 || (!godmode && stats.getMagicEffects().getOrDefault(ESM::MagicEffect::Paralyze).getModifier() > 0); | ||||
| 
 | ||||
|             simulations.emplace_back(ActorSimulation{ | ||||
|                 physicActor, ActorFrameData{ *physicActor, inert, waterCollision, slowFall, waterlevel } }); | ||||
|                 physicActor, ActorFrameData{ *physicActor, inert, waterCollision, slowFall, waterlevel, isPlayer } }); | ||||
| 
 | ||||
|             // if the simulation will run, a jump request will be fulfilled. Update mechanics accordingly.
 | ||||
|             if (willSimulate) | ||||
|  | @ -708,6 +709,8 @@ namespace MWPhysics | |||
|                 changed = false; | ||||
|             } | ||||
|         } | ||||
|         for (auto& [_, object] : mObjects) | ||||
|             object->resetCollisions(); | ||||
| 
 | ||||
| #ifndef BT_NO_PROFILE | ||||
|         CProfileManager::Reset(); | ||||
|  | @ -782,10 +785,12 @@ namespace MWPhysics | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     bool PhysicsSystem::isActorCollidingWith(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object) const | ||||
|     bool PhysicsSystem::isObjectCollidingWith(const MWWorld::ConstPtr& object, ScriptedCollisionType type) const | ||||
|     { | ||||
|         std::vector<MWWorld::Ptr> collisions = getCollisions(object, CollisionType_World, CollisionType_Actor); | ||||
|         return (std::find(collisions.begin(), collisions.end(), actor) != collisions.end()); | ||||
|         auto found = mObjects.find(object.mRef); | ||||
|         if (found != mObjects.end()) | ||||
|             return found->second->collidedWith(type); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     void PhysicsSystem::getActorsCollidingWith(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const | ||||
|  | @ -890,7 +895,8 @@ namespace MWPhysics | |||
|             mDebugDrawer->addCollision(position, normal); | ||||
|     } | ||||
| 
 | ||||
|     ActorFrameData::ActorFrameData(Actor& actor, bool inert, bool waterCollision, float slowFall, float waterlevel) | ||||
|     ActorFrameData::ActorFrameData( | ||||
|         Actor& actor, bool inert, bool waterCollision, float slowFall, float waterlevel, bool isPlayer) | ||||
|         : mPosition() | ||||
|         , mStandingOn(nullptr) | ||||
|         , mIsOnGround(actor.getOnGround()) | ||||
|  | @ -917,6 +923,7 @@ namespace MWPhysics | |||
|         , mIsAquatic(actor.getPtr().getClass().isPureWaterCreature(actor.getPtr())) | ||||
|         , mWaterCollision(waterCollision) | ||||
|         , mSkipCollisionDetection(!actor.getCollisionMode()) | ||||
|         , mIsPlayer(isPlayer) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -56,6 +56,7 @@ namespace MWPhysics | |||
|     class Actor; | ||||
|     class PhysicsTaskScheduler; | ||||
|     class Projectile; | ||||
|     enum ScriptedCollisionType : char; | ||||
| 
 | ||||
|     using ActorMap = std::unordered_map<const MWWorld::LiveCellRefBase*, std::shared_ptr<Actor>>; | ||||
| 
 | ||||
|  | @ -79,7 +80,7 @@ namespace MWPhysics | |||
| 
 | ||||
|     struct ActorFrameData | ||||
|     { | ||||
|         ActorFrameData(Actor& actor, bool inert, bool waterCollision, float slowFall, float waterlevel); | ||||
|         ActorFrameData(Actor& actor, bool inert, bool waterCollision, float slowFall, float waterlevel, bool isPlayer); | ||||
|         osg::Vec3f mPosition; | ||||
|         osg::Vec3f mInertia; | ||||
|         const btCollisionObject* mStandingOn; | ||||
|  | @ -102,6 +103,7 @@ namespace MWPhysics | |||
|         const bool mIsAquatic; | ||||
|         const bool mWaterCollision; | ||||
|         const bool mSkipCollisionDetection; | ||||
|         const bool mIsPlayer; | ||||
|     }; | ||||
| 
 | ||||
|     struct ProjectileFrameData | ||||
|  | @ -258,9 +260,8 @@ namespace MWPhysics | |||
|         /// Get the handle of all actors standing on \a object in this frame.
 | ||||
|         void getActorsStandingOn(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const; | ||||
| 
 | ||||
|         /// Return true if \a actor has collided with \a object in this frame.
 | ||||
|         /// This will detect running into objects, but will not detect climbing stairs, stepping up a small object, etc.
 | ||||
|         bool isActorCollidingWith(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object) const; | ||||
|         /// Return true if an object of the given type has collided with this object
 | ||||
|         bool isObjectCollidingWith(const MWWorld::ConstPtr& object, ScriptedCollisionType type) const; | ||||
| 
 | ||||
|         /// Get the handle of all actors colliding with \a object in this frame.
 | ||||
|         void getActorsCollidingWith(const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr>& out) const; | ||||
|  |  | |||
|  | @ -2425,15 +2425,12 @@ namespace MWWorld | |||
| 
 | ||||
|     bool World::getPlayerCollidingWith(const MWWorld::ConstPtr& object) | ||||
|     { | ||||
|         MWWorld::Ptr player = getPlayerPtr(); | ||||
|         return mPhysics->isActorCollidingWith(player, object); | ||||
|         return mPhysics->isObjectCollidingWith(object, MWPhysics::ScriptedCollisionType_Player); | ||||
|     } | ||||
| 
 | ||||
|     bool World::getActorCollidingWith(const MWWorld::ConstPtr& object) | ||||
|     { | ||||
|         std::vector<MWWorld::Ptr> actors; | ||||
|         mPhysics->getActorsCollidingWith(object, actors); | ||||
|         return !actors.empty(); | ||||
|         return mPhysics->isObjectCollidingWith(object, MWPhysics::ScriptedCollisionType_Actor); | ||||
|     } | ||||
| 
 | ||||
|     void World::hurtStandingActors(const ConstPtr& object, float healthPerSecond) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue