From 5075cc0d6b7b491af88f49de73fcd7b8dde5fdf2 Mon Sep 17 00:00:00 2001 From: marcushutchings <40723596+marcushutchings@users.noreply.github.com> Date: Mon, 1 Aug 2022 17:24:06 +0100 Subject: [PATCH] Bar105 collision avoidance mt (#327) * mt collision avoidance * fixed race condition on the temp number. * mt collision avoidence * fixed race condition on the temp number. * removed unneeded code. * tempNums are now saved. --- rts/Sim/Misc/GlobalSynced.cpp | 4 ++ rts/Sim/Misc/GlobalSynced.h | 4 ++ rts/Sim/Misc/QuadField.cpp | 59 ++++++++++++++++++++++------ rts/Sim/Misc/QuadField.h | 12 ++++-- rts/Sim/MoveTypes/GroundMoveType.cpp | 31 ++++++++++++++- rts/Sim/MoveTypes/GroundMoveType.h | 2 + rts/Sim/MoveTypes/MoveType.h | 2 + rts/Sim/Objects/WorldObject.cpp | 4 +- rts/Sim/Objects/WorldObject.h | 4 ++ rts/Sim/Units/UnitHandler.cpp | 7 ++++ 10 files changed, 108 insertions(+), 21 deletions(-) diff --git a/rts/Sim/Misc/GlobalSynced.cpp b/rts/Sim/Misc/GlobalSynced.cpp index 1470bd5801..7512cf37ad 100644 --- a/rts/Sim/Misc/GlobalSynced.cpp +++ b/rts/Sim/Misc/GlobalSynced.cpp @@ -2,6 +2,7 @@ #include "GlobalSynced.h" +#include #include #include @@ -34,6 +35,7 @@ CR_BIND(CGlobalSynced, ) CR_REG_METADATA(CGlobalSynced, ( CR_MEMBER(frameNum), CR_MEMBER(tempNum), + CR_MEMBER(mtTempNum), CR_MEMBER(godMode), CR_MEMBER(speedFactor), @@ -58,6 +60,8 @@ void CGlobalSynced::ResetState() { tempNum = 1; godMode = 0; + std::fill(std::begin(mtTempNum), std::end(mtTempNum), 1); + #ifdef SYNCCHECK // reset checksum CSyncChecker::NewFrame(); diff --git a/rts/Sim/Misc/GlobalSynced.h b/rts/Sim/Misc/GlobalSynced.h index 520bf78fef..4c4867e644 100644 --- a/rts/Sim/Misc/GlobalSynced.h +++ b/rts/Sim/Misc/GlobalSynced.h @@ -5,6 +5,7 @@ #include "System/creg/creg_cond.h" #include "System/GlobalRNG.h" +#include "System/Threading/ThreadPool.h" class CGameSetup; @@ -38,6 +39,8 @@ class CGlobalSynced int GetLuaSimFrame() { return (frameNum * (frameNum > 0)); } int GetTempNum() { return tempNum++; } + int GetMtTempNum() { return mtTempNum[ThreadPool::GetThreadNum()]++; } + // remains true until first SimFrame call bool PreSimFrame() const { return (frameNum == -1); } @@ -49,6 +52,7 @@ class CGlobalSynced * (increase after each use) */ int tempNum = 1; + std::array mtTempNum = {}; public: /** diff --git a/rts/Sim/Misc/QuadField.cpp b/rts/Sim/Misc/QuadField.cpp index 04655eaf17..92d4bedeb0 100644 --- a/rts/Sim/Misc/QuadField.cpp +++ b/rts/Sim/Misc/QuadField.cpp @@ -9,6 +9,7 @@ #include "Sim/Misc/GlobalConstants.h" #include "Sim/Misc/TeamHandler.h" #include "System/ContainerUtil.h" +#include "System/Threading/ThreadPool.h" #ifndef UNIT_TEST #include "Sim/Features/Feature.h" @@ -121,8 +122,20 @@ void CQuadField::Init(int2 mapDims, int quadSize) invQuadSize = {1.0f / quadSizeX, 1.0f / quadSizeZ}; baseQuads.resize(numQuadsX * numQuadsZ); - tempQuads.ReserveAll(numQuadsX * numQuadsZ); - tempQuads.ReleaseAll(); + + int threadCount = ThreadPool::GetNumThreads(); + tempQuads.reserve(threadCount); + tempSolids.reserve(threadCount); + + for (auto i = 0; i < threadCount; ++i) { + auto newQueryVectorCache = tempQuads.emplace_back(); + + newQueryVectorCache.ReserveAll(numQuadsX * numQuadsZ); + newQueryVectorCache.ReleaseAll(); + + tempSolids.emplace_back(); + } + #ifndef UNIT_TEST for (Quad& quad: baseQuads) { @@ -142,8 +155,26 @@ void CQuadField::Kill() tempUnits.ReleaseAll(); tempFeatures.ReleaseAll(); tempProjectiles.ReleaseAll(); - tempSolids.ReleaseAll(); - tempQuads.ReleaseAll(); + + for (auto cache : tempSolids) { + cache.ReleaseAll(); + } + tempSolids.clear(); + + for (auto cache : tempQuads) { + cache.ReleaseAll(); + } + tempQuads.clear(); +} + +void CQuadField::ReleaseVector(std::vector* v) +{ + tempSolids[ThreadPool::GetThreadNum()].ReleaseVector(v); +} + +void CQuadField::ReleaseVector(std::vector* v) +{ + tempQuads[ThreadPool::GetThreadNum()].ReleaseVector(v); } @@ -167,7 +198,7 @@ void CQuadField::GetQuads(QuadFieldQuery& qfq, float3 pos, float radius) { pos.AssertNaNs(); pos.ClampInBounds(); - qfq.quads = tempQuads.ReserveVector(); + qfq.quads = tempQuads[ThreadPool::GetThreadNum()].ReserveVector(); const int2 min = WorldPosToQuadField(pos - radius); const int2 max = WorldPosToQuadField(pos + radius); @@ -197,7 +228,7 @@ void CQuadField::GetQuadsRectangle(QuadFieldQuery& qfq, const float3& mins, cons { mins.AssertNaNs(); maxs.AssertNaNs(); - qfq.quads = tempQuads.ReserveVector(); + qfq.quads = tempQuads[ThreadPool::GetThreadNum()].ReserveVector(); const int2 min = WorldPosToQuadField(mins); const int2 max = WorldPosToQuadField(maxs); @@ -224,7 +255,7 @@ void CQuadField::GetQuadsOnRay(QuadFieldQuery& qfq, const float3& start, const f dir.AssertNaNs(); start.AssertNaNs(); - auto& queryQuads = *(qfq.quads = tempQuads.ReserveVector()); + auto& queryQuads = *(qfq.quads = tempQuads[ThreadPool::GetThreadNum()].ReserveVector()); const float3 to = start + (dir * length); @@ -729,15 +760,17 @@ void CQuadField::GetSolidsExact( ) { QuadFieldQuery qfQuery; GetQuads(qfQuery, pos, radius); - const int tempNum = gs->GetTempNum(); - qfq.solids = tempSolids.ReserveVector(); + const int tempNum = gs->GetMtTempNum(); + auto curThread = ThreadPool::GetThreadNum(); + qfq.solids = tempSolids[curThread].ReserveVector(); + for (const int qi: *qfQuery.quads) { for (CUnit* u: baseQuads[qi].units) { - if (u->tempNum == tempNum) + if (u->mtTempNum[curThread] == tempNum) continue; - u->tempNum = tempNum; + u->mtTempNum[curThread] = tempNum; if (!u->HasPhysicalStateBit(physicalStateBits)) continue; @@ -750,10 +783,10 @@ void CQuadField::GetSolidsExact( } for (CFeature* f: baseQuads[qi].features) { - if (f->tempNum == tempNum) + if (f->mtTempNum[curThread] == tempNum) continue; - f->tempNum = tempNum; + f->mtTempNum[curThread] = tempNum; if (!f->HasPhysicalStateBit(physicalStateBits)) continue; diff --git a/rts/Sim/Misc/QuadField.h b/rts/Sim/Misc/QuadField.h index c7de6bbaba..9d7516ac47 100644 --- a/rts/Sim/Misc/QuadField.h +++ b/rts/Sim/Misc/QuadField.h @@ -170,8 +170,12 @@ class CQuadField : spring::noncopyable void ReleaseVector(std::vector* v ) { tempUnits.ReleaseVector(v); } void ReleaseVector(std::vector* v ) { tempFeatures.ReleaseVector(v); } void ReleaseVector(std::vector* v ) { tempProjectiles.ReleaseVector(v); } - void ReleaseVector(std::vector* v) { tempSolids.ReleaseVector(v); } - void ReleaseVector(std::vector* v ) { tempQuads.ReleaseVector(v); } + + // Ensure release in same thread as original quad field query generated. + void ReleaseVector(std::vector* v); //{ tempSolids.ReleaseVector(v); } + + // Ensure release in same thread as original quad field query generated. + void ReleaseVector(std::vector* v );// { tempQuads.ReleaseVector(v); } struct Quad { public: @@ -242,8 +246,8 @@ class CQuadField : spring::noncopyable QueryVectorCache tempUnits; QueryVectorCache tempFeatures; QueryVectorCache tempProjectiles; - QueryVectorCache tempSolids; - QueryVectorCache tempQuads; + std::vector< QueryVectorCache > tempSolids; + std::vector< QueryVectorCache > tempQuads; float2 invQuadSize; diff --git a/rts/Sim/MoveTypes/GroundMoveType.cpp b/rts/Sim/MoveTypes/GroundMoveType.cpp index 887cc7fb2c..3865f4d15b 100644 --- a/rts/Sim/MoveTypes/GroundMoveType.cpp +++ b/rts/Sim/MoveTypes/GroundMoveType.cpp @@ -696,6 +696,30 @@ void CGroundMoveType::StopMoving(bool callScript, bool hardStop, bool cancelRaw) progressState = Done; } +void CGroundMoveType::UpdateObstacleAvoidance() { + if (owner->GetTransporter() != nullptr) + return; + + if (owner->IsSkidding()) + return; + + if (owner->IsFalling()) + return; + + if (owner->IsStunned() || owner->beingBuilt) + return; + + if (owner->UnderFirstPersonControl()) + return; + + if (WantToStop()) + return; + + const float3& ffd = flatFrontDir; + auto wantReverse = WantReverse(waypointDir, ffd); + const float3 rawWantedDir = waypointDir * Sign(int(!wantReverse)); + const float3& modWantedDir = GetObstacleAvoidanceDir(mix(ffd, rawWantedDir, !atGoal)); +} bool CGroundMoveType::FollowPath() { @@ -847,10 +871,13 @@ bool CGroundMoveType::FollowPath() wantReverse = WantReverse(waypointDir, ffd); // apply obstacle avoidance (steering), prevent unit from chasing its own tail if already at goal - const float3 rawWantedDir = waypointDir * Sign(int(!wantReverse)); - const float3& modWantedDir = GetObstacleAvoidanceDir(mix(ffd, rawWantedDir, !atGoal)); + // const float3 rawWantedDir = waypointDir * Sign(int(!wantReverse)); + // const float3& modWantedDir = GetObstacleAvoidanceDir(mix(ffd, rawWantedDir, !atGoal)); + // const float3& modWantedDir = GetObstacleAvoidanceDir(mix(ffd, rawWantedDir, (!atGoal) && (wpProjDists.x > wpProjDists.y || wpProjDists.z < 0.995f))); + const float3& modWantedDir = lastAvoidanceDir; + ChangeHeading(GetHeadingFromVector(modWantedDir.x, modWantedDir.z)); ChangeSpeed(maxWantedSpeed, wantReverse); diff --git a/rts/Sim/MoveTypes/GroundMoveType.h b/rts/Sim/MoveTypes/GroundMoveType.h index 762cf5b4c6..8caeff0c69 100644 --- a/rts/Sim/MoveTypes/GroundMoveType.h +++ b/rts/Sim/MoveTypes/GroundMoveType.h @@ -32,6 +32,8 @@ class CGroundMoveType : public AMoveType bool Update() override; void SlowUpdate() override; + void UpdateObstacleAvoidance() override; + void StartMovingRaw(const float3 moveGoalPos, float moveGoalRadius) override; void StartMoving(float3 pos, float moveGoalRadius) override; void StartMoving(float3 pos, float moveGoalRadius, float speed) override { StartMoving(pos, moveGoalRadius); } diff --git a/rts/Sim/MoveTypes/MoveType.h b/rts/Sim/MoveTypes/MoveType.h index b4500179da..e992c91719 100644 --- a/rts/Sim/MoveTypes/MoveType.h +++ b/rts/Sim/MoveTypes/MoveType.h @@ -64,6 +64,8 @@ class AMoveType : public CObject virtual void SlowUpdate() {}; void UpdateCollisionMap(); + virtual void UpdateObstacleAvoidance() {}; + virtual bool IsSkidding() const { return false; } virtual bool IsFlying() const { return false; } virtual bool IsReversing() const { return false; } diff --git a/rts/Sim/Objects/WorldObject.cpp b/rts/Sim/Objects/WorldObject.cpp index 306ac0dedf..7a095d9978 100644 --- a/rts/Sim/Objects/WorldObject.cpp +++ b/rts/Sim/Objects/WorldObject.cpp @@ -2,12 +2,13 @@ #include "WorldObject.h" #include "Rendering/Models/3DModel.h" +#include "System/Threading/ThreadPool.h" CR_BIND_DERIVED(CWorldObject, CObject, ) CR_REG_METADATA(CWorldObject, ( CR_MEMBER(id), CR_MEMBER(tempNum), - + CR_MEMBER(mtTempNum), CR_MEMBER(radius), CR_MEMBER(height), CR_MEMBER(sqRadius), @@ -32,4 +33,3 @@ void CWorldObject::SetRadiusAndHeight(const S3DModel* mdl) // we always want the (more reliable) auto-calculated DR value drawRadius = mdl->CalcDrawRadius(); } - diff --git a/rts/Sim/Objects/WorldObject.h b/rts/Sim/Objects/WorldObject.h index 028d14cada..d2eea3d5ae 100644 --- a/rts/Sim/Objects/WorldObject.h +++ b/rts/Sim/Objects/WorldObject.h @@ -5,6 +5,7 @@ #include "System/Object.h" #include "System/float4.h" +#include "System/Threading/ThreadPool.h" struct S3DModel; @@ -69,6 +70,9 @@ class CWorldObject: public CObject S3DModel* model = nullptr; protected: float drawRadius = 0.0f; ///< unsynced, used for projectile visibility culling + +public: + std::array mtTempNum = {}; }; #endif /* WORLD_OBJECT_H */ diff --git a/rts/Sim/Units/UnitHandler.cpp b/rts/Sim/Units/UnitHandler.cpp index 3efdb84440..603d64655d 100644 --- a/rts/Sim/Units/UnitHandler.cpp +++ b/rts/Sim/Units/UnitHandler.cpp @@ -304,6 +304,13 @@ void CUnitHandler::UpdateUnitMoveTypes() { SCOPED_TIMER("Sim::Unit::MoveType"); + for_mt(0, activeUnits.size(), [this](const int i){ + CUnit* unit = activeUnits[i]; + AMoveType* moveType = unit->moveType; + + moveType->UpdateObstacleAvoidance(); + }); + for (activeUpdateUnit = 0; activeUpdateUnit < activeUnits.size(); ++activeUpdateUnit) { CUnit* unit = activeUnits[activeUpdateUnit]; AMoveType* moveType = unit->moveType;