From e0928f15ac5f8595ab80cc61512b39073af1ff52 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Sat, 4 Nov 2023 14:50:29 -0700 Subject: [PATCH 01/55] Update ArenaMemWeightMode size estimates --- src/Sim/Arena/Arena.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Sim/Arena/Arena.h b/src/Sim/Arena/Arena.h index ce0f7bd8..fa796739 100644 --- a/src/Sim/Arena/Arena.h +++ b/src/Sim/Arena/Arena.h @@ -21,8 +21,8 @@ // Mode of speed/memory optimization for the arena // Will affect whether high memory consumption is used to slightly increase speed or not enum class ArenaMemWeightMode : byte { - HEAVY, // ~11MB per arena - LIGHT // ~0.8MB per arena + HEAVY, // ~611KB per arena with 4 cars + LIGHT // ~397KB per arena with 4 cars }; typedef std::function GoalScoreEventFn; From 8cf9ef49be17e776e5f031632437682c5ce5620f Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 7 Dec 2023 20:04:36 -0800 Subject: [PATCH 02/55] Make fields of btSequentialImpulseConstraintSolver public --- .../ConstraintSolver/btSequentialImpulseConstraintSolver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h b/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h index 2d47a058..5e6d04c1 100644 --- a/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h +++ b/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h @@ -50,7 +50,7 @@ btSequentialImpulseConstraintSolver { -protected: +public: btAlignedObjectArray m_tmpSolverBodyPool; btConstraintArray m_tmpSolverContactConstraintPool; btConstraintArray m_tmpSolverNonContactConstraintPool; From 8afb47bbffe99beb2120dc7048039512eb8e7a50 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 7 Dec 2023 20:05:04 -0800 Subject: [PATCH 03/55] Make _AddStaticCollisionShape() return the created rigidbody --- src/Sim/Arena/Arena.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Sim/Arena/Arena.h b/src/Sim/Arena/Arena.h index fa796739..1dbe1f54 100644 --- a/src/Sim/Arena/Arena.h +++ b/src/Sim/Arena/Arena.h @@ -152,7 +152,7 @@ class Arena { // NOTE: Passed shape pointer will be freed when arena is deconstructed template - void _AddStaticCollisionShape( + btRigidBody* _AddStaticCollisionShape( size_t rbIndex, size_t meshListIndex, T* shape, T* meshList, btVector3 posBT = btVector3(0, 0, 0), bool isHoopsNet = false) { @@ -169,6 +169,7 @@ class Arena { } else { _bulletWorld.addRigidBody(&shapeRB); } + return &shapeRB; } void _SetupArenaCollisionShapes(); From db0bb8b7e684b48425e9fe5a4c39a1d56b8c8172 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Fri, 8 Dec 2023 21:07:01 -0800 Subject: [PATCH 04/55] Add comment labels for hitbox type in CarConfig.cpp --- src/Sim/Car/CarConfig/CarConfig.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Sim/Car/CarConfig/CarConfig.cpp b/src/Sim/Car/CarConfig/CarConfig.cpp index f1271561..af70b8a5 100644 --- a/src/Sim/Car/CarConfig/CarConfig.cpp +++ b/src/Sim/Car/CarConfig/CarConfig.cpp @@ -16,12 +16,12 @@ // the ones everyone else uses/shares do not. const static Vec HITBOX_SIZES[6] = { - { 120.507f, 86.6994f, 38.6591f }, - { 130.427f, 85.7799f, 33.8f }, - { 131.32f, 87.1704f, 31.8944f }, - { 133.992f, 83.021f, 32.8f }, - { 129.519f, 84.6879f, 36.6591f }, - { 123.22f, 79.2103f, 44.1591f } + { 120.507f, 86.6994f, 38.6591f }, // OCTANE + { 130.427f, 85.7799f, 33.8f }, // DOMINUS + { 131.32f, 87.1704f, 31.8944f }, // PLANK + { 133.992f, 83.021f, 32.8f }, // BREAKOUT + { 129.519f, 84.6879f, 36.6591f }, // HYBRID + { 123.22f, 79.2103f, 44.1591f } // MERC }; const static Vec HITBOX_OFFSETS[6] = { From 4c9c2960ac6f5f3ad3829e52333d6f43fc80b6f6 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Fri, 8 Dec 2023 21:10:31 -0800 Subject: [PATCH 05/55] Remove physics rounding --- src/Sim/Ball/Ball.cpp | 11 ----------- src/Sim/Car/Car.cpp | 11 ----------- src/Sim/MutatorConfig/MutatorConfig.h | 4 +--- 3 files changed, 1 insertion(+), 25 deletions(-) diff --git a/src/Sim/Ball/Ball.cpp b/src/Sim/Ball/Ball.cpp index c0a8d1d4..77c6b3b0 100644 --- a/src/Sim/Ball/Ball.cpp +++ b/src/Sim/Ball/Ball.cpp @@ -129,17 +129,6 @@ void Ball::_FinishPhysicsTick(const MutatorConfig& mutatorConfig) { _rigidBody.m_angularVelocity = angVel; } - if (mutatorConfig.enablePhysicsRounding) { - _rigidBody.m_worldTransform.m_origin = - Math::RoundVec(_rigidBody.m_worldTransform.m_origin, 0.01 * UU_TO_BT); - - _rigidBody.m_linearVelocity = - Math::RoundVec(_rigidBody.m_linearVelocity, 0.01 * UU_TO_BT); - - _rigidBody.m_angularVelocity = - Math::RoundVec(_rigidBody.m_angularVelocity, 0.00001); - } - _internalState.updateCounter++; } diff --git a/src/Sim/Car/Car.cpp b/src/Sim/Car/Car.cpp index 0c5962fd..18ed40f9 100644 --- a/src/Sim/Car/Car.cpp +++ b/src/Sim/Car/Car.cpp @@ -192,17 +192,6 @@ void Car::_FinishPhysicsTick(const MutatorConfig& mutatorConfig) { _rigidBody.m_angularVelocity = angVel; } - if (mutatorConfig.enablePhysicsRounding) { - _rigidBody.m_worldTransform.m_origin = - Math::RoundVec(_rigidBody.m_worldTransform.m_origin, 0.01 * UU_TO_BT); - - _rigidBody.m_linearVelocity = - Math::RoundVec(_rigidBody.m_linearVelocity, 0.01 * UU_TO_BT); - - _rigidBody.m_angularVelocity = - Math::RoundVec(_rigidBody.m_angularVelocity, 0.00001); - } - _internalState.updateCounter++; } diff --git a/src/Sim/MutatorConfig/MutatorConfig.h b/src/Sim/MutatorConfig/MutatorConfig.h index ff77c3ab..8858918d 100644 --- a/src/Sim/MutatorConfig/MutatorConfig.h +++ b/src/Sim/MutatorConfig/MutatorConfig.h @@ -62,8 +62,6 @@ struct MutatorConfig { DemoMode demoMode = DemoMode::NORMAL; bool enableTeamDemos = false; - bool enablePhysicsRounding = true; - MutatorConfig(GameMode gameMode); RSAPI void Serialize(DataStreamOut& out) const; @@ -76,4 +74,4 @@ ballMaxSpeed, ballDrag, ballWorldFriction, ballWorldRestitution, jumpAccel, \ jumpImmediateForce, boostAccel, boostUsedPerSecond, respawnDelay, \ carSpawnBoostAmount, bumpCooldownTime, boostPadCooldown_Big, boostPadCooldown_Small, \ ballHitExtraForceScale, bumpForceScale, ballRadius, unlimitedFlips, unlimitedDoubleJumps, \ -demoMode, enableTeamDemos, enablePhysicsRounding \ No newline at end of file +demoMode, enableTeamDemos \ No newline at end of file From f80bfd4e95ceca7f4844f5d31785b2365c2fb813 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Fri, 8 Dec 2023 21:12:30 -0800 Subject: [PATCH 06/55] [pre-2.1.0] Update version number --- src/Framework.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Framework.h b/src/Framework.h index e2537d58..e5d59a6d 100644 --- a/src/Framework.h +++ b/src/Framework.h @@ -1,6 +1,6 @@ #pragma once -#define RS_VERSION "2.0.0" +#define RS_VERSION "pre-2.1.0" #include #include From b726b5c53385f0c4019d4fd22ee7e12a3c7ced2f Mon Sep 17 00:00:00 2001 From: ZealanL Date: Tue, 26 Dec 2023 03:01:39 -0800 Subject: [PATCH 07/55] Re-enable BVH quantization --- src/RocketSim.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RocketSim.cpp b/src/RocketSim.cpp index 0e159950..8561ee8c 100644 --- a/src/RocketSim.cpp +++ b/src/RocketSim.cpp @@ -125,7 +125,7 @@ void RocketSim::Init(std::filesystem::path collisionMeshesFolder) { btTriangleMesh* triMesh = meshFile.MakeBulletMesh(); - auto bvtMesh = new btBvhTriangleMeshShape(triMesh, false); + auto bvtMesh = new btBvhTriangleMeshShape(triMesh, true); btTriangleInfoMap* infoMap = new btTriangleInfoMap(); btGenerateInternalEdgeInfo(bvtMesh, infoMap); bvtMesh->setTriangleInfoMap(infoMap); From 5dd9dd8b20ee71c5adeb2d8d1be45dd7007aece2 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Tue, 26 Dec 2023 12:22:38 -0800 Subject: [PATCH 08/55] Implement experimental ball-arena collision resolution override --- .../CollisionDispatch/btCollisionObject.h | 11 + .../NarrowPhaseCollision/btManifoldPoint.h | 9 +- .../btPersistentManifold.cpp | 4 + .../btSequentialImpulseConstraintSolver.cpp | 300 +++++++++++------- .../btSequentialImpulseConstraintSolver.h | 7 + .../ConstraintSolver/btSolverConstraint.h | 4 + src/Sim/Arena/Arena.cpp | 3 + 7 files changed, 221 insertions(+), 117 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionObject.h b/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionObject.h index e22223cd..b72c4077 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionObject.h +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionObject.h @@ -123,6 +123,17 @@ btCollisionObject btVector3 m_customDebugColorRGB; + // ROCKETSIM CHANGE: Add custom info for special collision resolution + struct btSpecialResolveInfo { + int m_numSpecialCollisions; + btVector3 m_totalNormal; + float m_totalDist; + float m_restitution, m_friction; + + btSpecialResolveInfo() = default; + }; + btSpecialResolveInfo m_specialResolveInfo = {}; + public: BT_DECLARE_ALIGNED_ALLOCATOR(); diff --git a/libsrc/bullet3-3.24/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h b/libsrc/bullet3-3.24/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h index 36a645aa..8b528c2d 100644 --- a/libsrc/bullet3-3.24/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h +++ b/libsrc/bullet3-3.24/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h @@ -63,7 +63,8 @@ class btManifoldPoint m_contactCFM(0.f), m_contactERP(0.f), m_frictionCFM(0.f), - m_lifeTime(0) + m_lifeTime(0), + m_isSpecial(false) { } @@ -96,7 +97,8 @@ class btManifoldPoint m_frictionCFM(0.f), m_lifeTime(0), m_lateralFrictionDir1(0,0,0), - m_lateralFrictionDir2(0,0,0) + m_lateralFrictionDir2(0,0,0), + m_isSpecial(false) { } @@ -147,6 +149,9 @@ class btManifoldPoint btVector3 m_lateralFrictionDir1; btVector3 m_lateralFrictionDir2; + // ROCKETSIM CHANGE: Add flag for marking manifold point as needing special resolution + bool m_isSpecial; + btScalar getDistance() const { return m_distance1; diff --git a/libsrc/bullet3-3.24/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp b/libsrc/bullet3-3.24/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp index d4220ec6..8e3e3454 100644 --- a/libsrc/bullet3-3.24/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp @@ -190,6 +190,10 @@ int btPersistentManifold::sortCachedPoints(const btManifoldPoint& pt) int btPersistentManifold::getCacheEntry(const btManifoldPoint& newPoint) const { + // ROCKETSIM CHANGE: Don't overwrite old manifolds with new manifolds + // Disabling this return makes ball-arena collisions far less accurate to the game + return -1; + btScalar shortestDist = getContactBreakingThreshold() * getContactBreakingThreshold(); int size = getNumContacts(); int nearestPoint = -1; diff --git a/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp b/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp index 050d7bd2..4885b5b1 100644 --- a/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp +++ b/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp @@ -798,6 +798,7 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra btScalar& relaxation, const btVector3& rel_pos1, const btVector3& rel_pos2) { + // const btVector3& pos1 = cp.getPositionWorldOnA(); // const btVector3& pos2 = cp.getPositionWorldOnB(); @@ -955,7 +956,7 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra else { positionalError = -penetration * erp * invTimeStep; - } + } btScalar penetrationImpulse = positionalError * solverConstraint.m_jacDiagABInv; btScalar velocityImpulse = velocityError * solverConstraint.m_jacDiagABInv; @@ -976,6 +977,9 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra solverConstraint.m_lowerLimit = 0; solverConstraint.m_upperLimit = 1e10f; } + + // ROCKETSIM CHANGE: Copy over m_isSpecial from contact point + solverConstraint.m_isSpecial = cp.m_isSpecial; } void btSequentialImpulseConstraintSolver::setFrictionConstraintImpulse(btSolverConstraint& solverConstraint, @@ -996,9 +1000,8 @@ void btSequentialImpulseConstraintSolver::setFrictionConstraintImpulse(btSolverC } } -void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* manifold, const btContactSolverInfo& infoGlobal) -{ - btCollisionObject *colObj0 = 0, *colObj1 = 0; +void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* manifold, const btContactSolverInfo& infoGlobal) { + btCollisionObject* colObj0 = 0, * colObj1 = 0; colObj0 = (btCollisionObject*)manifold->getBody0(); colObj1 = (btCollisionObject*)manifold->getBody1(); @@ -1017,12 +1020,10 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m return; int rollingFriction = 1; - for (int j = 0; j < manifold->getNumContacts(); j++) - { + for (int j = 0; j < manifold->getNumContacts(); j++) { btManifoldPoint& cp = manifold->getContactPoint(j); - if (cp.getDistance() <= manifold->getContactProcessingThreshold()) - { + if (cp.getDistance() <= manifold->getContactProcessingThreshold()) { btVector3 rel_pos1; btVector3 rel_pos2; btScalar relaxation; @@ -1040,111 +1041,174 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin(); rel_pos2 = pos2 - colObj1->getWorldTransform().getOrigin(); - btVector3 vel1; - btVector3 vel2; - - solverBodyA->getVelocityInLocalPointNoDelta(rel_pos1, vel1); - solverBodyB->getVelocityInLocalPointNoDelta(rel_pos2, vel2); - - btVector3 vel = vel1 - vel2; - btScalar rel_vel = cp.m_normalWorldOnB.dot(vel); - setupContactConstraint(solverConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal, relaxation, rel_pos1, rel_pos2); - - /////setup the friction constraints - + solverConstraint.m_frictionIndex = m_tmpSolverContactFrictionConstraintPool.size(); - if ((cp.m_combinedRollingFriction > 0.f) && (rollingFriction > 0)) - { - { - addTorsionalFrictionConstraint(cp.m_normalWorldOnB, solverBodyIdA, solverBodyIdB, frictionIndex, cp, cp.m_combinedSpinningFriction, rel_pos1, rel_pos2, colObj0, colObj1, relaxation); - btVector3 axis0, axis1; - btPlaneSpace1(cp.m_normalWorldOnB, axis0, axis1); - axis0.normalize(); - axis1.normalize(); - - applyAnisotropicFriction(colObj0, axis0, btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - applyAnisotropicFriction(colObj1, axis0, btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - applyAnisotropicFriction(colObj0, axis1, btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - applyAnisotropicFriction(colObj1, axis1, btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - if (axis0.length() > 0.001) - addTorsionalFrictionConstraint(axis0, solverBodyIdA, solverBodyIdB, frictionIndex, cp, - cp.m_combinedRollingFriction, rel_pos1, rel_pos2, colObj0, colObj1, relaxation); - if (axis1.length() > 0.001) - addTorsionalFrictionConstraint(axis1, solverBodyIdA, solverBodyIdB, frictionIndex, cp, - cp.m_combinedRollingFriction, rel_pos1, rel_pos2, colObj0, colObj1, relaxation); + // ROCKETSIM CHANGE: Set btSpecialResolveInfo of bodies + if (cp.m_isSpecial) { + for (int i = 0; i < 2; i++) { + btCollisionObject* colObj = i ? colObj1 : colObj0; + if (colObj && !colObj->isStaticObject()) { + btCollisionObject::btSpecialResolveInfo& spri = colObj->m_specialResolveInfo; + spri.m_numSpecialCollisions++; + spri.m_friction = cp.m_combinedFriction; + spri.m_restitution = cp.m_combinedRestitution; + spri.m_totalNormal += cp.m_normalWorldOnB; + spri.m_totalDist += (i ? rel_pos2 : rel_pos1).length(); } } + } - ///Bullet has several options to set the friction directions - ///By default, each contact has only a single friction direction that is recomputed automatically very frame - ///based on the relative linear velocity. - ///If the relative velocity it zero, it will automatically compute a friction direction. - - ///You can also enable two friction directions, using the SOLVER_USE_2_FRICTION_DIRECTIONS. - ///In that case, the second friction direction will be orthogonal to both contact normal and first friction direction. - /// - ///If you choose SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION, then the friction will be independent from the relative projected velocity. - /// - ///The user can manually override the friction directions for certain contacts using a contact callback, - ///and use contactPoint.m_contactPointFlags |= BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED - ///In that case, you can set the target relative motion in each friction direction (cp.m_contactMotion1 and cp.m_contactMotion2) - ///this will give a conveyor belt effect - /// - - if (!(infoGlobal.m_solverMode & SOLVER_ENABLE_FRICTION_DIRECTION_CACHING) || !(cp.m_contactPointFlags & BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED)) - { - cp.m_lateralFrictionDir1 = vel - cp.m_normalWorldOnB * rel_vel; - btScalar lat_rel_vel = cp.m_lateralFrictionDir1.length2(); - if (!(infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION) && lat_rel_vel > SIMD_EPSILON) - { - cp.m_lateralFrictionDir1 *= 1.f / btSqrt(lat_rel_vel); - applyAnisotropicFriction(colObj0, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION); - applyAnisotropicFriction(colObj1, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION); - addFrictionConstraint(cp.m_lateralFrictionDir1, solverBodyIdA, solverBodyIdB, frictionIndex, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal); + // ROCKETSIM CHANGE: Rest of this function moved to convertContactInner + convertContactInner(infoGlobal, cp, solverConstraint, + colObj0, colObj1, solverBodyA, solverBodyB, solverBodyIdA, solverBodyIdB, + rel_pos1, rel_pos2, frictionIndex, relaxation, rollingFriction); + } + } +} - if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) - { - cp.m_lateralFrictionDir2 = cp.m_lateralFrictionDir1.cross(cp.m_normalWorldOnB); - cp.m_lateralFrictionDir2.normalize(); //?? - applyAnisotropicFriction(colObj0, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION); - applyAnisotropicFriction(colObj1, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION); - addFrictionConstraint(cp.m_lateralFrictionDir2, solverBodyIdA, solverBodyIdB, frictionIndex, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal); - } - } - else - { - btPlaneSpace1(cp.m_normalWorldOnB, cp.m_lateralFrictionDir1, cp.m_lateralFrictionDir2); +void btSequentialImpulseConstraintSolver::convertContactInner( + const btContactSolverInfo& infoGlobal, btManifoldPoint& cp, btSolverConstraint& solverConstraint, + btCollisionObject* colObj0, btCollisionObject* colObj1, btSolverBody* solverBodyA, btSolverBody* solverBodyB, int solverBodyIdA, int solverBodyIdB, + const btVector3& rel_pos1, const btVector3& rel_pos2, int frictionIndex, btScalar relaxation, btScalar rollingFriction) { + + if ((cp.m_combinedRollingFriction > 0.f) && (rollingFriction > 0)) { + { + addTorsionalFrictionConstraint(cp.m_normalWorldOnB, solverBodyIdA, solverBodyIdB, frictionIndex, cp, cp.m_combinedSpinningFriction, rel_pos1, rel_pos2, colObj0, colObj1, relaxation); + btVector3 axis0, axis1; + btPlaneSpace1(cp.m_normalWorldOnB, axis0, axis1); + axis0.normalize(); + axis1.normalize(); + + applyAnisotropicFriction(colObj0, axis0, btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); + applyAnisotropicFriction(colObj1, axis0, btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); + applyAnisotropicFriction(colObj0, axis1, btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); + applyAnisotropicFriction(colObj1, axis1, btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); + if (axis0.length() > 0.001) + addTorsionalFrictionConstraint(axis0, solverBodyIdA, solverBodyIdB, frictionIndex, cp, + cp.m_combinedRollingFriction, rel_pos1, rel_pos2, colObj0, colObj1, relaxation); + if (axis1.length() > 0.001) + addTorsionalFrictionConstraint(axis1, solverBodyIdA, solverBodyIdB, frictionIndex, cp, + cp.m_combinedRollingFriction, rel_pos1, rel_pos2, colObj0, colObj1, relaxation); + } + } - applyAnisotropicFriction(colObj0, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION); - applyAnisotropicFriction(colObj1, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION); - addFrictionConstraint(cp.m_lateralFrictionDir1, solverBodyIdA, solverBodyIdB, frictionIndex, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal); + ///Bullet has several options to set the friction directions + ///By default, each contact has only a single friction direction that is recomputed automatically very frame + ///based on the relative linear velocity. + ///If the relative velocity it zero, it will automatically compute a friction direction. + + ///You can also enable two friction directions, using the SOLVER_USE_2_FRICTION_DIRECTIONS. + ///In that case, the second friction direction will be orthogonal to both contact normal and first friction direction. + /// + ///If you choose SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION, then the friction will be independent from the relative projected velocity. + /// + ///The user can manually override the friction directions for certain contacts using a contact callback, + ///and use contactPoint.m_contactPointFlags |= BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED + ///In that case, you can set the target relative motion in each friction direction (cp.m_contactMotion1 and cp.m_contactMotion2) + ///this will give a conveyor belt effect + /// + + btVector3 vel1; + btVector3 vel2; + + solverBodyA->getVelocityInLocalPointNoDelta(rel_pos1, vel1); + solverBodyB->getVelocityInLocalPointNoDelta(rel_pos2, vel2); + + btVector3 vel = vel1 - vel2; + btScalar rel_vel = cp.m_normalWorldOnB.dot(vel); + + if (!(infoGlobal.m_solverMode & SOLVER_ENABLE_FRICTION_DIRECTION_CACHING) || !(cp.m_contactPointFlags & BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED)) { + cp.m_lateralFrictionDir1 = vel - cp.m_normalWorldOnB * rel_vel; + btScalar lat_rel_vel = cp.m_lateralFrictionDir1.length2(); + if (!(infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION) && lat_rel_vel > SIMD_EPSILON) { + cp.m_lateralFrictionDir1 *= 1.f / btSqrt(lat_rel_vel); + applyAnisotropicFriction(colObj0, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION); + applyAnisotropicFriction(colObj1, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION); + addFrictionConstraint(cp.m_lateralFrictionDir1, solverBodyIdA, solverBodyIdB, frictionIndex, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal); + + if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) { + cp.m_lateralFrictionDir2 = cp.m_lateralFrictionDir1.cross(cp.m_normalWorldOnB); + cp.m_lateralFrictionDir2.normalize(); //?? + applyAnisotropicFriction(colObj0, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION); + applyAnisotropicFriction(colObj1, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION); + addFrictionConstraint(cp.m_lateralFrictionDir2, solverBodyIdA, solverBodyIdB, frictionIndex, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal); + } + } else { + btPlaneSpace1(cp.m_normalWorldOnB, cp.m_lateralFrictionDir1, cp.m_lateralFrictionDir2); - if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) - { - applyAnisotropicFriction(colObj0, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION); - applyAnisotropicFriction(colObj1, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION); - addFrictionConstraint(cp.m_lateralFrictionDir2, solverBodyIdA, solverBodyIdB, frictionIndex, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal); - } + applyAnisotropicFriction(colObj0, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION); + applyAnisotropicFriction(colObj1, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION); + addFrictionConstraint(cp.m_lateralFrictionDir1, solverBodyIdA, solverBodyIdB, frictionIndex, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal); - if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS) && (infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION)) - { - cp.m_contactPointFlags |= BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED; - } - } + if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) { + applyAnisotropicFriction(colObj0, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION); + applyAnisotropicFriction(colObj1, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION); + addFrictionConstraint(cp.m_lateralFrictionDir2, solverBodyIdA, solverBodyIdB, frictionIndex, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal); } - else - { - addFrictionConstraint(cp.m_lateralFrictionDir1, solverBodyIdA, solverBodyIdB, frictionIndex, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal, cp.m_contactMotion1, cp.m_frictionCFM); - if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) - addFrictionConstraint(cp.m_lateralFrictionDir2, solverBodyIdA, solverBodyIdB, frictionIndex, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal, cp.m_contactMotion2, cp.m_frictionCFM); - } - setFrictionConstraintImpulse(solverConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal); + if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS) && (infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION)) { + cp.m_contactPointFlags |= BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED; } } + } else { + addFrictionConstraint(cp.m_lateralFrictionDir1, solverBodyIdA, solverBodyIdB, frictionIndex, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal, cp.m_contactMotion1, cp.m_frictionCFM); + + if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) + addFrictionConstraint(cp.m_lateralFrictionDir2, solverBodyIdA, solverBodyIdB, frictionIndex, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, infoGlobal, cp.m_contactMotion2, cp.m_frictionCFM); + } + setFrictionConstraintImpulse(solverConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal); +} + +void btSequentialImpulseConstraintSolver::convertContactSpecial(btCollisionObject& obj, const btContactSolverInfo& infoGlobal) { + + auto& specialResolveInfo = obj.m_specialResolveInfo; + btAssert(obj.m_specialResolveInfo.m_numSpecialCollisions > 0); + + // Calculate average distance and normal + float distance = obj.m_specialResolveInfo.m_totalDist / obj.m_specialResolveInfo.m_numSpecialCollisions; + btVector3 normal = obj.m_specialResolveInfo.m_totalNormal / obj.m_specialResolveInfo.m_numSpecialCollisions; + + // Create a temporary manifold for this collision + btManifoldPoint specialTempManifold = {}; + specialTempManifold.m_distance1 = distance; + specialTempManifold.m_normalWorldOnB = normal; + specialTempManifold.m_combinedFriction = specialResolveInfo.m_friction; + specialTempManifold.m_combinedRestitution = specialResolveInfo.m_restitution; + + int frictionIndex = m_tmpSolverContactConstraintPool.size(); + + // Get solver body A + int solverBodyIdA = getOrInitSolverBody(obj, infoGlobal.m_timeStep); + btSolverBody& solverBodyA = m_tmpSolverBodyPool[solverBodyIdA]; + + { // Create new solver body for B + if (m_fixedBodyId < 0) { + m_fixedBodyId = m_tmpSolverBodyPool.size(); + btSolverBody& fixedBody = m_tmpSolverBodyPool.expand(); + initSolverBody(&fixedBody, 0, infoGlobal.m_timeStep); + } } + int solverBodyIdB = m_fixedBodyId; + + // Initialize contact constraint + btSolverConstraint& solverConstraint = m_tmpSolverContactConstraintPool.expandNonInitializing(); + solverConstraint.m_solverBodyIdA = solverBodyIdA; + solverConstraint.m_solverBodyIdB = solverBodyIdB; + solverConstraint.m_originalContactPoint = NULL; + + btVector3 rel_pos1 = normal * -distance; + btVector3 rel_pos2 = btVector3(0,0,0); + + btSolverBody& solverBodyB = m_tmpSolverBodyPool[solverBodyIdB]; + + float relaxation = 0, rollingFriction = 0; + setupContactConstraint(solverConstraint, solverBodyIdA, solverBodyIdB, specialTempManifold, infoGlobal, relaxation, rel_pos1, rel_pos2); + convertContactInner(infoGlobal, specialTempManifold, solverConstraint, + &obj, NULL, &solverBodyA, &solverBodyB, solverBodyIdA, solverBodyIdB, + rel_pos1, rel_pos2, frictionIndex, relaxation, rollingFriction); +} void btSequentialImpulseConstraintSolver::convertContacts(btPersistentManifold** manifoldPtr, int numManifolds, const btContactSolverInfo& infoGlobal) { @@ -1489,6 +1553,17 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol convertContacts(manifoldPtr, numManifolds, infoGlobal); + // ROCKETSIM CHANGE: Handle special collisions + for (int i = 0; i < numBodies; i++) { + btCollisionObject* body = bodies[i]; + if (body && body->m_specialResolveInfo.m_numSpecialCollisions > 0) { + convertContactSpecial(*body, infoGlobal); + + // Reset + body->m_specialResolveInfo = {}; + } + } + // btContactSolverInfo info = infoGlobal; int numNonContactPool = m_tmpSolverNonContactConstraintPool.size(); @@ -1602,6 +1677,9 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration { const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[c]]; + if (!solveManifold.m_isSpecial) // ROCKETSIM CHANGE: Only resolve non-special manifolds + continue; + btScalar residual = resolveSingleConstraintRowLowerLimit(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA], m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB], solveManifold); leastSquaresResidual = btMax(leastSquaresResidual, residual * residual); @@ -1648,6 +1726,9 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration for (j = 0; j < numPoolConstraints; j++) { const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[j]]; + if (solveManifold.m_isSpecial) // ROCKETSIM CHANGE: Only resolve non-special manifolds + continue; + btScalar residual = resolveSingleConstraintRowLowerLimit(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA], m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB], solveManifold); leastSquaresResidual = btMax(leastSquaresResidual, residual * residual); } @@ -1714,6 +1795,7 @@ void btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySplitImpulseIte leastSquaresResidual = btMax(leastSquaresResidual, residual * residual); } } + if (leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || iteration >= (infoGlobal.m_numIterations - 1)) { #ifdef VERBOSE_RESIDUAL_PRINTF @@ -1740,22 +1822,6 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyIterations( //for ( int iteration = maxIterations-1 ; iteration >= 0;iteration--) { m_leastSquaresResidual = solveSingleIteration(iteration, bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal); - - if (m_leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || (iteration >= (maxIterations - 1))) - { -#ifdef VERBOSE_RESIDUAL_PRINTF - printf("residual = %f at iteration #%d\n", m_leastSquaresResidual, iteration); -#endif - m_analyticsData.m_numSolverCalls++; - m_analyticsData.m_numIterationsUsed = iteration+1; - m_analyticsData.m_islandId = -2; - if (numBodies>0) - m_analyticsData.m_islandId = bodies[0]->getCompanionId(); - m_analyticsData.m_numBodies = numBodies; - m_analyticsData.m_numContactManifolds = numManifolds; - m_analyticsData.m_remainingLeastSquaresResidual = m_leastSquaresResidual; - break; - } } } return 0.f; @@ -1767,7 +1833,11 @@ void btSequentialImpulseConstraintSolver::writeBackContacts(int iBegin, int iEnd { const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[j]; btManifoldPoint* pt = (btManifoldPoint*)solveManifold.m_originalContactPoint; - btAssert(pt); + + // ROCKETSIM CHANGE: Skip null contact points + if (!pt) + continue; + pt->m_appliedImpulse = solveManifold.m_appliedImpulse; // float f = m_tmpSolverContactFrictionConstraintPool[solveManifold.m_frictionIndex].m_appliedImpulse; // printf("pt->m_appliedImpulseLateral1 = %f\n", f); diff --git a/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h b/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h index 5e6d04c1..d6bde0c1 100644 --- a/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h +++ b/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h @@ -111,6 +111,13 @@ btSequentialImpulseConstraintSolver void convertContact(btPersistentManifold * manifold, const btContactSolverInfo& infoGlobal); + // ROCKETSIM CHANGE: Inner section of convertContact is made into its own function so it can be reused in a custom convertContact implementation + void convertContactInner(const btContactSolverInfo & infoGlobal, btManifoldPoint & cp, btSolverConstraint & solverConstraint, + btCollisionObject * colObj0, btCollisionObject * colObj1, btSolverBody * solverBodyA, btSolverBody * solverBodyB, int solverBodyIdA, int solverBodyIdB, + const btVector3 & rel_pos1, const btVector3 & rel_pos2, int frictionIndex, btScalar relaxation, btScalar rollingFriction); + + void convertContactSpecial(btCollisionObject& obj, const btContactSolverInfo& infoGlobal); + void convertJoints(btTypedConstraint * *constraints, int numConstraints, const btContactSolverInfo& infoGlobal); void convertJoint(btSolverConstraint * currentConstraintRow, btTypedConstraint * constraint, const btTypedConstraint::btConstraintInfo1& info1, int solverBodyIdA, int solverBodyIdB, const btContactSolverInfo& infoGlobal); diff --git a/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSolverConstraint.h b/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSolverConstraint.h index 87d49199..892acaf9 100644 --- a/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSolverConstraint.h +++ b/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSolverConstraint.h @@ -62,6 +62,10 @@ btSolverConstraint int m_solverBodyIdA; int m_solverBodyIdB; +public: + // ROCKETSIM CHANGE: Add matching property for btManifoldPoint.m_isSpecial + bool m_isSpecial; + enum btSolverConstraintType { BT_SOLVER_CONTACT_1D = 0, diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 27aef823..b7e07155 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -250,6 +250,9 @@ bool Arena::_BulletContactAddedCallback( // Ball + World Arena* arenaInst = (Arena*)bodyB->getUserPointer(); arenaInst->ball->_OnWorldCollision(arenaInst->gameMode, contactPoint.m_normalWorldOnB, arenaInst->tickTime); + + // Set as special + contactPoint.m_isSpecial = true; } btAdjustInternalEdgeContacts( From 0e22cb3a7b47eba1686ede20a9987152d11f54f3 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 3 Jan 2024 02:51:54 -0800 Subject: [PATCH 09/55] Make all members of btHashMap public --- libsrc/bullet3-3.24/LinearMath/btHashMap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsrc/bullet3-3.24/LinearMath/btHashMap.h b/libsrc/bullet3-3.24/LinearMath/btHashMap.h index 1fca0fb7..57d68621 100644 --- a/libsrc/bullet3-3.24/LinearMath/btHashMap.h +++ b/libsrc/bullet3-3.24/LinearMath/btHashMap.h @@ -218,7 +218,7 @@ class btHashKey template class btHashMap { -protected: +public: btAlignedObjectArray m_hashTable; btAlignedObjectArray m_next; From 8bfc9bca133ce4c53a1431ccef21eb0256f16260 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 3 Jan 2024 10:00:05 -0800 Subject: [PATCH 10/55] Disable special contact resolution on snowday --- src/Sim/Arena/Arena.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index b7e07155..0317f523 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -252,7 +252,8 @@ bool Arena::_BulletContactAddedCallback( arenaInst->ball->_OnWorldCollision(arenaInst->gameMode, contactPoint.m_normalWorldOnB, arenaInst->tickTime); // Set as special - contactPoint.m_isSpecial = true; + if (arenaInst->gameMode != GameMode::SNOWDAY) + contactPoint.m_isSpecial = true; } btAdjustInternalEdgeContacts( From c1356106046bbe7dc95a2370f3bd81e6c3a5eb18 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 3 Jan 2024 16:55:42 -0800 Subject: [PATCH 11/55] Add minimum car normal threshold for hoops extra ball hit force --- src/RLConst.h | 1 + src/Sim/Arena/Arena.cpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/RLConst.h b/src/RLConst.h index 954f1b57..30030c2e 100644 --- a/src/RLConst.h +++ b/src/RLConst.h @@ -122,6 +122,7 @@ namespace RLConst { BALL_CAR_EXTRA_IMPULSE_Z_SCALE_HOOPS_GROUND = BALL_CAR_EXTRA_IMPULSE_Z_SCALE * 1.55f, BALL_CAR_EXTRA_IMPULSE_FORWARD_SCALE = 0.65f, BALL_CAR_EXTRA_IMPULSE_MAXDELTAVEL_UU = 4600.f, + BALL_CAR_EXTRA_IMPULSE_Z_SCALE_HOOPS_NORMAL_Z_THRESH = 0.1f, CAR_SPAWN_REST_Z = 17.f, CAR_RESPAWN_Z = 36.f, diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 0317f523..86edff52 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -299,7 +299,11 @@ void Arena::_BtCallback_OnCarBallCollision(Car* car, Ball* ball, btManifoldPoint float relSpeed = RS_MIN(relVel.length(), BALL_CAR_EXTRA_IMPULSE_MAXDELTAVEL_UU); if (relSpeed > 0) { - float zScale = (gameMode == GameMode::HOOPS && car->_internalState.isOnGround) ? BALL_CAR_EXTRA_IMPULSE_Z_SCALE_HOOPS_GROUND : BALL_CAR_EXTRA_IMPULSE_Z_SCALE; + bool extraZScale = + gameMode == GameMode::HOOPS && + carState.isOnGround && + carState.rotMat.up.z > BALL_CAR_EXTRA_IMPULSE_Z_SCALE_HOOPS_NORMAL_Z_THRESH; + float zScale = extraZScale ? BALL_CAR_EXTRA_IMPULSE_Z_SCALE_HOOPS_GROUND : BALL_CAR_EXTRA_IMPULSE_Z_SCALE; btVector3 hitDir = (relPos * btVector3(1, 1, zScale)).safeNormalized(); btVector3 forwardDirAdjustment = carForward * hitDir.dot(carForward) * (1 - BALL_CAR_EXTRA_IMPULSE_FORWARD_SCALE); hitDir = (hitDir - forwardDirAdjustment).safeNormalized(); From 70300dddc564c9f5a44f56b84f4d872ee629ea3c Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 17 Jan 2024 14:49:27 -0800 Subject: [PATCH 12/55] Don't teleport cars outside the arena when demoed --- src/Sim/Car/Car.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Sim/Car/Car.cpp b/src/Sim/Car/Car.cpp index 18ed40f9..be22e025 100644 --- a/src/Sim/Car/Car.cpp +++ b/src/Sim/Car/Car.cpp @@ -69,18 +69,12 @@ void Car::_PreTickUpdate(GameMode gameMode, float tickTime, const MutatorConfig& _internalState.demoRespawnTimer = RS_MAX(_internalState.demoRespawnTimer - tickTime, 0); if (_internalState.demoRespawnTimer == 0) Respawn(gameMode, -1, mutatorConfig.carSpawnBoostAmount); - } - if (_internalState.isDemoed) { // Disable rigidbody simulation _rigidBody.m_activationState1 = DISABLE_SIMULATION; _rigidBody.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE; - // Put car far away from anything going on in the arena - _rigidBody.m_worldTransform.m_origin = btVector3(0, 0, -1000); - // Don't bother updating anything - return; } else { // Prevent the car's RB from becoming inactive _rigidBody.m_activationState1 = ACTIVE_TAG; @@ -88,6 +82,9 @@ void Car::_PreTickUpdate(GameMode gameMode, float tickTime, const MutatorConfig& } } + if (_internalState.isDemoed) + return; // No other updates need to occur + // Do first part of the btVehicleRL update (update wheel transforms, do traces, calculate friction impulses) _bulletVehicle.updateVehicleFirst(tickTime, grid); From f352d8732e14207fd168a99fe56d7c2deecd73c7 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 17 Jan 2024 14:51:32 -0800 Subject: [PATCH 13/55] Don't update suspension grid for demoed cars --- src/Sim/Arena/Arena.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 86edff52..03a28900 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -682,6 +682,9 @@ void Arena::Step(int ticksToSimulate) { #ifndef RS_NO_SUSPCOLGRID { // Add dynamic bodies to suspension grid for (Car* car : _cars) { + if (car->_internalState.isDemoed) + continue; + btVector3 min, max; car->_rigidBody.getAabb(min, max); _suspColGrid.UpdateDynamicCollisions(min, max, false); From 414680259890e7aa52d5ba493aa1446f68dddfea Mon Sep 17 00:00:00 2001 From: ZealanL <36944229+ZealanL@users.noreply.github.com> Date: Tue, 23 Jan 2024 16:50:11 -0800 Subject: [PATCH 14/55] Add updated accuracy descriptions in README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d8b43db3..4de55034 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,11 @@ This means RocketSim is accurate enough to: - *Train machine learning bots* - *Simulate different shots on the ball at different angles to find the best input combination* - *Simulate air control to find the optimal orientation input* +- *Simulate ground and floor pinches* However, RocketSim is NOT accurate enough to: - *Simulate entire games from inputs alone* -- *Accurately determine the outcome of powerful pinches* +- *Perfectly simulate long sequences of jumps and landings* ## Installation - Clone this repo and build it From 84341f7959ddc03e51bdd8ccbf1dba1c19097259 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 25 Jan 2024 23:01:50 -0800 Subject: [PATCH 15/55] Move everything within RocketSim namespace --- src/CollisionMeshFile/CollisionMeshFile.cpp | 6 +++++- src/CollisionMeshFile/CollisionMeshFile.h | 6 +++++- src/DataStream/DataStreamIn.h | 6 +++++- src/DataStream/DataStreamOut.h | 6 +++++- src/DataStream/SerializeObject.h | 6 +++++- src/Framework.h | 3 +++ src/Math/Math.cpp | 6 +++++- src/Math/Math.h | 6 +++++- src/Math/MathTypes/MathTypes.cpp | 6 +++++- src/Math/MathTypes/MathTypes.h | 14 +++++++++----- src/RLConst.h | 6 +++++- src/RocketSim.cpp | 13 +++++-------- src/RocketSim.h | 12 ++++++------ src/Sim/Arena/Arena.cpp | 7 +++++-- src/Sim/Arena/Arena.h | 6 +++++- src/Sim/Ball/Ball.cpp | 6 +++++- src/Sim/Ball/Ball.h | 14 ++++++++++---- src/Sim/BallHitInfo/BallHitInfo.cpp | 6 +++++- src/Sim/BallHitInfo/BallHitInfo.h | 6 +++++- src/Sim/BallPredTracker/BallPredTracker.cpp | 4 ++++ src/Sim/BallPredTracker/BallPredTracker.h | 6 +++++- src/Sim/BoostPad/BoostPad.cpp | 4 ++++ src/Sim/BoostPad/BoostPad.h | 6 +++++- src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.cpp | 6 +++++- src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.h | 6 +++++- src/Sim/Car/Car.cpp | 6 +++++- src/Sim/Car/Car.h | 6 +++++- src/Sim/Car/CarConfig/CarConfig.cpp | 8 ++++++-- src/Sim/Car/CarConfig/CarConfig.h | 6 +++++- src/Sim/CarControls.h | 6 +++++- src/Sim/CollisionMasks.h | 6 +++++- src/Sim/GameEventTracker/GameEventTracker.cpp | 4 ++++ src/Sim/GameEventTracker/GameEventTracker.h | 6 +++++- src/Sim/GameMode.h | 6 +++++- src/Sim/MutatorConfig/MutatorConfig.cpp | 6 +++++- src/Sim/MutatorConfig/MutatorConfig.h | 6 +++++- .../SuspensionCollisionGrid.cpp | 6 +++++- .../SuspensionCollisionGrid.h | 4 ++++ src/Sim/btVehicleRL/btVehicleRL.cpp | 6 +++++- src/Sim/btVehicleRL/btVehicleRL.h | 6 +++++- 40 files changed, 205 insertions(+), 56 deletions(-) diff --git a/src/CollisionMeshFile/CollisionMeshFile.cpp b/src/CollisionMeshFile/CollisionMeshFile.cpp index 69402452..2db589e6 100644 --- a/src/CollisionMeshFile/CollisionMeshFile.cpp +++ b/src/CollisionMeshFile/CollisionMeshFile.cpp @@ -6,6 +6,8 @@ #include "../../libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" #include "../../libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMesh.h" +RS_NS_START + void CollisionMeshFile::ReadFromFile(std::string filePath) { constexpr char ERROR_PREFIX_STR[] = " > CollisionMeshFile::ReadFromFile(): "; @@ -94,4 +96,6 @@ void CollisionMeshFile::UpdateHash() { } this->hash = hash; -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/CollisionMeshFile/CollisionMeshFile.h b/src/CollisionMeshFile/CollisionMeshFile.h index 6833e6bf..7c0cd1b3 100644 --- a/src/CollisionMeshFile/CollisionMeshFile.h +++ b/src/CollisionMeshFile/CollisionMeshFile.h @@ -7,6 +7,8 @@ class btTriangleMesh; +RS_NS_START + // Collision mesh file structure based off of the one in https://github.com/ZealanL/RLArenaCollisionDumper struct CollisionMeshFile { @@ -31,4 +33,6 @@ struct CollisionMeshFile { void ReadFromFile(std::string filePath); btTriangleMesh* MakeBulletMesh(); void UpdateHash(); -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/DataStream/DataStreamIn.h b/src/DataStream/DataStreamIn.h index 15288499..0fca06ce 100644 --- a/src/DataStream/DataStreamIn.h +++ b/src/DataStream/DataStreamIn.h @@ -3,6 +3,8 @@ #include "SerializeObject.h" +RS_NS_START + // Basic struct for reading raw data from a file struct DataStreamIn { std::vector data; @@ -81,4 +83,6 @@ struct DataStreamIn { void ReadMultiple(Args&... args) { ReadMultipleFromList({ args... }); } -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/DataStream/DataStreamOut.h b/src/DataStream/DataStreamOut.h index c57c0e7d..19f30296 100644 --- a/src/DataStream/DataStreamOut.h +++ b/src/DataStream/DataStreamOut.h @@ -3,6 +3,8 @@ #include "SerializeObject.h" +RS_NS_START + // Basic struct for writing raw data to a file struct DataStreamOut { std::vector data; @@ -65,4 +67,6 @@ inline void DataStreamOut::Write(const Vec& val) { template <> inline void DataStreamOut::Write(const RotMat& val) { WriteMultiple(val.forward, val.right, val.up); -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/DataStream/SerializeObject.h b/src/DataStream/SerializeObject.h index fa2dcc33..020ebdea 100644 --- a/src/DataStream/SerializeObject.h +++ b/src/DataStream/SerializeObject.h @@ -1,6 +1,8 @@ #pragma once #include "../Framework.h" +RS_NS_START + struct SerializeObject { void* ptr; size_t size = -1; @@ -17,4 +19,6 @@ struct SerializeObject { ptr = other.ptr; size = other.size; } -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/Framework.h b/src/Framework.h index e5d59a6d..4591563d 100644 --- a/src/Framework.h +++ b/src/Framework.h @@ -73,6 +73,9 @@ typedef uint8_t byte; #define RS_ALIGN_16 alignas(16) +#define RS_NS_START namespace RocketSim { +#define RS_NS_END } + template size_t __RS_GET_ARGUMENT_COUNT(Args ...) { return sizeof...(Args); diff --git a/src/Math/Math.cpp b/src/Math/Math.cpp index 31ff41b3..499c95b2 100644 --- a/src/Math/Math.cpp +++ b/src/Math/Math.cpp @@ -1,5 +1,7 @@ #include "Math.h" +RS_NS_START + float LinearPieceCurve::GetOutput(float input, float defaultOutput) const { float output = input; @@ -68,4 +70,6 @@ float Math::WrapNormalizeFloat(float val, float minmax) { else if (result < -minmax) result += minmax * 2; return result; -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/Math/Math.h b/src/Math/Math.h index 574e7afe..13364815 100644 --- a/src/Math/Math.h +++ b/src/Math/Math.h @@ -1,6 +1,8 @@ #pragma once #include "../BaseInc.h" +RS_NS_START + struct LinearPieceCurve { std::map valueMappings; @@ -19,4 +21,6 @@ namespace Math { RSAPI std::default_random_engine& GetRandEngine(); RSAPI float WrapNormalizeFloat(float val, float minmax); -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/Math/MathTypes/MathTypes.cpp b/src/Math/MathTypes/MathTypes.cpp index 4fb92069..e47e2e2b 100644 --- a/src/Math/MathTypes/MathTypes.cpp +++ b/src/Math/MathTypes/MathTypes.cpp @@ -2,6 +2,8 @@ #include "../Math.h" +RS_NS_START + #define VEC_OP_VEC(op) \ Vec Vec::operator op(const Vec& other) const { return Vec(x op other.x, y op other.y, z op other.z, _w op other._w); } \ Vec& Vec::operator op##=(const Vec& other) { return *this = *this op other; } @@ -111,4 +113,6 @@ void Angle::NormalizeFix() { yaw = Math::WrapNormalizeFloat(yaw, M_PI); pitch = Math::WrapNormalizeFloat(pitch, M_PI / 2); roll = Math::WrapNormalizeFloat(roll, M_PI); -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/Math/MathTypes/MathTypes.h b/src/Math/MathTypes/MathTypes.h index 6c2b0696..2ed07301 100644 --- a/src/Math/MathTypes/MathTypes.h +++ b/src/Math/MathTypes/MathTypes.h @@ -1,6 +1,8 @@ #pragma once #include "../../BaseInc.h" +RS_NS_START + // RocketSim 3D vector struct struct RS_ALIGN_16 Vec { float x, y, z; @@ -40,9 +42,9 @@ struct RS_ALIGN_16 Vec { Vec Cross(const Vec& other) const { return Vec( - (y * other.z) - (z * other.y), - (z * other.x) - (x * other.z), - (x * other.y) - (y * other.x) + (y * other.z) - (z * other.y), + (z * other.x) - (x * other.z), + (x * other.y) - (y * other.x) ); } @@ -232,7 +234,7 @@ struct RS_ALIGN_16 RotMat { RotMat result; for (size_t i = 0; i < 3; i++) - for (size_t j = 0; j < 3; j++) + for (size_t j = 0; j < 3; j++) for (size_t k = 0; k < 3; k++) result[i][j] += (*this)[i][j] * other[k][j]; @@ -296,4 +298,6 @@ struct Angle { stream << "(YPR)[ " << ang.yaw << ", " << ang.pitch << ", " << ang.roll << " ]"; return stream; } -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/RLConst.h b/src/RLConst.h index 30030c2e..e152495e 100644 --- a/src/RLConst.h +++ b/src/RLConst.h @@ -2,6 +2,8 @@ #include "BaseInc.h" #include "Math/Math.h" +RS_NS_START + // Constant/default values from the game namespace RLConst { @@ -421,4 +423,6 @@ namespace RLConst { {2200.f, 417.f}, } }; -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/RocketSim.cpp b/src/RocketSim.cpp index 8561ee8c..af4d23cb 100644 --- a/src/RocketSim.cpp +++ b/src/RocketSim.cpp @@ -1,14 +1,11 @@ #include "RocketSim.h" -#ifdef RS_PYBIND -// Make sure it gets compiled -#include "../python/src/PYB.h" -#endif - #include "../libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" #include "../libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMesh.h" #include "../libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h" +using namespace RocketSim; + struct MeshHashSet { std::unordered_map hashes; void AddAll(std::initializer_list hashesToAdd) { @@ -48,18 +45,18 @@ RocketSimStage RocketSim::GetStage() { return stage; } -std::vector& RocketSim::GetArenaCollisionShapes(GameMode gameMode) { +std::vector& RocketSim::GetArenaCollisionShapes(RocketSim::GameMode gameMode) { static std::vector arenaCollisionMeshes; static std::vector arenaCollisionMeshes_hoops; - return (gameMode == GameMode::HOOPS ? arenaCollisionMeshes_hoops : arenaCollisionMeshes); + return (gameMode == RocketSim::GameMode::HOOPS ? arenaCollisionMeshes_hoops : arenaCollisionMeshes); } #ifndef RS_NO_SUSPCOLGRID static SuspensionCollisionGrid suspColGrids_soccar[] = { {GameMode::SOCCAR, true}, {GameMode::SOCCAR, false} }, suspColGrids_hoops[] = { {GameMode::HOOPS, true}, {GameMode::HOOPS, false} }; -SuspensionCollisionGrid& RocketSim::GetDefaultSuspColGrid(GameMode gameMode, bool isLight) { + SuspensionCollisionGrid& RocketSim::GetDefaultSuspColGrid(GameMode gameMode, bool isLight) { if (gameMode == GameMode::HOOPS) { return suspColGrids_hoops[isLight]; } else { diff --git a/src/RocketSim.h b/src/RocketSim.h index e7dac426..8d8f4b24 100644 --- a/src/RocketSim.h +++ b/src/RocketSim.h @@ -12,13 +12,13 @@ class btBvhTriangleMeshShape; -enum class RocketSimStage : byte { - UNINITIALIZED, - INITIALIZING, - INITIALIZED -}; - namespace RocketSim { + enum class RocketSimStage : byte { + UNINITIALIZED, + INITIALIZING, + INITIALIZED + }; + void Init(std::filesystem::path collisionMeshesFolder); void AssertInitialized(const char* errorMsgPrefix); diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 03a28900..043dd5e5 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -1,5 +1,4 @@ #include "Arena.h" - #include "../../RocketSim.h" #include "../../../libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h" @@ -7,6 +6,8 @@ #include "../../../libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btBoxShape.h" #include "../../../libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btSphereShape.h" +RS_NS_START + RSAPI void Arena::SetMutatorConfig(const MutatorConfig& mutatorConfig) { bool @@ -1065,4 +1066,6 @@ void Arena::_SetupArenaCollisionShapes() { ); } } -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/Arena/Arena.h b/src/Sim/Arena/Arena.h index 1dbe1f54..8f6a2956 100644 --- a/src/Sim/Arena/Arena.h +++ b/src/Sim/Arena/Arena.h @@ -18,6 +18,8 @@ #include "../../../libsrc/bullet3-3.24/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h" #include "../../../libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h" +RS_NS_START + // Mode of speed/memory optimization for the arena // Will affect whether high memory consumption is used to slightly increase speed or not enum class ArenaMemWeightMode : byte { @@ -196,4 +198,6 @@ class Arena { // Making this private because horrible memory overflows would happen if you changed it ArenaMemWeightMode _memWeightMode; -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/Ball/Ball.cpp b/src/Sim/Ball/Ball.cpp index 77c6b3b0..a59a8efd 100644 --- a/src/Sim/Ball/Ball.cpp +++ b/src/Sim/Ball/Ball.cpp @@ -7,6 +7,8 @@ #include "../../../libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btConvexHullShape.h" #include "../CollisionMasks.h" +RS_NS_START + bool BallState::Matches(const BallState& other, float marginPos, float marginVel, float marginAngVel) const { return pos.DistSq(other.pos) < (marginPos * marginPos) && @@ -217,4 +219,6 @@ void Ball::_OnWorldCollision(GameMode gameMode, Vec normal, float tickTime) { groundStickApplied = true; } } -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/Ball/Ball.h b/src/Sim/Ball/Ball.h index 660d883b..3e5c068b 100644 --- a/src/Sim/Ball/Ball.h +++ b/src/Sim/Ball/Ball.h @@ -10,10 +10,14 @@ #include "../../../libsrc/bullet3-3.24/BulletDynamics/Dynamics/btRigidBody.h" #include "../../../libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btSphereShape.h" +class btDynamicsWorld; + +RS_NS_START + struct BallState { // Incremented every update, reset when SetState() is called -// Used for telling if a stateset occured -// Not serialized + // Used for telling if a stateset occured + // Not serialized uint64_t updateCounter = 0; // Position in world space @@ -64,7 +68,7 @@ class Ball { // For removal by Arena static void _DestroyBall(Ball* ball) { delete ball; } - void _BulletSetup(GameMode gameMode, class btDynamicsWorld* bulletWorld, const MutatorConfig& mutatorConfig); + void _BulletSetup(GameMode gameMode, btDynamicsWorld* bulletWorld, const MutatorConfig& mutatorConfig); bool groundStickApplied = false; Vec _velocityImpulseCache = { 0,0,0 }; @@ -93,4 +97,6 @@ class Ball { private: Ball() {} -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/BallHitInfo/BallHitInfo.cpp b/src/Sim/BallHitInfo/BallHitInfo.cpp index dc18964f..7cab812a 100644 --- a/src/Sim/BallHitInfo/BallHitInfo.cpp +++ b/src/Sim/BallHitInfo/BallHitInfo.cpp @@ -1,5 +1,7 @@ #include "BallHitInfo.h" +RS_NS_START + void BallHitInfo::Serialize(DataStreamOut& out) const { out.Write(isValid); @@ -12,4 +14,6 @@ void BallHitInfo::Deserialize(DataStreamIn& in) { if (isValid) in.ReadMultiple(BALLHITINFO_SERIALIZATION_FIELDS); -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/BallHitInfo/BallHitInfo.h b/src/Sim/BallHitInfo/BallHitInfo.h index f22bc3fd..03185fd2 100644 --- a/src/Sim/BallHitInfo/BallHitInfo.h +++ b/src/Sim/BallHitInfo/BallHitInfo.h @@ -4,6 +4,8 @@ #include "../../DataStream/DataStreamIn.h" #include "../../DataStream/DataStreamOut.h" +RS_NS_START + struct BallHitInfo { // If false, all other fields within this struct should not be trusted bool isValid = false; @@ -25,4 +27,6 @@ struct BallHitInfo { // NOTE: Does not include isValid #define BALLHITINFO_SERIALIZATION_FIELDS \ -relativePosOnBall, ballPos, extraHitVel, tickCountWhenHit, tickCountWhenExtraImpulseApplied \ No newline at end of file +relativePosOnBall, ballPos, extraHitVel, tickCountWhenHit, tickCountWhenExtraImpulseApplied + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/BallPredTracker/BallPredTracker.cpp b/src/Sim/BallPredTracker/BallPredTracker.cpp index a2f6fca8..90a43d60 100644 --- a/src/Sim/BallPredTracker/BallPredTracker.cpp +++ b/src/Sim/BallPredTracker/BallPredTracker.cpp @@ -1,5 +1,7 @@ #include "BallPredTracker.h" +RS_NS_START + BallPredTracker::BallPredTracker(Arena* arena, size_t numPredTicks) : numPredTicks(numPredTicks) { // Make ball pred arena this->ballPredArena = Arena::Create(arena->gameMode, ArenaMemWeightMode::LIGHT, arena->GetTickRate()); @@ -61,3 +63,5 @@ void BallPredTracker::ForceUpdateAllPred(Arena* arena) { BallState BallPredTracker::GetBallStateForTime(float predTime) const { return BallState(); } + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/BallPredTracker/BallPredTracker.h b/src/Sim/BallPredTracker/BallPredTracker.h index 315fff21..95324e86 100644 --- a/src/Sim/BallPredTracker/BallPredTracker.h +++ b/src/Sim/BallPredTracker/BallPredTracker.h @@ -1,6 +1,8 @@ #pragma once #include "../Arena/Arena.h" +RS_NS_START + // An external tool struct that predicts the ball of a given arena struct BallPredTracker { Arena* ballPredArena; @@ -22,4 +24,6 @@ struct BallPredTracker { // Get the predicted ball state at a given future time delta BallState GetBallStateForTime(float predTime) const; -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/BoostPad/BoostPad.cpp b/src/Sim/BoostPad/BoostPad.cpp index 14327f5a..3c5a0f12 100644 --- a/src/Sim/BoostPad/BoostPad.cpp +++ b/src/Sim/BoostPad/BoostPad.cpp @@ -4,6 +4,8 @@ #include "../../../libsrc/bullet3-3.24/BulletDynamics/Dynamics/btRigidBody.h" +RS_NS_START + BoostPad* BoostPad::_AllocBoostPad() { return new BoostPad(); } @@ -90,3 +92,5 @@ void BoostPadState::Deserialize(DataStreamIn& in) { BOOSTPAD_SERIALIZATION_FIELDS ); } + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/BoostPad/BoostPad.h b/src/Sim/BoostPad/BoostPad.h index 13135690..b583fe90 100644 --- a/src/Sim/BoostPad/BoostPad.h +++ b/src/Sim/BoostPad/BoostPad.h @@ -8,6 +8,8 @@ #include "../MutatorConfig/MutatorConfig.h" +RS_NS_START + struct BoostPadState { bool isActive = true; float cooldown = 0; @@ -44,4 +46,6 @@ class BoostPad { void _PostTickUpdate(float tickTime, const MutatorConfig& mutatorConfig); private: BoostPad() {} -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.cpp b/src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.cpp index 60a5218e..e5e1321e 100644 --- a/src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.cpp +++ b/src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.cpp @@ -1,5 +1,7 @@ #include "BoostPadGrid.h" +RS_NS_START + void BoostPadGrid::CheckCollision(Car* car) { if (car->_internalState.isDemoed || car->_internalState.boost >= 100) return; @@ -36,4 +38,6 @@ void BoostPadGrid::Add(BoostPad* pad) { } else { ptrInArray = pad; } -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.h b/src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.h index b0b29026..a41ecbee 100644 --- a/src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.h +++ b/src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.h @@ -4,6 +4,8 @@ #include "../BoostPad.h" +RS_NS_START + struct BoostPadGrid { constexpr static float EXTENT_X = 4096.f, @@ -23,4 +25,6 @@ struct BoostPadGrid { void CheckCollision(Car* car); void Add(BoostPad* pad); -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/Car/Car.cpp b/src/Sim/Car/Car.cpp index be22e025..2f19943e 100644 --- a/src/Sim/Car/Car.cpp +++ b/src/Sim/Car/Car.cpp @@ -4,6 +4,8 @@ #include "../../../libsrc/bullet3-3.24/BulletDynamics/Dynamics/btDynamicsWorld.h" +RS_NS_START + // Update our internal state from bullet and return it CarState Car::GetState() { _internalState.pos = _rigidBody.m_worldTransform.m_origin * BT_TO_UU; @@ -804,4 +806,6 @@ void Car::_UpdateAutoRoll(float tickTime, const MutatorConfig& mutatorConfig, in _rigidBody.applyCentralForce(groundDownDir * RLConst::CAR_AUTOROLL_FORCE * UU_TO_BT * CAR_MASS_BT); _rigidBody.applyTorque(_rigidBody.m_invInertiaTensorWorld.inverse() * (torqueForward + torqueRight) * RLConst::CAR_AUTOROLL_TORQUE); -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/Car/Car.h b/src/Sim/Car/Car.h index 172a021f..536373d9 100644 --- a/src/Sim/Car/Car.h +++ b/src/Sim/Car/Car.h @@ -11,6 +11,8 @@ #include "../../../libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCompoundShape.h" #include "../../../src/Sim/btVehicleRL/btVehicleRL.h" +RS_NS_START + struct CarState { // Incremented every update, reset when SetState() is called @@ -177,4 +179,6 @@ class Car { void _UpdateAutoRoll(float tickTime, const MutatorConfig& mutatorConfig, int numWheelsInContact); Car() {} -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/Car/CarConfig/CarConfig.cpp b/src/Sim/Car/CarConfig/CarConfig.cpp index af70b8a5..9742d2b5 100644 --- a/src/Sim/Car/CarConfig/CarConfig.cpp +++ b/src/Sim/Car/CarConfig/CarConfig.cpp @@ -1,5 +1,7 @@ #include "CarConfig.h" +RS_NS_START + // Default car-type config definitions // For those confused about the hitbox numbers, @@ -69,7 +71,7 @@ const static Vec BACK_WHEELS_OFFSET[6] = { // Using a macro here for convenience #define MAKE_CAR_CONFIG(name, index) \ - const CarConfig CAR_CONFIG_##name = { \ + const CarConfig RocketSim::CAR_CONFIG_##name = { \ HITBOX_SIZES[index], \ HITBOX_OFFSETS[index], \ { FRONT_WHEEL_RADS[index], FRONT_WHEEL_SUS_REST[index], FRONT_WHEELS_OFFSET[index] }, \ @@ -81,4 +83,6 @@ MAKE_CAR_CONFIG(DOMINUS, 1); MAKE_CAR_CONFIG(PLANK, 2); MAKE_CAR_CONFIG(BREAKOUT, 3); MAKE_CAR_CONFIG(HYBRID, 4); -MAKE_CAR_CONFIG(MERC, 5); \ No newline at end of file +MAKE_CAR_CONFIG(MERC, 5); + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/Car/CarConfig/CarConfig.h b/src/Sim/Car/CarConfig/CarConfig.h index 7f9847be..9bd8ee96 100644 --- a/src/Sim/Car/CarConfig/CarConfig.h +++ b/src/Sim/Car/CarConfig/CarConfig.h @@ -1,6 +1,8 @@ #pragma once #include "../../../BaseInc.h" +RS_NS_START + struct WheelPairConfig { // Radius of both wheels float wheelRadius; @@ -38,4 +40,6 @@ WHEEL_PAIR_CONFIG_SERIALIZATION_FIELDS(name.backWheels) \ // Global car configurations for all car type presets // NOTE: CAR_CONFIG_PLANK is the batmobile preset RSAPI const extern CarConfig - CAR_CONFIG_OCTANE, CAR_CONFIG_DOMINUS, CAR_CONFIG_PLANK, CAR_CONFIG_BREAKOUT, CAR_CONFIG_HYBRID, CAR_CONFIG_MERC; \ No newline at end of file + CAR_CONFIG_OCTANE, CAR_CONFIG_DOMINUS, CAR_CONFIG_PLANK, CAR_CONFIG_BREAKOUT, CAR_CONFIG_HYBRID, CAR_CONFIG_MERC; + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/CarControls.h b/src/Sim/CarControls.h index 9ceb6f41..107ab5a3 100644 --- a/src/Sim/CarControls.h +++ b/src/Sim/CarControls.h @@ -1,6 +1,8 @@ #pragma once #include "../BaseInc.h" +RS_NS_START + // Stores all control inputs to a car struct CarControls { // Driving control @@ -33,4 +35,6 @@ struct CarControls { #define CAR_CONTROLS_SERIALIZATION_FIELDS(name) \ name.throttle, name.steer, \ name.pitch, name.yaw, name.roll, \ -name.boost, name.jump, name.handbrake \ No newline at end of file +name.boost, name.jump, name.handbrake + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/CollisionMasks.h b/src/Sim/CollisionMasks.h index a4d961ed..3badf9c0 100644 --- a/src/Sim/CollisionMasks.h +++ b/src/Sim/CollisionMasks.h @@ -1,8 +1,12 @@ #pragma once #include "../Framework.h" +RS_NS_START + // Collision masks for different types of objects // Used so that the net in hoops doesn't collide with the cars enum CollisionMasks : uint32_t { HOOPS_NET = (1 << 8) -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/GameEventTracker/GameEventTracker.cpp b/src/Sim/GameEventTracker/GameEventTracker.cpp index 7f03e2e7..0dae55bc 100644 --- a/src/Sim/GameEventTracker/GameEventTracker.cpp +++ b/src/Sim/GameEventTracker/GameEventTracker.cpp @@ -1,5 +1,7 @@ #include "GameEventTracker.h" +RS_NS_START + bool GetShooterPasser(Arena* arena, Team team, Car*& shooterOut, bool findPasser, Car*& passerOut, uint64_t maxShooterTicks, uint64_t maxPasserTicks) { shooterOut = passerOut = NULL; // TODO: Instead of looping over cars to find who hit it last, use persistent info @@ -159,3 +161,5 @@ void GameEventTracker::ResetPersistentInfo() { // _ballShotGoalTeam doesn't need to be reset } + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/GameEventTracker/GameEventTracker.h b/src/Sim/GameEventTracker/GameEventTracker.h index 13a2cc1f..66f08eb1 100644 --- a/src/Sim/GameEventTracker/GameEventTracker.h +++ b/src/Sim/GameEventTracker/GameEventTracker.h @@ -1,6 +1,8 @@ #pragma once #include "../Arena/Arena.h" +RS_NS_START + typedef std::function ShotEventFn; typedef std::function GoalEventFn; typedef std::function SaveEventFn; @@ -95,4 +97,6 @@ struct GameEventTracker { // Automatically called from Update() when the ball's state has been set since last update // Call this whenever you set the arena to a new state if you want to be extra safe RSAPI void ResetPersistentInfo(); -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/GameMode.h b/src/Sim/GameMode.h index 91304e32..731bdb6a 100644 --- a/src/Sim/GameMode.h +++ b/src/Sim/GameMode.h @@ -1,6 +1,8 @@ #pragma once #include "../Framework.h" +RS_NS_START + enum class GameMode : byte { SOCCAR, HOOPS, @@ -18,4 +20,6 @@ constexpr const char* GAMEMODE_STRS[] = { "hoops", "heatseeker", "snowday" -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/MutatorConfig/MutatorConfig.cpp b/src/Sim/MutatorConfig/MutatorConfig.cpp index 18876ca6..70d386c9 100644 --- a/src/Sim/MutatorConfig/MutatorConfig.cpp +++ b/src/Sim/MutatorConfig/MutatorConfig.cpp @@ -1,5 +1,7 @@ #include "MutatorConfig.h" +RS_NS_START + MutatorConfig::MutatorConfig(GameMode gameMode) { using namespace RLConst; @@ -38,4 +40,6 @@ void MutatorConfig::Deserialize(DataStreamIn& in) { } in.ReadMultiple(MUTATOR_CONFIG_SERIALIZATION_FIELDS); -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/MutatorConfig/MutatorConfig.h b/src/Sim/MutatorConfig/MutatorConfig.h index 8858918d..702a6268 100644 --- a/src/Sim/MutatorConfig/MutatorConfig.h +++ b/src/Sim/MutatorConfig/MutatorConfig.h @@ -5,6 +5,8 @@ #include "../../DataStream/DataStreamIn.h" #include "../../DataStream/DataStreamOut.h" +RS_NS_START + enum class DemoMode : byte { NORMAL, ON_CONTACT, @@ -74,4 +76,6 @@ ballMaxSpeed, ballDrag, ballWorldFriction, ballWorldRestitution, jumpAccel, \ jumpImmediateForce, boostAccel, boostUsedPerSecond, respawnDelay, \ carSpawnBoostAmount, bumpCooldownTime, boostPadCooldown_Big, boostPadCooldown_Small, \ ballHitExtraForceScale, bumpForceScale, ballRadius, unlimitedFlips, unlimitedDoubleJumps, \ -demoMode, enableTeamDemos \ No newline at end of file +demoMode, enableTeamDemos + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.cpp b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.cpp index a27ab2a4..e9887882 100644 --- a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.cpp +++ b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.cpp @@ -3,6 +3,8 @@ #include "../../../libsrc/bullet3-3.24/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" #include "../../../libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" +RS_NS_START + // Quick virtual btTriangleCallback child class to simply check if any triangles are processed struct BoolHitTriangleCallback : public btTriangleCallback { @@ -198,4 +200,6 @@ void SuspensionCollisionGrid::UpdateDynamicCollisions(Vec minBT, Vec maxBT, bool } else { return _UpdateDynamicCollisions(*this, minBT, maxBT, remove); } -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h index 1d5b9685..6e3bae30 100644 --- a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h +++ b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h @@ -3,6 +3,8 @@ class btBvhTriangleMeshShape; +RS_NS_START + struct SuspensionCollisionGrid { GameMode gameMode; bool lightMem; @@ -96,3 +98,5 @@ struct SuspensionCollisionGrid { btRigidBody* defaultWorldCollisionRB = NULL; }; + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/btVehicleRL/btVehicleRL.cpp b/src/Sim/btVehicleRL/btVehicleRL.cpp index 7141faba..e2a8c3ce 100644 --- a/src/Sim/btVehicleRL/btVehicleRL.cpp +++ b/src/Sim/btVehicleRL/btVehicleRL.cpp @@ -7,6 +7,8 @@ #include "../../../libsrc/bullet3-3.24/BulletDynamics/Dynamics/btDynamicsWorld.h" #include "../../../libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btContactConstraint.h" +RS_NS_START + btVehicleRL::btVehicleRL(const btVehicleTuning& tuning, btRigidBody* chassis, btVehicleRaycaster* raycaster, btDynamicsWorld* world) : m_vehicleRaycaster(raycaster), m_pitchControl(0), m_dynamicsWorld(world) { m_chassisBody = chassis; @@ -411,4 +413,6 @@ btVector3 btVehicleRL::getUpwardsDirFromWheelContacts() { float btVehicleRL::getForwardSpeed() { return m_chassisBody->getLinearVelocity().dot(getForwardVector()); -} \ No newline at end of file +} + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/btVehicleRL/btVehicleRL.h b/src/Sim/btVehicleRL/btVehicleRL.h index 6e5d9181..d743d5b0 100644 --- a/src/Sim/btVehicleRL/btVehicleRL.h +++ b/src/Sim/btVehicleRL/btVehicleRL.h @@ -3,6 +3,8 @@ #include "../../../libsrc/bullet3-3.24/BulletDynamics/Vehicle/btDefaultVehicleRaycaster.h" +RS_NS_START + // This is a modified version of btWheelInfo to more accurately follow Rocket League struct btWheelInfoRL : public btWheelInfo { bool m_isInContactWithWorld = false; @@ -206,4 +208,6 @@ class btVehicleRL : public btActionInterface { // Extra utility funcs btVector3 getUpwardsDirFromWheelContacts(); float getForwardSpeed(); -}; \ No newline at end of file +}; + +RS_NS_END \ No newline at end of file From 39543aa0480fdf31aab3ebf0b324949b0cb8cb5e Mon Sep 17 00:00:00 2001 From: ZealanL Date: Fri, 26 Jan 2024 17:14:07 -0800 Subject: [PATCH 16/55] Fix partial flip cancels not scaling correctly --- src/Sim/Car/Car.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Sim/Car/Car.cpp b/src/Sim/Car/Car.cpp index 2f19943e..fe56d1ad 100644 --- a/src/Sim/Car/Car.cpp +++ b/src/Sim/Car/Car.cpp @@ -558,7 +558,12 @@ void Car::_UpdateAirTorque(float tickTime, const MutatorConfig& mutatorConfig, b float pitchScale = 1; if (relDodgeTorque.y() != 0 && controls.pitch != 0) { if (RS_SGN(relDodgeTorque.y()) == RS_SGN(controls.pitch)) { - pitchScale = 0; + +#ifndef RS_MAX_SPEED + pitchScale = 1 - RS_MIN(abs(controls.pitch), 1); // Sanity clamp +#else + pitchScale = 1 - abs(controls.pitch); // No sanity check +#endif doAirControl = true; } } From 13209d809317463b743547e9681ce0865738f07d Mon Sep 17 00:00:00 2001 From: ZealanL Date: Tue, 30 Jan 2024 22:37:31 -0800 Subject: [PATCH 17/55] Fix some boost pad loops not firing for hoops --- src/Sim/Arena/Arena.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 043dd5e5..19786a4b 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -538,7 +538,7 @@ void Arena::Serialize(DataStreamOut& out) const { } } - if (gameMode == GameMode::SOCCAR) { // Serialize boost pads + if (_boostPads.size() > 0) { // Serialize boost pads out.Write(_boostPads.size()); for (auto pad : _boostPads) pad->GetState().Serialize(out); @@ -592,7 +592,7 @@ Arena* Arena::DeserializeNew(DataStreamIn& in) { } // Deserialize boost pads - if (gameMode == GameMode::SOCCAR) { + if (newArena->_boostPads.size() > 0) { uint32_t boostPadAmount = in.Read(); #ifndef RS_MAX_SPEED @@ -947,7 +947,7 @@ Arena::~Arena() { Ball::_DestroyBall(ball); } - if (gameMode == GameMode::SOCCAR) { + if (_boostPads.size() > 0) { if (ownsBoostPads) { // Remove all boost pads for (BoostPad* boostPad : _boostPads) From ff44039ff1bb6023d10dc3d102e8b3d5387850c5 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Mon, 5 Feb 2024 03:24:42 -0800 Subject: [PATCH 18/55] Add raycast feature to allow suspension ray to ignore own car body --- .../CollisionDispatch/btCollisionWorld.cpp | 2 ++ .../CollisionDispatch/btCollisionWorld.h | 5 ++++- .../Vehicle/btDefaultVehicleRaycaster.cpp | 4 ++-- .../Vehicle/btDefaultVehicleRaycaster.h | 2 +- .../BulletDynamics/Vehicle/btVehicleRaycaster.h | 2 +- .../SuspensionCollisionGrid.cpp | 13 ++++++++----- .../SuspensionCollisionGrid.h | 2 +- src/Sim/btVehicleRL/btVehicleRL.cpp | 4 ++-- 8 files changed, 21 insertions(+), 13 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionWorld.cpp b/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionWorld.cpp index f7dc5cfe..80096a9a 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionWorld.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionWorld.cpp @@ -1208,5 +1208,7 @@ void btCollisionWorld::contactPairTest(btCollisionObject* colObjA, btCollisionOb bool btCollisionWorld::RayResultCallback::needsCollision(btBroadphaseProxy* proxy0) const { bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0 && (m_collisionFilterGroup & proxy0->m_collisionFilterMask); + if (proxy0->m_clientObject == m_ignoreObj) + return false; return collides; } \ No newline at end of file diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionWorld.h b/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionWorld.h index 874a1792..5dbd76dd 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionWorld.h +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionWorld.h @@ -177,6 +177,7 @@ class btCollisionWorld { btScalar m_closestHitFraction; const btCollisionObject* m_collisionObject; + const btCollisionObject* m_ignoreObj; int m_collisionFilterGroup; int m_collisionFilterMask; //@BP Mod - Custom flags, currently used to enable backface culling on tri-meshes, see btRaycastCallback.h. Apply any of the EFlags defined there on m_flags here to invoke. @@ -195,6 +196,7 @@ class btCollisionWorld m_collisionObject(0), m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), m_collisionFilterMask(btBroadphaseProxy::AllFilter), + m_ignoreObj(0), //@BP Mod m_flags(0) { @@ -208,10 +210,11 @@ class btCollisionWorld struct ClosestRayResultCallback : public RayResultCallback { - ClosestRayResultCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld) + ClosestRayResultCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld, const btCollisionObject* ignoreObj) : m_rayFromWorld(rayFromWorld), m_rayToWorld(rayToWorld) { + this->m_ignoreObj = ignoreObj; } btVector3 m_rayFromWorld; //used to calculate hitPointWorld from hitFraction diff --git a/libsrc/bullet3-3.24/BulletDynamics/Vehicle/btDefaultVehicleRaycaster.cpp b/libsrc/bullet3-3.24/BulletDynamics/Vehicle/btDefaultVehicleRaycaster.cpp index 59d56b57..d99c40c2 100644 --- a/libsrc/bullet3-3.24/BulletDynamics/Vehicle/btDefaultVehicleRaycaster.cpp +++ b/libsrc/bullet3-3.24/BulletDynamics/Vehicle/btDefaultVehicleRaycaster.cpp @@ -29,11 +29,11 @@ btRigidBody& btActionInterface::getFixedBody() return s_fixed; } -void* btDefaultVehicleRaycaster::castRay(const btVector3& from, const btVector3& to, btVehicleRaycasterResult& result) +void* btDefaultVehicleRaycaster::castRay(const btVector3& from, const btVector3& to, const btCollisionObject* ignoreObj, btVehicleRaycasterResult& result) { // RayResultCallback& resultCallback; - btCollisionWorld::ClosestRayResultCallback rayCallback(from, to); + btCollisionWorld::ClosestRayResultCallback rayCallback(from, to, ignoreObj); m_dynamicsWorld->rayTest(from, to, rayCallback); diff --git a/libsrc/bullet3-3.24/BulletDynamics/Vehicle/btDefaultVehicleRaycaster.h b/libsrc/bullet3-3.24/BulletDynamics/Vehicle/btDefaultVehicleRaycaster.h index f5996ce7..84dce283 100644 --- a/libsrc/bullet3-3.24/BulletDynamics/Vehicle/btDefaultVehicleRaycaster.h +++ b/libsrc/bullet3-3.24/BulletDynamics/Vehicle/btDefaultVehicleRaycaster.h @@ -31,7 +31,7 @@ class btDefaultVehicleRaycaster : public btVehicleRaycaster { } - virtual void* castRay(const btVector3& from, const btVector3& to, btVehicleRaycasterResult& result); + virtual void* castRay(const btVector3& from, const btVector3& to, const btCollisionObject* ignoreObj, btVehicleRaycasterResult& result); }; #endif //BT_RAYCASTVEHICLE_H diff --git a/libsrc/bullet3-3.24/BulletDynamics/Vehicle/btVehicleRaycaster.h b/libsrc/bullet3-3.24/BulletDynamics/Vehicle/btVehicleRaycaster.h index 218edb0a..4733d245 100644 --- a/libsrc/bullet3-3.24/BulletDynamics/Vehicle/btVehicleRaycaster.h +++ b/libsrc/bullet3-3.24/BulletDynamics/Vehicle/btVehicleRaycaster.h @@ -27,7 +27,7 @@ struct btVehicleRaycaster btScalar m_distFraction; }; - virtual void* castRay(const btVector3& from, const btVector3& to, btVehicleRaycasterResult& result) = 0; + virtual void* castRay(const btVector3& from, const btVector3& to, const btCollisionObject* ignoreObj, btVehicleRaycasterResult& result) = 0; }; #endif //BT_VEHICLE_RAYCASTER_H diff --git a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.cpp b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.cpp index e9887882..7400c494 100644 --- a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.cpp +++ b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.cpp @@ -122,11 +122,14 @@ void SuspensionCollisionGrid::SetupWorldCollision(const std::vector -btCollisionObject* _CastSuspensionRay(SuspensionCollisionGrid& grid, btVehicleRaycaster* raycaster, Vec start, Vec end, btVehicleRaycaster::btVehicleRaycasterResult& result) { +btCollisionObject* _CastSuspensionRay( + SuspensionCollisionGrid& grid, btVehicleRaycaster* raycaster, + Vec start, Vec end, const btCollisionObject* ignoreObj, btVehicleRaycaster::btVehicleRaycasterResult& result +) { SuspensionCollisionGrid::Cell& cell = grid.GetCellFromPos(start * BT_TO_UU); if (cell.worldCollision || cell.dynamicObjects > 1) { - return (btCollisionObject*)raycaster->castRay(start, end, result); + return (btCollisionObject*)raycaster->castRay(start, end, ignoreObj, result); } else { Vec delta = end - start; float dist = delta.Length(); @@ -170,11 +173,11 @@ btCollisionObject* _CastSuspensionRay(SuspensionCollisionGrid& grid, btVehicleRa } } -btCollisionObject* SuspensionCollisionGrid::CastSuspensionRay(btVehicleRaycaster* raycaster, Vec start, Vec end, btVehicleRaycaster::btVehicleRaycasterResult& result) { +btCollisionObject* SuspensionCollisionGrid::CastSuspensionRay(btVehicleRaycaster* raycaster, Vec start, Vec end, const btCollisionObject* ignoreObj, btVehicleRaycaster::btVehicleRaycasterResult& result) { if (lightMem) { - return _CastSuspensionRay(*this, raycaster, start, end, result); + return _CastSuspensionRay(*this, raycaster, start, end, ignoreObj, result); } else { - return _CastSuspensionRay(*this, raycaster, start, end, result); + return _CastSuspensionRay(*this, raycaster, start, end, ignoreObj, result); } } diff --git a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h index 6e3bae30..540a8302 100644 --- a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h +++ b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h @@ -93,7 +93,7 @@ struct SuspensionCollisionGrid { void SetupWorldCollision(const std::vector& triMeshShapes); - btCollisionObject* CastSuspensionRay(btVehicleRaycaster* raycaster, Vec start, Vec end, btVehicleRaycaster::btVehicleRaycasterResult& result); + btCollisionObject* CastSuspensionRay(btVehicleRaycaster* raycaster, Vec start, Vec end, const btCollisionObject* ignoreObj, btVehicleRaycaster::btVehicleRaycasterResult& result); void UpdateDynamicCollisions(Vec minBT, Vec maxBT, bool remove); btRigidBody* defaultWorldCollisionRB = NULL; diff --git a/src/Sim/btVehicleRL/btVehicleRL.cpp b/src/Sim/btVehicleRL/btVehicleRL.cpp index e2a8c3ce..7d690e23 100644 --- a/src/Sim/btVehicleRL/btVehicleRL.cpp +++ b/src/Sim/btVehicleRL/btVehicleRL.cpp @@ -132,9 +132,9 @@ float btVehicleRL::rayCast(btWheelInfoRL& wheel, SuspensionCollisionGrid* grid) btCollisionObject* object; if (grid) { - object = grid->CastSuspensionRay(m_vehicleRaycaster, source, target, rayResults); + object = grid->CastSuspensionRay(m_vehicleRaycaster, source, target, m_chassisBody, rayResults); } else { - object = (btCollisionObject*)m_vehicleRaycaster->castRay(source, target, rayResults); + object = (btCollisionObject*)m_vehicleRaycaster->castRay(source, target, m_chassisBody, rayResults); } if (object) { From 8a8355ac98508d701d227909f8b4a57d7262facb Mon Sep 17 00:00:00 2001 From: ZealanL Date: Mon, 5 Feb 2024 22:44:09 -0800 Subject: [PATCH 19/55] Fix suspension grid dynamic marker restoration issues with new system --- src/Sim/Arena/Arena.cpp | 12 +------ .../SuspensionCollisionGrid.cpp | 32 +++++++++++++++++-- .../SuspensionCollisionGrid.h | 13 ++++++-- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 19786a4b..f603b4e4 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -714,17 +714,7 @@ void Arena::Step(int ticksToSimulate) { if (hasArenaStuff) { #ifndef RS_NO_SUSPCOLGRID - { // Remove dynamic bodies from suspension grid - for (Car* car : _cars) { - btVector3 min, max; - car->_rigidBody.getAabb(min, max); - _suspColGrid.UpdateDynamicCollisions(min, max, true); - } - - btVector3 min, max; - ball->_rigidBody.getAabb(min, max); - _suspColGrid.UpdateDynamicCollisions(min, max, true); - } + _suspColGrid.ClearDynamicCollisions(); #endif } diff --git a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.cpp b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.cpp index 7400c494..7ab627b2 100644 --- a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.cpp +++ b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.cpp @@ -128,7 +128,8 @@ btCollisionObject* _CastSuspensionRay( ) { SuspensionCollisionGrid::Cell& cell = grid.GetCellFromPos(start * BT_TO_UU); - if (cell.worldCollision || cell.dynamicObjects > 1) { + if (cell.worldCollision || cell.dynamicCollision) { + // TODO: Do world-only or dynamic-only raycasts return (btCollisionObject*)raycaster->castRay(start, end, ignoreObj, result); } else { Vec delta = end - start; @@ -194,7 +195,14 @@ void _UpdateDynamicCollisions(SuspensionCollisionGrid& grid, Vec minBT, Vec maxB for (int i = i1; i <= i2; i++) for (int j = j1; j <= j2; j++) for (int k = k1; k <= k2; k++) - grid.Get(i, j, k).dynamicObjects += deltaVal; + grid.Get(i, j, k).dynamicCollision = true; + + grid.dynamicCellRanges.push_back( + { + i1, j1, k1, + i2, j2, k2 + } + ); } void SuspensionCollisionGrid::UpdateDynamicCollisions(Vec minBT, Vec maxBT, bool remove) { @@ -205,4 +213,24 @@ void SuspensionCollisionGrid::UpdateDynamicCollisions(Vec minBT, Vec maxBT, bool } } +template +void _ClearDynamicCollisions(SuspensionCollisionGrid& grid) { + for (auto& range : grid.dynamicCellRanges) { + for (int i = range.minX; i <= range.maxX; i++) + for (int j = range.minY; j <= range.maxY; j++) + for (int k = range.minZ; k <= range.maxZ; k++) + grid.Get(i, j, k).dynamicCollision = false; + } + + grid.dynamicCellRanges.clear(); +} + +void SuspensionCollisionGrid::ClearDynamicCollisions() { + if (lightMem) { + return _ClearDynamicCollisions(*this); + } else { + return _ClearDynamicCollisions(*this); + } +} + RS_NS_END \ No newline at end of file diff --git a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h index 540a8302..08868775 100644 --- a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h +++ b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h @@ -29,10 +29,17 @@ struct SuspensionCollisionGrid { static_assert(RS_MIN(CELL_SIZE_X[0], RS_MIN(CELL_SIZE_Y[0], CELL_SIZE_Z[0])) > 60, "SuspensionCollisionGrid cells are too small"); struct Cell { - bool worldCollision = false; - int dynamicObjects = 0; + bool + worldCollision = false, + dynamicCollision = false; }; + struct CellRange { + int minX, minY, minZ; + int maxX, maxY, maxZ; + }; + std::vector dynamicCellRanges; + struct { float extentX_bt, extentY_bt, height_bt; } cache; @@ -94,7 +101,9 @@ struct SuspensionCollisionGrid { void SetupWorldCollision(const std::vector& triMeshShapes); btCollisionObject* CastSuspensionRay(btVehicleRaycaster* raycaster, Vec start, Vec end, const btCollisionObject* ignoreObj, btVehicleRaycaster::btVehicleRaycasterResult& result); + void UpdateDynamicCollisions(Vec minBT, Vec maxBT, bool remove); + void ClearDynamicCollisions(); btRigidBody* defaultWorldCollisionRB = NULL; }; From 6fcb79617911519b15497ecfafa5cbcfd7769996 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 7 Feb 2024 14:30:53 -0800 Subject: [PATCH 20/55] Add helpful comment for BallPredTracker constructor --- src/Sim/BallPredTracker/BallPredTracker.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Sim/BallPredTracker/BallPredTracker.h b/src/Sim/BallPredTracker/BallPredTracker.h index 95324e86..20e9d2ec 100644 --- a/src/Sim/BallPredTracker/BallPredTracker.h +++ b/src/Sim/BallPredTracker/BallPredTracker.h @@ -9,6 +9,8 @@ struct BallPredTracker { std::vector predData; size_t numPredTicks; + // arena: The arena you want to predict the ball for (BallPredTracker will make a copy of it without the cars) + // You do not need to make another arena for BallPredTracker, it does that itself BallPredTracker(Arena* arena, size_t numPredTicks); ~BallPredTracker(); From 5c27db0b3ee10bf7c41909c6172675e255fe64c0 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 7 Feb 2024 14:50:26 -0800 Subject: [PATCH 21/55] Improve fatal error formatting and clarity --- src/Framework.h | 9 +++++++-- src/RocketSim.cpp | 13 ++++++++----- src/RocketSim.h | 3 +++ src/Sim/Arena/Arena.cpp | 11 +++++++---- src/Sim/MutatorConfig/MutatorConfig.cpp | 2 +- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/Framework.h b/src/Framework.h index 4591563d..fdd8d1af 100644 --- a/src/Framework.h +++ b/src/Framework.h @@ -57,9 +57,14 @@ typedef uint8_t byte; // Returns sign of number (1 if positive, -1 if negative, and 0 if 0) #define RS_SGN(val) ((val > 0) - (val < 0)) -#define RS_WARN(s) RS_LOG("WARNING: " << s) +#define RS_WARN(s) RS_LOG("ROCKETSIM WARNING: " << s) -#define RS_ERR_CLOSE(s) { std::string _errorStr = RS_STR("FATAL ERROR: " << s); RS_LOG(_errorStr); throw std::runtime_error(_errorStr); exit(EXIT_FAILURE); } +#define RS_ERR_CLOSE(s) { \ + std::string _errorStr = RS_STR("ROCKETSIM FATAL ERROR: " << s); \ + RS_LOG(_errorStr); \ + throw std::runtime_error(_errorStr); \ + exit(EXIT_FAILURE); \ +} #if 0 // FOR FUTURE USE: Exports/imports setup #ifdef ROCKETSIM_EXPORTS diff --git a/src/RocketSim.cpp b/src/RocketSim.cpp index af4d23cb..55d150f9 100644 --- a/src/RocketSim.cpp +++ b/src/RocketSim.cpp @@ -6,6 +6,9 @@ using namespace RocketSim; +std::filesystem::path RocketSim::_collisionMeshesFolder = {}; +std::mutex RocketSim::_beginInitMutex = {}; + struct MeshHashSet { std::unordered_map hashes; void AddAll(std::initializer_list hashesToAdd) { @@ -38,7 +41,6 @@ struct MeshHashSet { return hashes[hash]; } }; -static std::mutex beginInitMutex; static RocketSimStage stage = RocketSimStage::UNINITIALIZED; RocketSimStage RocketSim::GetStage() { @@ -69,16 +71,17 @@ void RocketSim::Init(std::filesystem::path collisionMeshesFolder) { constexpr char MSG_PREFIX[] = "RocketSim::Init(): "; - beginInitMutex.lock(); + _beginInitMutex.lock(); { if (stage != RocketSimStage::UNINITIALIZED) { RS_WARN("RocketSim::Init() called again after already initialized, ignoring..."); - beginInitMutex.unlock(); + _beginInitMutex.unlock(); return; } RS_LOG("Initializing RocketSim version " RS_VERSION ", created by ZealanL..."); + _collisionMeshesFolder = collisionMeshesFolder; stage = RocketSimStage::INITIALIZING; uint64_t startMS = RS_CUR_MS(); @@ -159,11 +162,11 @@ void RocketSim::Init(std::filesystem::path collisionMeshesFolder) { stage = RocketSimStage::INITIALIZED; } - beginInitMutex.unlock(); + _beginInitMutex.unlock(); } void RocketSim::AssertInitialized(const char* errorMsgPrefix) { if (stage != RocketSimStage::INITIALIZED) { - RS_ERR_CLOSE(errorMsgPrefix << "RocketSim has not been initialized, call RocketSim::Init() first.") + RS_ERR_CLOSE(errorMsgPrefix << "RocketSim has not been initialized, call RocketSim::Init() first") } } \ No newline at end of file diff --git a/src/RocketSim.h b/src/RocketSim.h index 8d8f4b24..f3c59f66 100644 --- a/src/RocketSim.h +++ b/src/RocketSim.h @@ -19,6 +19,9 @@ namespace RocketSim { INITIALIZED }; + extern std::filesystem::path _collisionMeshesFolder; + extern std::mutex _beginInitMutex; + void Init(std::filesystem::path collisionMeshesFolder); void AssertInitialized(const char* errorMsgPrefix); diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index f603b4e4..7d4c9815 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -93,7 +93,7 @@ Car* Arena::GetCar(uint32_t id) { void Arena::SetGoalScoreCallback(GoalScoreEventFn callbackFunc, void* userInfo) { if (gameMode == GameMode::THE_VOID) - RS_ERR_CLOSE("Cannot set a goal score callback when on THE_VOID gamemode!"); + RS_ERR_CLOSE("Cannot set a goal score callback when on THE_VOID gamemode"); _goalScoreCallback.func = callbackFunc; _goalScoreCallback.userInfo = userInfo; @@ -577,7 +577,7 @@ Arena* Arena::DeserializeNew(DataStreamIn& in) { #ifndef RS_MAX_SPEED if (newArena->_carIDMap.count(id)) - RS_ERR_CLOSE(ERROR_PREFIX << "Failed to load, got repeated car ID of " << id << "."); + RS_ERR_CLOSE(ERROR_PREFIX << "Failed to load, got repeated car ID of " << id); #endif Car* newCar = newArena->DeserializeNewCar(in, team); @@ -882,7 +882,7 @@ bool Arena::IsBallProbablyGoingIn(float maxTime, float extraMargin, Team* goalTe } } else { - RS_ERR_CLOSE("Arena::IsBallProbablyGoingIn() is not supported for: " << GAMEMODE_STRS[(int)gameMode]); + RS_ERR_CLOSE("Arena::IsBallProbablyGoingIn() is not supported for gamemode " << GAMEMODE_STRS[(int)gameMode]); return false; } } @@ -960,7 +960,10 @@ void Arena::_SetupArenaCollisionShapes() { auto collisionMeshes = RocketSim::GetArenaCollisionShapes(gameMode); if (collisionMeshes.empty()) { - RS_ERR_CLOSE("Failed to setup arena collision meshes, no meshes found for game mode") + RS_ERR_CLOSE( + "No arena meshes found for gamemode " << GAMEMODE_STRS[(int)gameMode] << ", " << + "the mesh files should be in " << RocketSim::_collisionMeshesFolder + ) } _worldCollisionBvhShapes = new btBvhTriangleMeshShape[collisionMeshes.size()]; diff --git a/src/Sim/MutatorConfig/MutatorConfig.cpp b/src/Sim/MutatorConfig/MutatorConfig.cpp index 70d386c9..799435c2 100644 --- a/src/Sim/MutatorConfig/MutatorConfig.cpp +++ b/src/Sim/MutatorConfig/MutatorConfig.cpp @@ -36,7 +36,7 @@ void MutatorConfig::Deserialize(DataStreamIn& in) { uint16_t argCount = in.Read(); if (argCount != RS_GET_ARGUMENT_COUNT(MUTATOR_CONFIG_SERIALIZATION_FIELDS)) { - RS_ERR_CLOSE(" MutatorConfig::Deserialize(): Mutator config is from a different version of RocketSim, fields don't match!"); + RS_ERR_CLOSE(" MutatorConfig::Deserialize(): Mutator config is from a different version of RocketSim, fields don't match"); } in.ReadMultiple(MUTATOR_CONFIG_SERIALIZATION_FIELDS); From 1f7e07b71f5b4beee81cff714818dad93b1d409c Mon Sep 17 00:00:00 2001 From: ZealanL Date: Fri, 9 Feb 2024 02:37:21 -0800 Subject: [PATCH 22/55] Rename CarState.lastRelDodgeTorque to CarState.flipRelTorque --- src/Sim/Car/Car.cpp | 6 +++--- src/Sim/Car/Car.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Sim/Car/Car.cpp b/src/Sim/Car/Car.cpp index fe56d1ad..d68914b3 100644 --- a/src/Sim/Car/Car.cpp +++ b/src/Sim/Car/Car.cpp @@ -551,9 +551,9 @@ void Car::_UpdateAirTorque(float tickTime, const MutatorConfig& mutatorConfig, b if (_internalState.isFlipping) { - btVector3 relDodgeTorque = _internalState.lastRelDodgeTorque; + btVector3 relDodgeTorque = _internalState.flipRelTorque; - if (!_internalState.lastRelDodgeTorque.IsZero()) { + if (!_internalState.flipRelTorque.IsZero()) { // Flip cancel check float pitchScale = 1; if (relDodgeTorque.y() != 0 && controls.pitch != 0) { @@ -674,7 +674,7 @@ void Car::_UpdateDoubleJumpOrFlip(float tickTime, const MutatorConfig& mutatorCo dodgeDir = dodgeDir.safeNormalized(); } - _internalState.lastRelDodgeTorque = btVector3(-dodgeDir.y(), dodgeDir.x(), 0); + _internalState.flipRelTorque = btVector3(-dodgeDir.y(), dodgeDir.x(), 0); if (abs(dodgeDir.x()) < 0.1f) dodgeDir.x() = 0; if (abs(dodgeDir.y()) < 0.1f) dodgeDir.y() = 0; diff --git a/src/Sim/Car/Car.h b/src/Sim/Car/Car.h index 536373d9..b1ea3a08 100644 --- a/src/Sim/Car/Car.h +++ b/src/Sim/Car/Car.h @@ -33,7 +33,7 @@ struct CarState { bool isOnGround = true; bool hasJumped = false, hasDoubleJumped = false, hasFlipped = false; - Vec lastRelDodgeTorque = { 0, 0, 0 }; + Vec flipRelTorque = { 0, 0, 0 }; // Active during the duration of a jump or flip float jumpTime = 0, flipTime = 0; @@ -90,7 +90,7 @@ struct CarState { #define CARSTATE_SERIALIZATION_FIELDS \ pos, rotMat, vel, angVel, isOnGround, hasJumped, hasDoubleJumped, hasFlipped, \ -lastRelDodgeTorque, jumpTime, isFlipping, flipTime, isJumping, airTimeSinceJump, \ +flipRelTorque, jumpTime, isFlipping, flipTime, isJumping, airTimeSinceJump, \ boost, timeSpentBoosting, supersonicTime, handbrakeVal, isAutoFlipping, \ autoFlipTimer, autoFlipTorqueScale, isDemoed, demoRespawnTimer, lastControls, \ worldContact.hasContact, worldContact.contactNormal, \ From e0375e605fca31fdb4e5308b5e50cb7c53f01dd7 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Sat, 17 Feb 2024 18:25:40 -0800 Subject: [PATCH 23/55] Fix double namespace error for some compiles with CarConfig constants --- src/Sim/Car/CarConfig/CarConfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Sim/Car/CarConfig/CarConfig.cpp b/src/Sim/Car/CarConfig/CarConfig.cpp index 9742d2b5..b46f5ff4 100644 --- a/src/Sim/Car/CarConfig/CarConfig.cpp +++ b/src/Sim/Car/CarConfig/CarConfig.cpp @@ -71,7 +71,7 @@ const static Vec BACK_WHEELS_OFFSET[6] = { // Using a macro here for convenience #define MAKE_CAR_CONFIG(name, index) \ - const CarConfig RocketSim::CAR_CONFIG_##name = { \ + const CarConfig CAR_CONFIG_##name = { \ HITBOX_SIZES[index], \ HITBOX_OFFSETS[index], \ { FRONT_WHEEL_RADS[index], FRONT_WHEEL_SUS_REST[index], FRONT_WHEELS_OFFSET[index] }, \ From da5b143fb4448f6904e472905361422d6f082b0a Mon Sep 17 00:00:00 2001 From: ZealanL Date: Sat, 24 Feb 2024 09:46:42 -0800 Subject: [PATCH 24/55] Delete .gitmodules --- .gitmodules | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 9b655d9c..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "python/pybind11"] - path = python/pybind11 - url = https://github.com/pybind/pybind11.git From 3553bf9ef004ad42455e1bd5c39a221288917256 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Fri, 22 Mar 2024 18:44:59 -0700 Subject: [PATCH 25/55] Fix GameEventTracker calling null callbacks --- src/Sim/GameEventTracker/GameEventTracker.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Sim/GameEventTracker/GameEventTracker.cpp b/src/Sim/GameEventTracker/GameEventTracker.cpp index 0dae55bc..7629c2c7 100644 --- a/src/Sim/GameEventTracker/GameEventTracker.cpp +++ b/src/Sim/GameEventTracker/GameEventTracker.cpp @@ -60,7 +60,7 @@ void GameEventTracker::Update(Arena* arena) { float deltaTime = deltaTicks * arena->tickTime; // Goal event - if (scored && _goalCallback.func && !_ballScoredLast) { + if (scored && !_ballScoredLast) { Car* shooter; Car* passer; if (GetShooterPasser( @@ -71,7 +71,8 @@ void GameEventTracker::Update(Arena* arena) { config.passMaxTouchTime * tickrate )) { - _goalCallback.func(arena, shooter, passer, _goalCallback.userInfo); + if (_goalCallback.func) + _goalCallback.func(arena, shooter, passer, _goalCallback.userInfo); } } else { if (!_ballShot) { // Ball is not currently shot @@ -106,7 +107,8 @@ void GameEventTracker::Update(Arena* arena) { _ballShot = true; _ballShotGoalTeam = goalTeam; _shotCooldown = config.shotEventCooldown; - _shotCallback.func(arena, shooter, passer, _shotCallback.userInfo); + if (_shotCallback.func) + _shotCallback.func(arena, shooter, passer, _shotCallback.userInfo); } } } @@ -132,7 +134,8 @@ void GameEventTracker::Update(Arena* arena) { // A car from the team the ball has just hit the ball // Since it's no longer scoring, this was a save - _saveCallback.func(arena, saver, _saveCallback.userInfo); + if (_saveCallback.func) + _saveCallback.func(arena, saver, _saveCallback.userInfo); } else { // It just stopped going in (probably missed) } From 1a2f9e4bc7634095076d4a4edae8ba1f461bcca2 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Sat, 23 Mar 2024 15:02:01 -0700 Subject: [PATCH 26/55] Add new CarState data: wheelsWithContact --- src/Sim/Car/Car.cpp | 8 ++++++-- src/Sim/Car/Car.h | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Sim/Car/Car.cpp b/src/Sim/Car/Car.cpp index d68914b3..f06bd147 100644 --- a/src/Sim/Car/Car.cpp +++ b/src/Sim/Car/Car.cpp @@ -131,9 +131,13 @@ void Car::_PostTickUpdate(GameMode gameMode, float tickTime, const MutatorConfig _internalState.rotMat = _rigidBody.m_worldTransform.m_basis; + // Update wheelsWithContact int numWheelsInContact = 0; - for (int i = 0; i < 4; i++) - numWheelsInContact += _bulletVehicle.m_wheelInfo[i].m_raycastInfo.m_isInContact; + for (int i = 0; i < 4; i++) { + bool inContact = _bulletVehicle.m_wheelInfo[i].m_raycastInfo.m_isInContact; + _internalState.wheelsWithContact[i] = inContact; + numWheelsInContact += inContact; + } { // Update isOnGround _internalState.isOnGround = numWheelsInContact >= 3; diff --git a/src/Sim/Car/Car.h b/src/Sim/Car/Car.h index b1ea3a08..755a4f72 100644 --- a/src/Sim/Car/Car.h +++ b/src/Sim/Car/Car.h @@ -32,6 +32,11 @@ struct CarState { Vec angVel = { 0, 0, 0 }; bool isOnGround = true; + + // Whether each of the 4 wheels have contact + // First two are front + bool wheelsWithContact[4] = {}; + bool hasJumped = false, hasDoubleJumped = false, hasFlipped = false; Vec flipRelTorque = { 0, 0, 0 }; From df624dc91368970ecd09590bafcfba8660088763 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Sat, 23 Mar 2024 15:16:15 -0700 Subject: [PATCH 27/55] Fix many annoying warnings --- src/Framework.h | 5 +++++ src/Math/MathTypes/MathTypes.h | 6 +++--- src/RLConst.h | 8 ++++---- src/Sim/Arena/Arena.cpp | 4 ++-- src/Sim/Ball/Ball.h | 2 +- src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.h | 4 ++-- src/Sim/Car/Car.cpp | 2 +- src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h | 6 +++--- src/Sim/btVehicleRL/btVehicleRL.cpp | 2 -- 9 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/Framework.h b/src/Framework.h index fdd8d1af..05ba07ce 100644 --- a/src/Framework.h +++ b/src/Framework.h @@ -34,6 +34,11 @@ #include #include +#ifdef _MSC_VER +// Disable annoying truncation warnings on MSVC +#pragma warning(disable: 4305 4244 4267) +#endif + typedef uint8_t byte; // Current millisecond time diff --git a/src/Math/MathTypes/MathTypes.h b/src/Math/MathTypes/MathTypes.h index 2ed07301..b77dcc30 100644 --- a/src/Math/MathTypes/MathTypes.h +++ b/src/Math/MathTypes/MathTypes.h @@ -233,9 +233,9 @@ struct RS_ALIGN_16 RotMat { RotMat Dot(const RotMat& other) const { RotMat result; - for (size_t i = 0; i < 3; i++) - for (size_t j = 0; j < 3; j++) - for (size_t k = 0; k < 3; k++) + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 3; k++) result[i][j] += (*this)[i][j] * other[k][j]; return result; diff --git a/src/RLConst.h b/src/RLConst.h index e152495e..162cba35 100644 --- a/src/RLConst.h +++ b/src/RLConst.h @@ -103,13 +103,13 @@ namespace RLConst { FLIP_BACKWARD_IMPULSE_SCALE_X = 16.f / 15.f, BALL_COLLISION_RADIUS_SOCCAR = 91.25f, - BALL_COLLISION_RADIUS_HOOPS = 96.38307f, - BALL_COLLISION_RADIUS_DROPSHOT = 100.2565, + BALL_COLLISION_RADIUS_HOOPS = 96.3831f, + BALL_COLLISION_RADIUS_DROPSHOT = 100.2565f, SOCCAR_GOAL_SCORE_BASE_THRESHOLD_Y = 5124.25f, HOOPS_GOAL_SCORE_THRESHOLD_Z = 270.f, - CAR_TORQUE_SCALE = 0.09587, + CAR_TORQUE_SCALE = 0.09587f, CAR_AUTOFLIP_IMPULSE = 200, CAR_AUTOFLIP_TORQUE = 50, @@ -274,7 +274,7 @@ namespace RLConst { {-2176, -2944, 72 }, {-2432, 0, 72 }, { 2432, 0, 72 }, - { 2175.99, 2944, 72 } + { 2175.99f, 2944, 72 } }; } diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 7d4c9815..c18c9633 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -453,7 +453,7 @@ Arena::Arena(GameMode gameMode, ArenaMemWeightMode memWeightMode, float tickRate // Adjust solver configuration to be closer to older Bullet (Rocket League's Bullet is from somewhere between 2013 and 2015) auto& solverInfo = _bulletWorld.getSolverInfo(); - solverInfo.m_splitImpulsePenetrationThreshold = 1.0e30; + solverInfo.m_splitImpulsePenetrationThreshold = 1.0e30f; solverInfo.m_erp2 = 0.8f; } @@ -569,7 +569,7 @@ Arena* Arena::DeserializeNew(DataStreamIn& in) { { // Deserialize cars uint32_t carAmount = in.Read(); - for (int i = 0; i < carAmount; i++) { + for (uint32_t i = 0; i < carAmount; i++) { Team team; uint32_t id; in.Read(team); diff --git a/src/Sim/Ball/Ball.h b/src/Sim/Ball/Ball.h index 3e5c068b..2ec1702a 100644 --- a/src/Sim/Ball/Ball.h +++ b/src/Sim/Ball/Ball.h @@ -85,7 +85,7 @@ class Ball { } void _PreTickUpdate(GameMode gameMode, float tickTime); - void _OnHit(GameMode gameMode, struct Car* car); + void _OnHit(GameMode gameMode, class Car* car); void _OnWorldCollision(GameMode gameMode, Vec normal, float tickTime); Ball(const Ball& other) = delete; diff --git a/src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.h b/src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.h index a41ecbee..a0f0730e 100644 --- a/src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.h +++ b/src/Sim/BoostPad/BoostPadGrid/BoostPadGrid.h @@ -15,8 +15,8 @@ struct BoostPadGrid { constexpr static int CELLS_X = 8, CELLS_Y = 10, - CELL_SIZE_X = EXTENT_X / (CELLS_X / 2), - CELL_SIZE_Y = EXTENT_Y / (CELLS_Y / 2), + CELL_SIZE_X = (int)(EXTENT_X / (CELLS_X / 2)), + CELL_SIZE_Y = (int)(EXTENT_Y / (CELLS_Y / 2)), CELL_AMOUNT = CELLS_X * CELLS_Y; BoostPad* pads[CELLS_X][CELLS_Y] = {}; diff --git a/src/Sim/Car/Car.cpp b/src/Sim/Car/Car.cpp index f06bd147..b8513a56 100644 --- a/src/Sim/Car/Car.cpp +++ b/src/Sim/Car/Car.cpp @@ -348,7 +348,7 @@ void Car::_UpdateWheels(float tickTime, const MutatorConfig& mutatorConfig, int float engineThrottle = realThrottle; - if (controls.handbrake > 0) { + if (controls.handbrake) { // Real throttle is unchanged from the input throttle when powersliding } else { float absThrottle = abs(realThrottle); diff --git a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h index 08868775..4922460a 100644 --- a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h +++ b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h @@ -81,9 +81,9 @@ struct SuspensionCollisionGrid { template void GetCellIndicesFromPos(Vec pos, int& i, int& j, int& k) const { - i = RS_CLAMP(pos.x / CELL_SIZE_X[LIGHT] + (CELL_AMOUNT_X[LIGHT] / 2), 0, CELL_AMOUNT_X[LIGHT] - 1), - j = RS_CLAMP(pos.y / CELL_SIZE_Y[LIGHT] + (CELL_AMOUNT_Y[LIGHT] / 2), 0, CELL_AMOUNT_Y[LIGHT] - 1), - k = RS_CLAMP(pos.z / CELL_SIZE_Z[LIGHT], 0, CELL_AMOUNT_Z[LIGHT] - 1); + i = (int)RS_CLAMP(pos.x / CELL_SIZE_X[LIGHT] + (CELL_AMOUNT_X[LIGHT] / 2), 0, CELL_AMOUNT_X[LIGHT] - 1), + j = (int)RS_CLAMP(pos.y / CELL_SIZE_Y[LIGHT] + (CELL_AMOUNT_Y[LIGHT] / 2), 0, CELL_AMOUNT_Y[LIGHT] - 1), + k = (int)RS_CLAMP(pos.z / CELL_SIZE_Z[LIGHT], 0, CELL_AMOUNT_Z[LIGHT] - 1); } template diff --git a/src/Sim/btVehicleRL/btVehicleRL.cpp b/src/Sim/btVehicleRL/btVehicleRL.cpp index 7d690e23..67bdbcea 100644 --- a/src/Sim/btVehicleRL/btVehicleRL.cpp +++ b/src/Sim/btVehicleRL/btVehicleRL.cpp @@ -270,8 +270,6 @@ void btVehicleRL::setBrake(float brake, int wheelIndex) { } void btVehicleRL::updateSuspension(float deltaTime) { - float chassisMass = 1 / m_chassisBody->getInvMass(); - for (int i = 0; i < getNumWheels(); i++) { btWheelInfoRL& wheel_info = m_wheelInfo[i]; From 91a7db533313ba05ec3844036ff5c9b06bce68b7 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Sat, 23 Mar 2024 15:28:37 -0700 Subject: [PATCH 28/55] Add note reference number comments for btVehicleRL functions --- src/Sim/btVehicleRL/btVehicleRL.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Sim/btVehicleRL/btVehicleRL.cpp b/src/Sim/btVehicleRL/btVehicleRL.cpp index 67bdbcea..065abb6a 100644 --- a/src/Sim/btVehicleRL/btVehicleRL.cpp +++ b/src/Sim/btVehicleRL/btVehicleRL.cpp @@ -60,6 +60,7 @@ const btTransform& btVehicleRL::getWheelTransformWS(int wheelIndex) const { return wheel.m_worldTransform; } +// See: I20 or I21 void btVehicleRL::updateWheelTransform(int wheelIndex) { btWheelInfoRL& wheel = m_wheelInfo[wheelIndex]; updateWheelTransformsWS(wheel); @@ -103,6 +104,7 @@ void btVehicleRL::resetSuspension() { } } +// See: I20 or I21 void btVehicleRL::updateWheelTransformsWS(btWheelInfoRL& wheel) { wheel.m_raycastInfo.m_isInContact = false; wheel.m_isInContactWithWorld = false; @@ -121,15 +123,16 @@ float btVehicleRL::rayCast(btWheelInfoRL& wheel, SuspensionCollisionGrid* grid) float suspensionTravel = wheel.m_maxSuspensionTravelCm / 100; float realRayLength = wheel.getSuspensionRestLength() + suspensionTravel + wheel.m_wheelsRadius - RLConst::BTVehicle::SUSPENSION_SUBTRACTION; + // See: I21 btVector3 source = wheel.m_raycastInfo.m_hardPointWS; btVector3 target = source + (wheel.m_raycastInfo.m_wheelDirectionWS * realRayLength); wheel.m_raycastInfo.m_contactPointWS = target; wheel.m_raycastInfo.m_groundObject = NULL; + // See: I22 btVehicleRaycaster::btVehicleRaycasterResult rayResults; - + btAssert(m_vehicleRaycaster); - btCollisionObject* object; if (grid) { object = grid->CastSuspensionRay(m_vehicleRaycaster, source, target, m_chassisBody, rayResults); @@ -137,6 +140,7 @@ float btVehicleRL::rayCast(btWheelInfoRL& wheel, SuspensionCollisionGrid* grid) object = (btCollisionObject*)m_vehicleRaycaster->castRay(source, target, m_chassisBody, rayResults); } + // See: I23 if (object) { wheel.m_raycastInfo.m_contactPointWS = rayResults.m_hitPointInWorld; float fraction = rayResults.m_distFraction; @@ -269,7 +273,9 @@ void btVehicleRL::setBrake(float brake, int wheelIndex) { getWheelInfo(wheelIndex).m_brake = brake; } +// See: I24 void btVehicleRL::updateSuspension(float deltaTime) { + for (int i = 0; i < getNumWheels(); i++) { btWheelInfoRL& wheel_info = m_wheelInfo[i]; @@ -293,7 +299,6 @@ void btVehicleRL::updateSuspension(float deltaTime) { } for (int i = 0; i < getNumWheels(); i++) { - //apply suspension force btWheelInfoRL& wheel = m_wheelInfo[i]; if (wheel.m_wheelsSuspensionForce != 0) { btVector3 contactPointOffset = wheel.m_raycastInfo.m_contactPointWS - getRigidBody()->getCenterOfMassPosition(); @@ -304,6 +309,7 @@ void btVehicleRL::updateSuspension(float deltaTime) { } } +// See: I25 void btVehicleRL::calcFrictionImpulses(float timeStep) { float frictionScale = m_chassisBody->getMass() / 3; @@ -380,6 +386,7 @@ void btVehicleRL::calcFrictionImpulses(float timeStep) { } } +// See: I25 void btVehicleRL::applyFrictionImpulses(float timeStep) { // Apply impulses btVector3 upDir = m_chassisBody->getWorldTransform().getBasis().getColumn(m_indexUpAxis); From 85abbd45f0a04eef3ff4399c77054a699b889c86 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Sun, 31 Mar 2024 13:37:08 -0700 Subject: [PATCH 29/55] Make CarState and BallState extent new PhysState type --- src/Sim/Ball/Ball.h | 19 ++++++------------- src/Sim/Car/Car.h | 18 ++++++------------ src/Sim/PhysState/PhysState.cpp | 1 + src/Sim/PhysState/PhysState.h | 20 ++++++++++++++++++++ 4 files changed, 33 insertions(+), 25 deletions(-) create mode 100644 src/Sim/PhysState/PhysState.cpp create mode 100644 src/Sim/PhysState/PhysState.h diff --git a/src/Sim/Ball/Ball.h b/src/Sim/Ball/Ball.h index 2ec1702a..a0fadc5b 100644 --- a/src/Sim/Ball/Ball.h +++ b/src/Sim/Ball/Ball.h @@ -1,5 +1,5 @@ #pragma once -#include "../../BaseInc.h" +#include "../PhysState/PhysState.h" #include "../../RLConst.h" #include "../../DataStream/DataStreamIn.h" @@ -14,23 +14,12 @@ class btDynamicsWorld; RS_NS_START -struct BallState { +struct BallState : public PhysState { // Incremented every update, reset when SetState() is called // Used for telling if a stateset occured // Not serialized uint64_t updateCounter = 0; - // Position in world space - Vec pos = { 0, 0, RLConst::BALL_REST_Z }; - - RotMat rotMat = RotMat::GetIdentity(); - - // Linear velocity - Vec vel = { 0, 0, 0 }; - - // Angular velocity (axis-angle) - Vec angVel = { 0, 0, 0 }; - struct HeatseekerInfo { // Which net the ball should seek towards // When 0, no net @@ -42,6 +31,10 @@ struct BallState { HeatseekerInfo hsInfo; + BallState() : PhysState() { + pos.z = RLConst::BALL_REST_Z; + } + bool Matches(const BallState& other, float marginPos = 0.8, float marginVel = 0.4, float marginAngVel = 0.02) const; void Serialize(DataStreamOut& out); diff --git a/src/Sim/Car/Car.h b/src/Sim/Car/Car.h index 755a4f72..db822a63 100644 --- a/src/Sim/Car/Car.h +++ b/src/Sim/Car/Car.h @@ -1,4 +1,5 @@ #pragma once +#include "../PhysState/PhysState.h" #include "CarConfig/CarConfig.h" #include "../btVehicleRL/btVehicleRL.h" #include "../CarControls.h" @@ -13,24 +14,13 @@ RS_NS_START -struct CarState { +struct CarState : public PhysState { // Incremented every update, reset when SetState() is called // Used for telling if a stateset occured // Not serialized uint64_t updateCounter = 0; - // Position in world space (UU) - Vec pos = { 0, 0, 17 }; - - RotMat rotMat = RotMat::GetIdentity(); - - // Linear velocity - Vec vel = { 0, 0, 0 }; - - // Angular velocity (rad/s) - Vec angVel = { 0, 0, 0 }; - bool isOnGround = true; // Whether each of the 4 wheels have contact @@ -89,6 +79,10 @@ struct CarState { // Controls from last tick, set to this->controls after simulation CarControls lastControls = CarControls(); + CarState() : PhysState() { + pos.z = RLConst::CAR_SPAWN_REST_Z; + } + void Serialize(DataStreamOut& out) const; void Deserialize(DataStreamIn& in); }; diff --git a/src/Sim/PhysState/PhysState.cpp b/src/Sim/PhysState/PhysState.cpp new file mode 100644 index 00000000..055efcd4 --- /dev/null +++ b/src/Sim/PhysState/PhysState.cpp @@ -0,0 +1 @@ +#include "PhysState.h" diff --git a/src/Sim/PhysState/PhysState.h b/src/Sim/PhysState/PhysState.h new file mode 100644 index 00000000..8e537e00 --- /dev/null +++ b/src/Sim/PhysState/PhysState.h @@ -0,0 +1,20 @@ +#pragma once +#include "../../BaseInc.h" + +RS_NS_START + +struct PhysState { + // Position in world space (UU) + Vec pos = {}; + + // Rotation matrix (column-major) + RotMat rotMat = RotMat::GetIdentity(); + + // Linear velocity + Vec vel = {}; + + // Angular velocity (rad/s) + Vec angVel = {}; +}; + +RS_NS_END \ No newline at end of file From 83275a77dd75ae4dfe452063ca94d65978f99d40 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Sun, 31 Mar 2024 13:44:12 -0700 Subject: [PATCH 30/55] Add PhysState.GetInvertedY() --- src/Sim/PhysState/PhysState.cpp | 17 +++++++++++++++++ src/Sim/PhysState/PhysState.h | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/src/Sim/PhysState/PhysState.cpp b/src/Sim/PhysState/PhysState.cpp index 055efcd4..784d0677 100644 --- a/src/Sim/PhysState/PhysState.cpp +++ b/src/Sim/PhysState/PhysState.cpp @@ -1 +1,18 @@ #include "PhysState.h" + +RS_NS_START + +PhysState PhysState::GetInvertedY() const { + constexpr Vec INVERT_SCALE = Vec(-1, -1, 1); + + PhysState inverted = *this; + inverted.pos *= INVERT_SCALE; + for (int i = 0; i < 3; i++) + rotMat[i] *= INVERT_SCALE; + inverted.vel *= INVERT_SCALE; + inverted.angVel *= INVERT_SCALE; + + return inverted; +} + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/PhysState/PhysState.h b/src/Sim/PhysState/PhysState.h index 8e537e00..e565205e 100644 --- a/src/Sim/PhysState/PhysState.h +++ b/src/Sim/PhysState/PhysState.h @@ -15,6 +15,10 @@ struct PhysState { // Angular velocity (rad/s) Vec angVel = {}; + + // Gets a copy of this state rotated 180 degrees around Z axis + // This is achieved by multiplying all vectors by (-1, -1, 1) + PhysState GetInvertedY() const; }; RS_NS_END \ No newline at end of file From ca8554ab1b0cbacdf6a28f6f948f5a3678055a16 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Sun, 31 Mar 2024 13:48:54 -0700 Subject: [PATCH 31/55] Add CarState.HasFlipOrJump() --- src/Sim/Car/Car.cpp | 6 ++++++ src/Sim/Car/Car.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/Sim/Car/Car.cpp b/src/Sim/Car/Car.cpp index b8513a56..0158fabb 100644 --- a/src/Sim/Car/Car.cpp +++ b/src/Sim/Car/Car.cpp @@ -288,6 +288,12 @@ void Car::_BulletSetup(GameMode gameMode, btDynamicsWorld* bulletWorld, const Mu _internalState.boost = mutatorConfig.carSpawnBoostAmount; } +bool CarState::HasFlipOrJump() const { + return + isOnGround || + (!hasFlipped && !hasDoubleJumped && airTimeSinceJump < RLConst::DOUBLEJUMP_MAX_DELAY); +} + void CarState::Serialize(DataStreamOut& out) const { ballHitInfo.Serialize(out); diff --git a/src/Sim/Car/Car.h b/src/Sim/Car/Car.h index db822a63..67265750 100644 --- a/src/Sim/Car/Car.h +++ b/src/Sim/Car/Car.h @@ -83,6 +83,9 @@ struct CarState : public PhysState { pos.z = RLConst::CAR_SPAWN_REST_Z; } + // Returns true if the car is currently able to jump, double-jump, or start a flip + bool HasFlipOrJump() const; + void Serialize(DataStreamOut& out) const; void Deserialize(DataStreamIn& in); }; From 7f2f90a882668b8fc0bcb6cf89c5c4cc24202e9c Mon Sep 17 00:00:00 2001 From: ZealanL Date: Fri, 26 Apr 2024 19:45:53 -0700 Subject: [PATCH 32/55] Add Vec.To2D(), Vec.LengthSq2D(), and Vec.Length2D() --- src/Math/MathTypes/MathTypes.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Math/MathTypes/MathTypes.h b/src/Math/MathTypes/MathTypes.h index b77dcc30..231850a2 100644 --- a/src/Math/MathTypes/MathTypes.h +++ b/src/Math/MathTypes/MathTypes.h @@ -23,6 +23,11 @@ struct RS_ALIGN_16 Vec { return (x == 0 && y == 0 && z == 0 && _w == 0); } + // Makes a copy with zeroed z + Vec To2D() const { + return Vec(x, y, 0); + } + float LengthSq() const { return (x * x + y * y + z * z + _w * _w); } @@ -36,6 +41,19 @@ struct RS_ALIGN_16 Vec { } } + float LengthSq2D() const { + return (x * x + y * y); + } + + float Length2D() const { + float lengthSq2D = LengthSq2D(); + if (lengthSq2D > 0) { + return sqrtf(lengthSq2D); + } else { + return 0; + } + } + float Dot(const Vec& other) const { return (x * other.x + y * other.y + z * other.z + _w * other._w); } From 150e3a2c03a0534d1dcb3872c7503dbc764a6630 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Tue, 30 Apr 2024 12:30:06 -0700 Subject: [PATCH 33/55] Fix contact callbacks occurring on objects without collision --- src/Sim/Arena/Arena.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index c18c9633..9b2e5039 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -212,6 +212,9 @@ bool Arena::_BulletContactAddedCallback( bodyA = objA->m_collisionObject, bodyB = objB->m_collisionObject; + if (!objA->m_collisionObject->hasContactResponse() || !objB->m_collisionObject->hasContactResponse()) + return true; + bool shouldSwap = false; if ((bodyA->getUserIndex() != -1) && (bodyB->getUserIndex() != -1)) { // If both bodies have a user index, the lower user index should be A From d001da4f4f28d987376ed79fcdf24b864f68f571 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Tue, 30 Apr 2024 12:38:44 -0700 Subject: [PATCH 34/55] Add option to disable RocketSim namespace for all types --- src/Framework.h | 5 +++++ src/RocketSim.cpp | 4 ++-- src/RocketSim.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Framework.h b/src/Framework.h index 05ba07ce..886aff8e 100644 --- a/src/Framework.h +++ b/src/Framework.h @@ -83,8 +83,13 @@ typedef uint8_t byte; #define RS_ALIGN_16 alignas(16) +#ifndef RS_NO_NAMESPACE #define RS_NS_START namespace RocketSim { #define RS_NS_END } +#else +#define RS_NS_START +#define RS_NS_END +#endif template size_t __RS_GET_ARGUMENT_COUNT(Args ...) { diff --git a/src/RocketSim.cpp b/src/RocketSim.cpp index 55d150f9..34b7ed37 100644 --- a/src/RocketSim.cpp +++ b/src/RocketSim.cpp @@ -47,11 +47,11 @@ RocketSimStage RocketSim::GetStage() { return stage; } -std::vector& RocketSim::GetArenaCollisionShapes(RocketSim::GameMode gameMode) { +std::vector& RocketSim::GetArenaCollisionShapes(GameMode gameMode) { static std::vector arenaCollisionMeshes; static std::vector arenaCollisionMeshes_hoops; - return (gameMode == RocketSim::GameMode::HOOPS ? arenaCollisionMeshes_hoops : arenaCollisionMeshes); + return (gameMode == GameMode::HOOPS ? arenaCollisionMeshes_hoops : arenaCollisionMeshes); } #ifndef RS_NO_SUSPCOLGRID diff --git a/src/RocketSim.h b/src/RocketSim.h index f3c59f66..4cfa4cc3 100644 --- a/src/RocketSim.h +++ b/src/RocketSim.h @@ -9,6 +9,7 @@ // RS_MAX_SPEED: Define this to remove certain sanity checks for faster speed // RS_DONT_LOG: Define this to disable all logging output // RS_NO_SUSPCOLGRID: Disable the suspension-collision grid optimization +// RS_NO_NAMESPACE: Disable the RocketSim namespace encapsulating all RocketSim classes/structs class btBvhTriangleMeshShape; From 884fde60a6a2a506fc2bfe0a5b54c00fada5308b Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 2 May 2024 21:06:05 -0700 Subject: [PATCH 35/55] Add CarState.airTime, CarState.HasFlipReset(), CarState.GotFlipReset(), improve comments of CarState fields --- src/Sim/Car/Car.cpp | 11 +++++++++++ src/Sim/Car/Car.h | 35 +++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/Sim/Car/Car.cpp b/src/Sim/Car/Car.cpp index 0158fabb..f253c17a 100644 --- a/src/Sim/Car/Car.cpp +++ b/src/Sim/Car/Car.cpp @@ -294,6 +294,14 @@ bool CarState::HasFlipOrJump() const { (!hasFlipped && !hasDoubleJumped && airTimeSinceJump < RLConst::DOUBLEJUMP_MAX_DELAY); } +bool CarState::HasFlipReset() const { + return !isOnGround && HasFlipOrJump() && !hasJumped; +} + +bool CarState::GotFlipReset() const { + return !isOnGround && !hasJumped; +} + void CarState::Serialize(DataStreamOut& out) const { ballHitInfo.Serialize(out); @@ -640,9 +648,12 @@ void Car::_UpdateDoubleJumpOrFlip(float tickTime, const MutatorConfig& mutatorCo if (_internalState.isOnGround) { _internalState.hasDoubleJumped = false; _internalState.hasFlipped = false; + _internalState.airTime = 0; _internalState.airTimeSinceJump = 0; _internalState.flipTime = 0; } else { + _internalState.airTime += tickTime; + if (_internalState.hasJumped && !_internalState.isJumping) { _internalState.airTimeSinceJump += tickTime; } else { diff --git a/src/Sim/Car/Car.h b/src/Sim/Car/Car.h index 67265750..2fd61c19 100644 --- a/src/Sim/Car/Car.h +++ b/src/Sim/Car/Car.h @@ -27,19 +27,35 @@ struct CarState : public PhysState { // First two are front bool wheelsWithContact[4] = {}; - bool hasJumped = false, hasDoubleJumped = false, hasFlipped = false; + // Whether we jumped to get into the air + // Can be false while airborne, if we left the ground with a flip reset + bool hasJumped = false; + + // True if we have double jumped and are still in the air + // NOTE: Flips DO NOT COUNT as double jumps! This is not RLBot. + bool hasDoubleJumped = false; + + // True if we are in the air, and (have flipped or are currently flipping) + bool hasFlipped = false; + + // Relative torque direction of the flip + // Forward flip will have positive Y Vec flipRelTorque = { 0, 0, 0 }; - // Active during the duration of a jump or flip - float jumpTime = 0, flipTime = 0; + float jumpTime = 0; // When currently jumping, the time since we started jumping, else 0 + float flipTime = 0; // When currently flipping, the time since we started flipping, else 0 - // True during a flip (not a jump, and not after a flip) + // True during a flip (not an auto-flip, and not after a flip) bool isFlipping = false; - // True during a jump (not double jumps or a flip) + // True during a jump bool isJumping = false; + // Total time spent in the air + float airTime = 0; + // Time spent in the air once !isJumping + // If we never jumped, it is 0 float airTimeSinceJump = 0; // Goes from 0 to 100 @@ -83,9 +99,16 @@ struct CarState : public PhysState { pos.z = RLConst::CAR_SPAWN_REST_Z; } - // Returns true if the car is currently able to jump, double-jump, or start a flip + // Returns true if the car is currently able to jump, double-jump, or flip bool HasFlipOrJump() const; + // Returns true if we currently have a flip, and got it from a flip reset (instead of a jump) + bool HasFlipReset() const; + + // Returns true if we are in the air, and became airborne from a flip reset + // This returns true regardless of whether or not we still have the flip + bool GotFlipReset() const; + void Serialize(DataStreamOut& out) const; void Deserialize(DataStreamIn& in); }; From 3c0e321b5f8fedb73ec3aec782173ea2f25ed274 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Sun, 5 May 2024 20:56:30 -0700 Subject: [PATCH 36/55] Make Heatseeker infinite boost --- src/Sim/MutatorConfig/MutatorConfig.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Sim/MutatorConfig/MutatorConfig.cpp b/src/Sim/MutatorConfig/MutatorConfig.cpp index 799435c2..b0a3f3b7 100644 --- a/src/Sim/MutatorConfig/MutatorConfig.cpp +++ b/src/Sim/MutatorConfig/MutatorConfig.cpp @@ -25,6 +25,12 @@ MutatorConfig::MutatorConfig(GameMode gameMode) { ballWorldRestitution = BALL_RESTITUTION; ballMass = BALL_MASS_BT; } + + if (gameMode == GameMode::HEATSEEKER) { + // Infinite boost + carSpawnBoostAmount = 100; + boostUsedPerSecond = 0; + } } void MutatorConfig::Serialize(DataStreamOut& out) const { From 05507a367a63cb4b5cc3c78fcf9bccd4d354ed75 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Tue, 7 May 2024 20:55:03 -0700 Subject: [PATCH 37/55] Disable suspcolgrid updates when there are no cars --- src/Sim/Arena/Arena.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 9b2e5039..80bda6e7 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -682,7 +682,8 @@ void Arena::Step(int ticksToSimulate) { } bool hasArenaStuff = (gameMode != GameMode::THE_VOID); - if (hasArenaStuff) { + bool shouldUpdateSuspColGrid = hasArenaStuff && !_cars.empty(); + if (shouldUpdateSuspColGrid) { #ifndef RS_NO_SUSPCOLGRID { // Add dynamic bodies to suspension grid for (Car* car : _cars) { @@ -706,7 +707,7 @@ void Arena::Step(int ticksToSimulate) { #ifdef RS_NO_SUSPCOLGRID suspColGridPtr = NULL; #else - if (hasArenaStuff) { + if (shouldUpdateSuspColGrid) { suspColGridPtr = &_suspColGrid; } else { suspColGridPtr = NULL; @@ -715,7 +716,7 @@ void Arena::Step(int ticksToSimulate) { car->_PreTickUpdate(gameMode, tickTime, _mutatorConfig, suspColGridPtr); } - if (hasArenaStuff) { + if (shouldUpdateSuspColGrid) { #ifndef RS_NO_SUSPCOLGRID _suspColGrid.ClearDynamicCollisions(); #endif From 51a52b66add5e2e796909d5c6614ed2f5a32f757 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 8 May 2024 03:36:46 -0700 Subject: [PATCH 38/55] Add experimental custom broadphase collision, disable suspcolgrid --- .../BroadphaseCollision/btAxisSweep3.cpp | 33 + .../BroadphaseCollision/btAxisSweep3.h | 48 + .../btAxisSweep3Internal.h | 954 ++++++++++++++++++ .../btBroadphaseInterface.h | 1 + .../BroadphaseCollision/btRSBroadphase.cpp | 390 +++++++ .../BroadphaseCollision/btRSBroadphase.h | 187 ++++ .../btSimpleBroadphase.cpp | 325 ++++++ .../BroadphaseCollision/btSimpleBroadphase.h | 148 +++ src/Framework.h | 5 +- src/Sim/Arena/Arena.cpp | 25 +- src/Sim/Arena/Arena.h | 2 +- .../SuspensionCollisionGrid.h | 6 - 12 files changed, 2114 insertions(+), 10 deletions(-) create mode 100644 libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp create mode 100644 libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3.h create mode 100644 libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h create mode 100644 libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp create mode 100644 libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.h create mode 100644 libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp create mode 100644 libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h diff --git a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp new file mode 100644 index 00000000..29310ec0 --- /dev/null +++ b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp @@ -0,0 +1,33 @@ + +//Bullet Continuous Collision Detection and Physics Library +//Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org + +// +// btAxisSweep3 +// +// Copyright (c) 2006 Simon Hobbs +// +// This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +#include "btAxisSweep3.h" + +btAxisSweep3::btAxisSweep3(const btVector3& worldAabbMin, const btVector3& worldAabbMax, unsigned short int maxHandles, btOverlappingPairCache* pairCache, bool disableRaycastAccelerator) + : btAxisSweep3Internal(worldAabbMin, worldAabbMax, 0xfffe, 0xffff, maxHandles, pairCache, disableRaycastAccelerator) +{ + // 1 handle is reserved as sentinel + btAssert(maxHandles > 1 && maxHandles < 32767); +} + +bt32BitAxisSweep3::bt32BitAxisSweep3(const btVector3& worldAabbMin, const btVector3& worldAabbMax, unsigned int maxHandles, btOverlappingPairCache* pairCache, bool disableRaycastAccelerator) + : btAxisSweep3Internal(worldAabbMin, worldAabbMax, 0xfffffffe, 0x7fffffff, maxHandles, pairCache, disableRaycastAccelerator) +{ + // 1 handle is reserved as sentinel + btAssert(maxHandles > 1 && maxHandles < 2147483647); +} diff --git a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3.h b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3.h new file mode 100644 index 00000000..4f2b8845 --- /dev/null +++ b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3.h @@ -0,0 +1,48 @@ +//Bullet Continuous Collision Detection and Physics Library +//Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org + +// +// btAxisSweep3.h +// +// Copyright (c) 2006 Simon Hobbs +// +// This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef BT_AXIS_SWEEP_3_H +#define BT_AXIS_SWEEP_3_H + +#include "../../LinearMath/btVector3.h" +#include "btOverlappingPairCache.h" +#include "btBroadphaseInterface.h" +#include "btBroadphaseProxy.h" +#include "btOverlappingPairCallback.h" +#include "btDbvtBroadphase.h" +#include "btAxisSweep3Internal.h" + +/// The btAxisSweep3 is an efficient implementation of the 3d axis sweep and prune broadphase. +/// It uses arrays rather then lists for storage of the 3 axis. Also it operates using 16 bit integer coordinates instead of floats. +/// For large worlds and many objects, use bt32BitAxisSweep3 or btDbvtBroadphase instead. bt32BitAxisSweep3 has higher precision and allows more then 16384 objects at the cost of more memory and bit of performance. +class btAxisSweep3 : public btAxisSweep3Internal +{ +public: + btAxisSweep3(const btVector3& worldAabbMin, const btVector3& worldAabbMax, unsigned short int maxHandles = 16384, btOverlappingPairCache* pairCache = 0, bool disableRaycastAccelerator = false); +}; + +/// The bt32BitAxisSweep3 allows higher precision quantization and more objects compared to the btAxisSweep3 sweep and prune. +/// This comes at the cost of more memory per handle, and a bit slower performance. +/// It uses arrays rather then lists for storage of the 3 axis. +class bt32BitAxisSweep3 : public btAxisSweep3Internal +{ +public: + bt32BitAxisSweep3(const btVector3& worldAabbMin, const btVector3& worldAabbMax, unsigned int maxHandles = 1500000, btOverlappingPairCache* pairCache = 0, bool disableRaycastAccelerator = false); +}; + +#endif diff --git a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h new file mode 100644 index 00000000..0fff5163 --- /dev/null +++ b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h @@ -0,0 +1,954 @@ +//Bullet Continuous Collision Detection and Physics Library +//Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org + +// +// btAxisSweep3.h +// +// Copyright (c) 2006 Simon Hobbs +// +// This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef BT_AXIS_SWEEP_3_INTERNAL_H +#define BT_AXIS_SWEEP_3_INTERNAL_H + +#include "../../LinearMath/btVector3.h" +#include "btOverlappingPairCache.h" +#include "btBroadphaseInterface.h" +#include "btBroadphaseProxy.h" +#include "btOverlappingPairCallback.h" +#include "btDbvtBroadphase.h" + +//#define DEBUG_BROADPHASE 1 +#define USE_OVERLAP_TEST_ON_REMOVES 1 + +/// The internal templace class btAxisSweep3Internal implements the sweep and prune broadphase. +/// It uses quantized integers to represent the begin and end points for each of the 3 axis. +/// Dont use this class directly, use btAxisSweep3 or bt32BitAxisSweep3 instead. +template +class btAxisSweep3Internal : public btBroadphaseInterface +{ +protected: + BP_FP_INT_TYPE m_bpHandleMask; + BP_FP_INT_TYPE m_handleSentinel; + +public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + + class Edge + { + public: + BP_FP_INT_TYPE m_pos; // low bit is min/max + BP_FP_INT_TYPE m_handle; + + BP_FP_INT_TYPE IsMax() const { return static_cast(m_pos & 1); } + }; + +public: + class Handle : public btBroadphaseProxy + { + public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + + // indexes into the edge arrays + BP_FP_INT_TYPE m_minEdges[3], m_maxEdges[3]; // 6 * 2 = 12 + // BP_FP_INT_TYPE m_uniqueId; + btBroadphaseProxy* m_dbvtProxy; //for faster raycast + //void* m_pOwner; this is now in btBroadphaseProxy.m_clientObject + + SIMD_FORCE_INLINE void SetNextFree(BP_FP_INT_TYPE next) { m_minEdges[0] = next; } + SIMD_FORCE_INLINE BP_FP_INT_TYPE GetNextFree() const { return m_minEdges[0]; } + }; // 24 bytes + 24 for Edge structures = 44 bytes total per entry + +protected: + btVector3 m_worldAabbMin; // overall system bounds + btVector3 m_worldAabbMax; // overall system bounds + + btVector3 m_quantize; // scaling factor for quantization + + BP_FP_INT_TYPE m_numHandles; // number of active handles + BP_FP_INT_TYPE m_maxHandles; // max number of handles + Handle* m_pHandles; // handles pool + + BP_FP_INT_TYPE m_firstFreeHandle; // free handles list + + Edge* m_pEdges[3]; // edge arrays for the 3 axes (each array has m_maxHandles * 2 + 2 sentinel entries) + void* m_pEdgesRawPtr[3]; + + btOverlappingPairCache* m_pairCache; + + ///btOverlappingPairCallback is an additional optional user callback for adding/removing overlapping pairs, similar interface to btOverlappingPairCache. + btOverlappingPairCallback* m_userPairCallback; + + bool m_ownsPairCache; + + int m_invalidPair; + + ///additional dynamic aabb structure, used to accelerate ray cast queries. + ///can be disabled using a optional argument in the constructor + btDbvtBroadphase* m_raycastAccelerator; + btOverlappingPairCache* m_nullPairCache; + + // allocation/deallocation + BP_FP_INT_TYPE allocHandle(); + void freeHandle(BP_FP_INT_TYPE handle); + + bool testOverlap2D(const Handle* pHandleA, const Handle* pHandleB, int axis0, int axis1); + +#ifdef DEBUG_BROADPHASE + void debugPrintAxis(int axis, bool checkCardinality = true); +#endif //DEBUG_BROADPHASE + + //Overlap* AddOverlap(BP_FP_INT_TYPE handleA, BP_FP_INT_TYPE handleB); + //void RemoveOverlap(BP_FP_INT_TYPE handleA, BP_FP_INT_TYPE handleB); + + void sortMinDown(int axis, BP_FP_INT_TYPE edge, btCollisionDispatcher* dispatcher, bool updateOverlaps); + void sortMinUp(int axis, BP_FP_INT_TYPE edge, btCollisionDispatcher* dispatcher, bool updateOverlaps); + void sortMaxDown(int axis, BP_FP_INT_TYPE edge, btCollisionDispatcher* dispatcher, bool updateOverlaps); + void sortMaxUp(int axis, BP_FP_INT_TYPE edge, btCollisionDispatcher* dispatcher, bool updateOverlaps); + +public: + btAxisSweep3Internal(const btVector3& worldAabbMin, const btVector3& worldAabbMax, BP_FP_INT_TYPE handleMask, BP_FP_INT_TYPE handleSentinel, BP_FP_INT_TYPE maxHandles = 16384, btOverlappingPairCache* pairCache = 0, bool disableRaycastAccelerator = false); + + virtual ~btAxisSweep3Internal(); + + BP_FP_INT_TYPE getNumHandles() const + { + return m_numHandles; + } + + virtual void calculateOverlappingPairs(btCollisionDispatcher* dispatcher); + + BP_FP_INT_TYPE addHandle(const btVector3& aabbMin, const btVector3& aabbMax, void* pOwner, int collisionFilterGroup, int collisionFilterMask, btCollisionDispatcher* dispatcher); + void removeHandle(BP_FP_INT_TYPE handle, btCollisionDispatcher* dispatcher); + void updateHandle(BP_FP_INT_TYPE handle, const btVector3& aabbMin, const btVector3& aabbMax, btCollisionDispatcher* dispatcher); + SIMD_FORCE_INLINE Handle* getHandle(BP_FP_INT_TYPE index) const { return m_pHandles + index; } + + virtual void resetPool(btCollisionDispatcher* dispatcher); + + void processAllOverlappingPairs(btOverlapCallback* callback); + + //Broadphase Interface + virtual btBroadphaseProxy* createProxy(const btVector3& aabbMin, const btVector3& aabbMax, int shapeType, void* userPtr, int collisionFilterGroup, int collisionFilterMask, btCollisionDispatcher* dispatcher); + virtual void destroyProxy(btBroadphaseProxy* proxy, btCollisionDispatcher* dispatcher); + virtual void setAabb(btBroadphaseProxy* proxy, const btVector3& aabbMin, const btVector3& aabbMax, btCollisionDispatcher* dispatcher); + virtual void getAabb(btBroadphaseProxy* proxy, btVector3& aabbMin, btVector3& aabbMax) const; + + virtual void rayTest(const btVector3& rayFrom, const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin = btVector3(0, 0, 0), const btVector3& aabbMax = btVector3(0, 0, 0)); + virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback); + + void quantize(BP_FP_INT_TYPE* out, const btVector3& point, int isMax) const; + ///unQuantize should be conservative: aabbMin/aabbMax should be larger then 'getAabb' result + void unQuantize(btBroadphaseProxy* proxy, btVector3& aabbMin, btVector3& aabbMax) const; + + bool testAabbOverlap(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1); + + btOverlappingPairCache* getOverlappingPairCache() + { + return m_pairCache; + } + const btOverlappingPairCache* getOverlappingPairCache() const + { + return m_pairCache; + } + + void setOverlappingPairUserCallback(btOverlappingPairCallback* pairCallback) + { + m_userPairCallback = pairCallback; + } + const btOverlappingPairCallback* getOverlappingPairUserCallback() const + { + return m_userPairCallback; + } + + ///getAabb returns the axis aligned bounding box in the 'global' coordinate frame + ///will add some transform later + virtual void getBroadphaseAabb(btVector3& aabbMin, btVector3& aabbMax) const + { + aabbMin = m_worldAabbMin; + aabbMax = m_worldAabbMax; + } + + virtual void printStats() + { + /* printf("btAxisSweep3.h\n"); + printf("numHandles = %d, maxHandles = %d\n",m_numHandles,m_maxHandles); + printf("aabbMin=%f,%f,%f,aabbMax=%f,%f,%f\n",m_worldAabbMin.getX(),m_worldAabbMin.getY(),m_worldAabbMin.getZ(), + m_worldAabbMax.getX(),m_worldAabbMax.getY(),m_worldAabbMax.getZ()); + */ + } +}; + +//////////////////////////////////////////////////////////////////// + +#ifdef DEBUG_BROADPHASE +#include + +template +void btAxisSweep3::debugPrintAxis(int axis, bool checkCardinality) +{ + int numEdges = m_pHandles[0].m_maxEdges[axis]; + printf("SAP Axis %d, numEdges=%d\n", axis, numEdges); + + int i; + for (i = 0; i < numEdges + 1; i++) + { + Edge* pEdge = m_pEdges[axis] + i; + Handle* pHandlePrev = getHandle(pEdge->m_handle); + int handleIndex = pEdge->IsMax() ? pHandlePrev->m_maxEdges[axis] : pHandlePrev->m_minEdges[axis]; + char beginOrEnd; + beginOrEnd = pEdge->IsMax() ? 'E' : 'B'; + printf(" [%c,h=%d,p=%x,i=%d]\n", beginOrEnd, pEdge->m_handle, pEdge->m_pos, handleIndex); + } + + if (checkCardinality) + btAssert(numEdges == m_numHandles * 2 + 1); +} +#endif //DEBUG_BROADPHASE + +template +btBroadphaseProxy* btAxisSweep3Internal::createProxy(const btVector3& aabbMin, const btVector3& aabbMax, int shapeType, void* userPtr, int collisionFilterGroup, int collisionFilterMask, btCollisionDispatcher* dispatcher) +{ + (void)shapeType; + BP_FP_INT_TYPE handleId = addHandle(aabbMin, aabbMax, userPtr, collisionFilterGroup, collisionFilterMask, dispatcher); + + Handle* handle = getHandle(handleId); + + if (m_raycastAccelerator) + { + btBroadphaseProxy* rayProxy = m_raycastAccelerator->createProxy(aabbMin, aabbMax, shapeType, userPtr, collisionFilterGroup, collisionFilterMask, dispatcher); + handle->m_dbvtProxy = rayProxy; + } + return handle; +} + +template +void btAxisSweep3Internal::destroyProxy(btBroadphaseProxy* proxy, btCollisionDispatcher* dispatcher) +{ + Handle* handle = static_cast(proxy); + if (m_raycastAccelerator) + m_raycastAccelerator->destroyProxy(handle->m_dbvtProxy, dispatcher); + removeHandle(static_cast(handle->m_uniqueId), dispatcher); +} + +template +void btAxisSweep3Internal::setAabb(btBroadphaseProxy* proxy, const btVector3& aabbMin, const btVector3& aabbMax, btCollisionDispatcher* dispatcher) +{ + Handle* handle = static_cast(proxy); + handle->m_aabbMin = aabbMin; + handle->m_aabbMax = aabbMax; + updateHandle(static_cast(handle->m_uniqueId), aabbMin, aabbMax, dispatcher); + if (m_raycastAccelerator) + m_raycastAccelerator->setAabb(handle->m_dbvtProxy, aabbMin, aabbMax, dispatcher); +} + +template +void btAxisSweep3Internal::rayTest(const btVector3& rayFrom, const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin, const btVector3& aabbMax) +{ + if (m_raycastAccelerator) + { + m_raycastAccelerator->rayTest(rayFrom, rayTo, rayCallback, aabbMin, aabbMax); + } + else + { + //choose axis? + BP_FP_INT_TYPE axis = 0; + //for each proxy + for (BP_FP_INT_TYPE i = 1; i < m_numHandles * 2 + 1; i++) + { + if (m_pEdges[axis][i].IsMax()) + { + rayCallback.process(getHandle(m_pEdges[axis][i].m_handle)); + } + } + } +} + +template +void btAxisSweep3Internal::aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) +{ + if (m_raycastAccelerator) + { + m_raycastAccelerator->aabbTest(aabbMin, aabbMax, callback); + } + else + { + //choose axis? + BP_FP_INT_TYPE axis = 0; + //for each proxy + for (BP_FP_INT_TYPE i = 1; i < m_numHandles * 2 + 1; i++) + { + if (m_pEdges[axis][i].IsMax()) + { + Handle* handle = getHandle(m_pEdges[axis][i].m_handle); + if (TestAabbAgainstAabb2(aabbMin, aabbMax, handle->m_aabbMin, handle->m_aabbMax)) + { + callback.process(handle); + } + } + } + } +} + +template +void btAxisSweep3Internal::getAabb(btBroadphaseProxy* proxy, btVector3& aabbMin, btVector3& aabbMax) const +{ + Handle* pHandle = static_cast(proxy); + aabbMin = pHandle->m_aabbMin; + aabbMax = pHandle->m_aabbMax; +} + +template +void btAxisSweep3Internal::unQuantize(btBroadphaseProxy* proxy, btVector3& aabbMin, btVector3& aabbMax) const +{ + Handle* pHandle = static_cast(proxy); + + unsigned short vecInMin[3]; + unsigned short vecInMax[3]; + + vecInMin[0] = m_pEdges[0][pHandle->m_minEdges[0]].m_pos; + vecInMax[0] = m_pEdges[0][pHandle->m_maxEdges[0]].m_pos + 1; + vecInMin[1] = m_pEdges[1][pHandle->m_minEdges[1]].m_pos; + vecInMax[1] = m_pEdges[1][pHandle->m_maxEdges[1]].m_pos + 1; + vecInMin[2] = m_pEdges[2][pHandle->m_minEdges[2]].m_pos; + vecInMax[2] = m_pEdges[2][pHandle->m_maxEdges[2]].m_pos + 1; + + aabbMin.setValue((btScalar)(vecInMin[0]) / (m_quantize.getX()), (btScalar)(vecInMin[1]) / (m_quantize.getY()), (btScalar)(vecInMin[2]) / (m_quantize.getZ())); + aabbMin += m_worldAabbMin; + + aabbMax.setValue((btScalar)(vecInMax[0]) / (m_quantize.getX()), (btScalar)(vecInMax[1]) / (m_quantize.getY()), (btScalar)(vecInMax[2]) / (m_quantize.getZ())); + aabbMax += m_worldAabbMin; +} + +template +btAxisSweep3Internal::btAxisSweep3Internal(const btVector3& worldAabbMin, const btVector3& worldAabbMax, BP_FP_INT_TYPE handleMask, BP_FP_INT_TYPE handleSentinel, BP_FP_INT_TYPE userMaxHandles, btOverlappingPairCache* pairCache, bool disableRaycastAccelerator) + : m_bpHandleMask(handleMask), + m_handleSentinel(handleSentinel), + m_pairCache(pairCache), + m_userPairCallback(0), + m_ownsPairCache(false), + m_invalidPair(0), + m_raycastAccelerator(0) +{ + BP_FP_INT_TYPE maxHandles = static_cast(userMaxHandles + 1); //need to add one sentinel handle + + if (!m_pairCache) + { + void* ptr = btAlignedAlloc(sizeof(btHashedOverlappingPairCache), 16); + m_pairCache = new (ptr) btHashedOverlappingPairCache(); + m_ownsPairCache = true; + } + + if (!disableRaycastAccelerator) + { + m_nullPairCache = new (btAlignedAlloc(sizeof(btNullPairCache), 16)) btNullPairCache(); + m_raycastAccelerator = new (btAlignedAlloc(sizeof(btDbvtBroadphase), 16)) btDbvtBroadphase(m_nullPairCache); //m_pairCache); + m_raycastAccelerator->m_deferedcollide = true; //don't add/remove pairs + } + + //btAssert(bounds.HasVolume()); + + // init bounds + m_worldAabbMin = worldAabbMin; + m_worldAabbMax = worldAabbMax; + + btVector3 aabbSize = m_worldAabbMax - m_worldAabbMin; + + BP_FP_INT_TYPE maxInt = m_handleSentinel; + + m_quantize = btVector3(btScalar(maxInt), btScalar(maxInt), btScalar(maxInt)) / aabbSize; + + // allocate handles buffer, using btAlignedAlloc, and put all handles on free list + m_pHandles = new Handle[maxHandles]; + + m_maxHandles = maxHandles; + m_numHandles = 0; + + // handle 0 is reserved as the null index, and is also used as the sentinel + m_firstFreeHandle = 1; + { + for (BP_FP_INT_TYPE i = m_firstFreeHandle; i < maxHandles; i++) + m_pHandles[i].SetNextFree(static_cast(i + 1)); + m_pHandles[maxHandles - 1].SetNextFree(0); + } + + { + // allocate edge buffers + for (int i = 0; i < 3; i++) + { + m_pEdgesRawPtr[i] = btAlignedAlloc(sizeof(Edge) * maxHandles * 2, 16); + m_pEdges[i] = new (m_pEdgesRawPtr[i]) Edge[maxHandles * 2]; + } + } + //removed overlap management + + // make boundary sentinels + + m_pHandles[0].m_clientObject = 0; + + for (int axis = 0; axis < 3; axis++) + { + m_pHandles[0].m_minEdges[axis] = 0; + m_pHandles[0].m_maxEdges[axis] = 1; + + m_pEdges[axis][0].m_pos = 0; + m_pEdges[axis][0].m_handle = 0; + m_pEdges[axis][1].m_pos = m_handleSentinel; + m_pEdges[axis][1].m_handle = 0; +#ifdef DEBUG_BROADPHASE + debugPrintAxis(axis); +#endif //DEBUG_BROADPHASE + } +} + +template +btAxisSweep3Internal::~btAxisSweep3Internal() +{ + if (m_raycastAccelerator) + { + m_nullPairCache->~btOverlappingPairCache(); + btAlignedFree(m_nullPairCache); + m_raycastAccelerator->~btDbvtBroadphase(); + btAlignedFree(m_raycastAccelerator); + } + + for (int i = 2; i >= 0; i--) + { + btAlignedFree(m_pEdgesRawPtr[i]); + } + delete[] m_pHandles; + + if (m_ownsPairCache) + { + m_pairCache->~btOverlappingPairCache(); + btAlignedFree(m_pairCache); + } +} + +template +void btAxisSweep3Internal::quantize(BP_FP_INT_TYPE* out, const btVector3& point, int isMax) const +{ +#ifdef OLD_CLAMPING_METHOD + ///problem with this clamping method is that the floating point during quantization might still go outside the range [(0|isMax) .. (m_handleSentinel&m_bpHandleMask]|isMax] + ///see http://code.google.com/p/bullet/issues/detail?id=87 + btVector3 clampedPoint(point); + clampedPoint.setMax(m_worldAabbMin); + clampedPoint.setMin(m_worldAabbMax); + btVector3 v = (clampedPoint - m_worldAabbMin) * m_quantize; + out[0] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getX() & m_bpHandleMask) | isMax); + out[1] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getY() & m_bpHandleMask) | isMax); + out[2] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getZ() & m_bpHandleMask) | isMax); +#else + btVector3 v = (point - m_worldAabbMin) * m_quantize; + out[0] = (v[0] <= 0) ? (BP_FP_INT_TYPE)isMax : (v[0] >= m_handleSentinel) ? (BP_FP_INT_TYPE)((m_handleSentinel & m_bpHandleMask) | isMax) : (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v[0] & m_bpHandleMask) | isMax); + out[1] = (v[1] <= 0) ? (BP_FP_INT_TYPE)isMax : (v[1] >= m_handleSentinel) ? (BP_FP_INT_TYPE)((m_handleSentinel & m_bpHandleMask) | isMax) : (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v[1] & m_bpHandleMask) | isMax); + out[2] = (v[2] <= 0) ? (BP_FP_INT_TYPE)isMax : (v[2] >= m_handleSentinel) ? (BP_FP_INT_TYPE)((m_handleSentinel & m_bpHandleMask) | isMax) : (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v[2] & m_bpHandleMask) | isMax); +#endif //OLD_CLAMPING_METHOD +} + +template +BP_FP_INT_TYPE btAxisSweep3Internal::allocHandle() +{ + btAssert(m_firstFreeHandle); + + BP_FP_INT_TYPE handle = m_firstFreeHandle; + m_firstFreeHandle = getHandle(handle)->GetNextFree(); + m_numHandles++; + + return handle; +} + +template +void btAxisSweep3Internal::freeHandle(BP_FP_INT_TYPE handle) +{ + btAssert(handle > 0 && handle < m_maxHandles); + + getHandle(handle)->SetNextFree(m_firstFreeHandle); + m_firstFreeHandle = handle; + + m_numHandles--; +} + +template +BP_FP_INT_TYPE btAxisSweep3Internal::addHandle(const btVector3& aabbMin, const btVector3& aabbMax, void* pOwner, int collisionFilterGroup, int collisionFilterMask, btCollisionDispatcher* dispatcher) +{ + // quantize the bounds + BP_FP_INT_TYPE min[3], max[3]; + quantize(min, aabbMin, 0); + quantize(max, aabbMax, 1); + + // allocate a handle + BP_FP_INT_TYPE handle = allocHandle(); + + Handle* pHandle = getHandle(handle); + + pHandle->m_uniqueId = static_cast(handle); + //pHandle->m_pOverlaps = 0; + pHandle->m_clientObject = pOwner; + pHandle->m_collisionFilterGroup = collisionFilterGroup; + pHandle->m_collisionFilterMask = collisionFilterMask; + + // compute current limit of edge arrays + BP_FP_INT_TYPE limit = static_cast(m_numHandles * 2); + + // insert new edges just inside the max boundary edge + for (BP_FP_INT_TYPE axis = 0; axis < 3; axis++) + { + m_pHandles[0].m_maxEdges[axis] += 2; + + m_pEdges[axis][limit + 1] = m_pEdges[axis][limit - 1]; + + m_pEdges[axis][limit - 1].m_pos = min[axis]; + m_pEdges[axis][limit - 1].m_handle = handle; + + m_pEdges[axis][limit].m_pos = max[axis]; + m_pEdges[axis][limit].m_handle = handle; + + pHandle->m_minEdges[axis] = static_cast(limit - 1); + pHandle->m_maxEdges[axis] = limit; + } + + // now sort the new edges to their correct position + sortMinDown(0, pHandle->m_minEdges[0], dispatcher, false); + sortMaxDown(0, pHandle->m_maxEdges[0], dispatcher, false); + sortMinDown(1, pHandle->m_minEdges[1], dispatcher, false); + sortMaxDown(1, pHandle->m_maxEdges[1], dispatcher, false); + sortMinDown(2, pHandle->m_minEdges[2], dispatcher, true); + sortMaxDown(2, pHandle->m_maxEdges[2], dispatcher, true); + + return handle; +} + +template +void btAxisSweep3Internal::removeHandle(BP_FP_INT_TYPE handle, btCollisionDispatcher* dispatcher) +{ + Handle* pHandle = getHandle(handle); + + //explicitly remove the pairs containing the proxy + //we could do it also in the sortMinUp (passing true) + ///@todo: compare performance + if (!m_pairCache->hasDeferredRemoval()) + { + m_pairCache->removeOverlappingPairsContainingProxy(pHandle, dispatcher); + } + + // compute current limit of edge arrays + int limit = static_cast(m_numHandles * 2); + + int axis; + + for (axis = 0; axis < 3; axis++) + { + m_pHandles[0].m_maxEdges[axis] -= 2; + } + + // remove the edges by sorting them up to the end of the list + for (axis = 0; axis < 3; axis++) + { + Edge* pEdges = m_pEdges[axis]; + BP_FP_INT_TYPE max = pHandle->m_maxEdges[axis]; + pEdges[max].m_pos = m_handleSentinel; + + sortMaxUp(axis, max, dispatcher, false); + + BP_FP_INT_TYPE i = pHandle->m_minEdges[axis]; + pEdges[i].m_pos = m_handleSentinel; + + sortMinUp(axis, i, dispatcher, false); + + pEdges[limit - 1].m_handle = 0; + pEdges[limit - 1].m_pos = m_handleSentinel; + +#ifdef DEBUG_BROADPHASE + debugPrintAxis(axis, false); +#endif //DEBUG_BROADPHASE + } + + // free the handle + freeHandle(handle); +} + +template +void btAxisSweep3Internal::resetPool(btCollisionDispatcher* /*dispatcher*/) +{ + if (m_numHandles == 0) + { + m_firstFreeHandle = 1; + { + for (BP_FP_INT_TYPE i = m_firstFreeHandle; i < m_maxHandles; i++) + m_pHandles[i].SetNextFree(static_cast(i + 1)); + m_pHandles[m_maxHandles - 1].SetNextFree(0); + } + } +} + +//#include + +template +void btAxisSweep3Internal::calculateOverlappingPairs(btCollisionDispatcher* dispatcher) +{ + if (m_pairCache->hasDeferredRemoval()) + { + btBroadphasePairArray& overlappingPairArray = m_pairCache->getOverlappingPairArray(); + + //perform a sort, to find duplicates and to sort 'invalid' pairs to the end + overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); + + overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); + m_invalidPair = 0; + + int i; + + btBroadphasePair previousPair; + previousPair.m_pProxy0 = 0; + previousPair.m_pProxy1 = 0; + previousPair.m_algorithm = 0; + + for (i = 0; i < overlappingPairArray.size(); i++) + { + btBroadphasePair& pair = overlappingPairArray[i]; + + bool isDuplicate = (pair == previousPair); + + previousPair = pair; + + bool needsRemoval = false; + + if (!isDuplicate) + { + ///important to use an AABB test that is consistent with the broadphase + bool hasOverlap = testAabbOverlap(pair.m_pProxy0, pair.m_pProxy1); + + if (hasOverlap) + { + needsRemoval = false; //callback->processOverlap(pair); + } + else + { + needsRemoval = true; + } + } + else + { + //remove duplicate + needsRemoval = true; + //should have no algorithm + btAssert(!pair.m_algorithm); + } + + if (needsRemoval) + { + m_pairCache->cleanOverlappingPair(pair, dispatcher); + + // m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); + // m_overlappingPairArray.pop_back(); + pair.m_pProxy0 = 0; + pair.m_pProxy1 = 0; + m_invalidPair++; + } + } + +///if you don't like to skip the invalid pairs in the array, execute following code: +#define CLEAN_INVALID_PAIRS 1 +#ifdef CLEAN_INVALID_PAIRS + + //perform a sort, to sort 'invalid' pairs to the end + overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); + + overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); + m_invalidPair = 0; +#endif //CLEAN_INVALID_PAIRS + + //printf("overlappingPairArray.size()=%d\n",overlappingPairArray.size()); + } +} + +template +bool btAxisSweep3Internal::testAabbOverlap(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) +{ + const Handle* pHandleA = static_cast(proxy0); + const Handle* pHandleB = static_cast(proxy1); + + //optimization 1: check the array index (memory address), instead of the m_pos + + for (int axis = 0; axis < 3; axis++) + { + if (pHandleA->m_maxEdges[axis] < pHandleB->m_minEdges[axis] || + pHandleB->m_maxEdges[axis] < pHandleA->m_minEdges[axis]) + { + return false; + } + } + return true; +} + +template +bool btAxisSweep3Internal::testOverlap2D(const Handle* pHandleA, const Handle* pHandleB, int axis0, int axis1) +{ + //optimization 1: check the array index (memory address), instead of the m_pos + + if (pHandleA->m_maxEdges[axis0] < pHandleB->m_minEdges[axis0] || + pHandleB->m_maxEdges[axis0] < pHandleA->m_minEdges[axis0] || + pHandleA->m_maxEdges[axis1] < pHandleB->m_minEdges[axis1] || + pHandleB->m_maxEdges[axis1] < pHandleA->m_minEdges[axis1]) + { + return false; + } + return true; +} + +template +void btAxisSweep3Internal::updateHandle(BP_FP_INT_TYPE handle, const btVector3& aabbMin, const btVector3& aabbMax, btCollisionDispatcher* dispatcher) +{ + // btAssert(bounds.IsFinite()); + //btAssert(bounds.HasVolume()); + + Handle* pHandle = getHandle(handle); + + // quantize the new bounds + BP_FP_INT_TYPE min[3], max[3]; + quantize(min, aabbMin, 0); + quantize(max, aabbMax, 1); + + // update changed edges + for (int axis = 0; axis < 3; axis++) + { + BP_FP_INT_TYPE emin = pHandle->m_minEdges[axis]; + BP_FP_INT_TYPE emax = pHandle->m_maxEdges[axis]; + + int dmin = (int)min[axis] - (int)m_pEdges[axis][emin].m_pos; + int dmax = (int)max[axis] - (int)m_pEdges[axis][emax].m_pos; + + m_pEdges[axis][emin].m_pos = min[axis]; + m_pEdges[axis][emax].m_pos = max[axis]; + + // expand (only adds overlaps) + if (dmin < 0) + sortMinDown(axis, emin, dispatcher, true); + + if (dmax > 0) + sortMaxUp(axis, emax, dispatcher, true); + + // shrink (only removes overlaps) + if (dmin > 0) + sortMinUp(axis, emin, dispatcher, true); + + if (dmax < 0) + sortMaxDown(axis, emax, dispatcher, true); + +#ifdef DEBUG_BROADPHASE + debugPrintAxis(axis); +#endif //DEBUG_BROADPHASE + } +} + +// sorting a min edge downwards can only ever *add* overlaps +template +void btAxisSweep3Internal::sortMinDown(int axis, BP_FP_INT_TYPE edge, btCollisionDispatcher* /* dispatcher */, bool updateOverlaps) +{ + Edge* pEdge = m_pEdges[axis] + edge; + Edge* pPrev = pEdge - 1; + Handle* pHandleEdge = getHandle(pEdge->m_handle); + + while (pEdge->m_pos < pPrev->m_pos) + { + Handle* pHandlePrev = getHandle(pPrev->m_handle); + + if (pPrev->IsMax()) + { + // if previous edge is a maximum check the bounds and add an overlap if necessary + const int axis1 = (1 << axis) & 3; + const int axis2 = (1 << axis1) & 3; + if (updateOverlaps && testOverlap2D(pHandleEdge, pHandlePrev, axis1, axis2)) + { + m_pairCache->addOverlappingPair(pHandleEdge, pHandlePrev); + if (m_userPairCallback) + m_userPairCallback->addOverlappingPair(pHandleEdge, pHandlePrev); + + //AddOverlap(pEdge->m_handle, pPrev->m_handle); + } + + // update edge reference in other handle + pHandlePrev->m_maxEdges[axis]++; + } + else + pHandlePrev->m_minEdges[axis]++; + + pHandleEdge->m_minEdges[axis]--; + + // swap the edges + Edge swap = *pEdge; + *pEdge = *pPrev; + *pPrev = swap; + + // decrement + pEdge--; + pPrev--; + } + +#ifdef DEBUG_BROADPHASE + debugPrintAxis(axis); +#endif //DEBUG_BROADPHASE +} + +// sorting a min edge upwards can only ever *remove* overlaps +template +void btAxisSweep3Internal::sortMinUp(int axis, BP_FP_INT_TYPE edge, btCollisionDispatcher* dispatcher, bool updateOverlaps) +{ + Edge* pEdge = m_pEdges[axis] + edge; + Edge* pNext = pEdge + 1; + Handle* pHandleEdge = getHandle(pEdge->m_handle); + + while (pNext->m_handle && (pEdge->m_pos >= pNext->m_pos)) + { + Handle* pHandleNext = getHandle(pNext->m_handle); + + if (pNext->IsMax()) + { + Handle* handle0 = getHandle(pEdge->m_handle); + Handle* handle1 = getHandle(pNext->m_handle); + const int axis1 = (1 << axis) & 3; + const int axis2 = (1 << axis1) & 3; + + // if next edge is maximum remove any overlap between the two handles + if (updateOverlaps +#ifdef USE_OVERLAP_TEST_ON_REMOVES + && testOverlap2D(handle0, handle1, axis1, axis2) +#endif //USE_OVERLAP_TEST_ON_REMOVES + ) + { + m_pairCache->removeOverlappingPair(handle0, handle1, dispatcher); + if (m_userPairCallback) + m_userPairCallback->removeOverlappingPair(handle0, handle1, dispatcher); + } + + // update edge reference in other handle + pHandleNext->m_maxEdges[axis]--; + } + else + pHandleNext->m_minEdges[axis]--; + + pHandleEdge->m_minEdges[axis]++; + + // swap the edges + Edge swap = *pEdge; + *pEdge = *pNext; + *pNext = swap; + + // increment + pEdge++; + pNext++; + } +} + +// sorting a max edge downwards can only ever *remove* overlaps +template +void btAxisSweep3Internal::sortMaxDown(int axis, BP_FP_INT_TYPE edge, btCollisionDispatcher* dispatcher, bool updateOverlaps) +{ + Edge* pEdge = m_pEdges[axis] + edge; + Edge* pPrev = pEdge - 1; + Handle* pHandleEdge = getHandle(pEdge->m_handle); + + while (pEdge->m_pos < pPrev->m_pos) + { + Handle* pHandlePrev = getHandle(pPrev->m_handle); + + if (!pPrev->IsMax()) + { + // if previous edge was a minimum remove any overlap between the two handles + Handle* handle0 = getHandle(pEdge->m_handle); + Handle* handle1 = getHandle(pPrev->m_handle); + const int axis1 = (1 << axis) & 3; + const int axis2 = (1 << axis1) & 3; + + if (updateOverlaps +#ifdef USE_OVERLAP_TEST_ON_REMOVES + && testOverlap2D(handle0, handle1, axis1, axis2) +#endif //USE_OVERLAP_TEST_ON_REMOVES + ) + { + //this is done during the overlappingpairarray iteration/narrowphase collision + + m_pairCache->removeOverlappingPair(handle0, handle1, dispatcher); + if (m_userPairCallback) + m_userPairCallback->removeOverlappingPair(handle0, handle1, dispatcher); + } + + // update edge reference in other handle + pHandlePrev->m_minEdges[axis]++; + ; + } + else + pHandlePrev->m_maxEdges[axis]++; + + pHandleEdge->m_maxEdges[axis]--; + + // swap the edges + Edge swap = *pEdge; + *pEdge = *pPrev; + *pPrev = swap; + + // decrement + pEdge--; + pPrev--; + } + +#ifdef DEBUG_BROADPHASE + debugPrintAxis(axis); +#endif //DEBUG_BROADPHASE +} + +// sorting a max edge upwards can only ever *add* overlaps +template +void btAxisSweep3Internal::sortMaxUp(int axis, BP_FP_INT_TYPE edge, btCollisionDispatcher* /* dispatcher */, bool updateOverlaps) +{ + Edge* pEdge = m_pEdges[axis] + edge; + Edge* pNext = pEdge + 1; + Handle* pHandleEdge = getHandle(pEdge->m_handle); + + while (pNext->m_handle && (pEdge->m_pos >= pNext->m_pos)) + { + Handle* pHandleNext = getHandle(pNext->m_handle); + + const int axis1 = (1 << axis) & 3; + const int axis2 = (1 << axis1) & 3; + + if (!pNext->IsMax()) + { + // if next edge is a minimum check the bounds and add an overlap if necessary + if (updateOverlaps && testOverlap2D(pHandleEdge, pHandleNext, axis1, axis2)) + { + Handle* handle0 = getHandle(pEdge->m_handle); + Handle* handle1 = getHandle(pNext->m_handle); + m_pairCache->addOverlappingPair(handle0, handle1); + if (m_userPairCallback) + m_userPairCallback->addOverlappingPair(handle0, handle1); + } + + // update edge reference in other handle + pHandleNext->m_minEdges[axis]--; + } + else + pHandleNext->m_maxEdges[axis]--; + + pHandleEdge->m_maxEdges[axis]++; + + // swap the edges + Edge swap = *pEdge; + *pEdge = *pNext; + *pNext = swap; + + // increment + pEdge++; + pNext++; + } +} + +#endif diff --git a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h index fc4e0455..7e07e6de 100644 --- a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h +++ b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h @@ -49,6 +49,7 @@ struct btBroadphaseRayCallback : public btBroadphaseAabbCallback class btBroadphaseInterface { public: + virtual ~btBroadphaseInterface() {} virtual btBroadphaseProxy* createProxy(const btVector3& aabbMin, const btVector3& aabbMax, int shapeType, void* userPtr, int collisionFilterGroup, int collisionFilterMask, btCollisionDispatcher* dispatcher) = 0; diff --git a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp new file mode 100644 index 00000000..3d622075 --- /dev/null +++ b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp @@ -0,0 +1,390 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btRSBroadphase.h" +#include "btDispatcher.h" +#include "btCollisionAlgorithm.h" + +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btTransform.h" +#include "../../LinearMath/btMatrix3x3.h" +#include "../../LinearMath/btAabbUtil2.h" + +#include +#include +#include +#include +#define THROW_ERR(msg) { std::string fullMsg = std::string() + "btRSBroadphase fatal error: " msg; std::cout << msg << std::endl; throw std::runtime_error(fullMsg); } + +void btRSBroadphase::validate() { + for (int i = 0; i < m_numHandles; i++) { + for (int j = i + 1; j < m_numHandles; j++) { + btAssert(&m_pHandles[i] != &m_pHandles[j]); + } + } +} + +btRSBroadphase::btRSBroadphase(btVector3 min, btVector3 max, float cellSize, btOverlappingPairCache* overlappingPairCache, int maxProxies) + : m_pairCache(overlappingPairCache), + m_ownsPairCache(false), + m_invalidPair(0) { + + if (!overlappingPairCache) + THROW_ERR("overlappingPairCache is NULL"); + + // allocate handles buffer and put all handles on free list + m_pHandlesRawPtr = btAlignedAlloc(sizeof(btRSBroadphaseProxy) * maxProxies, 16); + m_pHandles = new (m_pHandlesRawPtr) btRSBroadphaseProxy[maxProxies]; + m_maxHandles = maxProxies; + m_numHandles = 0; + m_firstFreeHandle = 0; + m_LastHandleIndex = -1; + + { + for (int i = m_firstFreeHandle; i < maxProxies; i++) { + m_pHandles[i].SetNextFree(i + 1); + m_pHandles[i].m_uniqueId = i + 2; //any UID will do, we just avoid too trivial values (0,1) for debugging purposes + } + m_pHandles[maxProxies - 1].SetNextFree(0); + } + + // Build grid + minPos = min; + maxPos = max; + if (!(minPos < maxPos)) + THROW_ERR("Invalid minPos and maxPos, (minPos < maxPos) failed"); + + btVector3 range = maxPos - minPos; + + this->cellSize = cellSize; + this->cellSizeSq = cellSize * cellSize; + + cellsX = btMax(1, (int)ceil(range.x() / cellSize)); + cellsY = btMax(1, (int)ceil(range.y() / cellSize)); + cellsZ = btMax(1, (int)ceil(range.z() / cellSize)); + totalCells = cellsX * cellsY * cellsZ; + + cells = std::vector(totalCells); +} + +btRSBroadphase::~btRSBroadphase() { + btAlignedFree(m_pHandlesRawPtr); + + if (m_ownsPairCache) { + m_pairCache->~btOverlappingPairCache(); + btAlignedFree(m_pairCache); + } +} + +template +void _UpdateCellsStatic(btRSBroadphase* _this, btRSBroadphaseProxy* proxy) { + + // Fix dumb massive value aabb bug + btVector3 aabbMax = proxy->m_aabbMax; + for (int i = 0; i < 3; i++) + aabbMax[i] = btMin(aabbMax[i], _this->maxPos[i]); + + int iMin, jMin, kMin; + int iMax, jMax, kMax; + _this->GetCellIndices(proxy->m_aabbMin, iMin, jMin, kMin); + _this->GetCellIndices(aabbMax, iMax, jMax, kMax); + + for (int i = iMin; i <= iMax; i++) { + for (int j = jMin; j <= jMax; j++) { + for (int k = kMin; k <= kMax; k++) { + auto& cell = _this->GetCell(i, j, k); + if (ADD) { + cell.staticHandles.push_back(proxy); + } else { + cell.RemoveStatic(proxy); + } + } + } + } +} + +btBroadphaseProxy* btRSBroadphase::createProxy(const btVector3& aabbMin, const btVector3& aabbMax, int shapeType, void* userPtr, int collisionFilterGroup, int collisionFilterMask, btCollisionDispatcher* /*dispatcher*/) { + if (m_numHandles >= m_maxHandles) { + btAssert(0); + return 0; //should never happen, but don't let the game crash ;-) + } + btAssert(aabbMin[0] <= aabbMax[0] && aabbMin[1] <= aabbMax[1] && aabbMin[2] <= aabbMax[2]); + + // TODO: Stupid + bool isStatic = (shapeType == TRIANGLE_MESH_SHAPE_PROXYTYPE || shapeType == STATIC_PLANE_PROXYTYPE); + + int newHandleIndex = allocHandle(); + int cellIdx = GetCellIdx(aabbMin); + btRSBroadphaseProxy* proxy = new (&m_pHandles[newHandleIndex]) btRSBroadphaseProxy( + aabbMin, aabbMax, shapeType, userPtr, collisionFilterGroup, collisionFilterMask, + isStatic, cellIdx + ); + + if (isStatic) { + _UpdateCellsStatic(this, proxy); + + } else { + if (aabbMin.distance2(aabbMax) > cellSizeSq) + THROW_ERR("Object AABB size exceeds maximum cell size (" + std::to_string(aabbMin.distance(aabbMax)) + " > " + std::to_string(cellSize) + ")"); + + int cellIdx = GetCellIdx(aabbMin); + cells[cellIdx].dynHandles.push_back(proxy); + numDynProxies++; + } + + return proxy; +} + +class RemovingOverlapCallback : public btOverlapCallback +{ +protected: + virtual bool processOverlap(btBroadphasePair& pair) { + (void)pair; + btAssert(0); + return false; + } +}; + +class RemovePairContainingProxy +{ + btBroadphaseProxy* m_targetProxy; + +public: + virtual ~RemovePairContainingProxy() { + } + +protected: + virtual bool processOverlap(btBroadphasePair& pair) { + btRSBroadphaseProxy* proxy0 = static_cast(pair.m_pProxy0); + btRSBroadphaseProxy* proxy1 = static_cast(pair.m_pProxy1); + + return ((m_targetProxy == proxy0 || m_targetProxy == proxy1)); + }; +}; + +void btRSBroadphase::destroyProxy(btBroadphaseProxy* proxyOrg, btCollisionDispatcher* dispatcher) { + btRSBroadphaseProxy* sbp = getRSProxyFromProxy(proxyOrg); + m_pairCache->removeOverlappingPairsContainingProxy(proxyOrg, dispatcher); + + if (sbp->isStatic) { + _UpdateCellsStatic(this, sbp); + } else { + Cell& cell = cells[sbp->cellIdx]; + for (int i = 0; i < cell.dynHandles.size(); i++) { + if (cell.dynHandles[i] == proxyOrg) { + cell.dynHandles.erase(cell.dynHandles.begin() + i); + break; + } + } + numDynProxies--; + } + + btRSBroadphaseProxy* proxy0 = static_cast(proxyOrg); + freeHandle(proxy0); +} + +void btRSBroadphase::getAabb(btBroadphaseProxy* proxy, btVector3& aabbMin, btVector3& aabbMax) const { + const btRSBroadphaseProxy* sbp = getRSProxyFromProxy(proxy); + aabbMin = sbp->m_aabbMin; + aabbMax = sbp->m_aabbMax; +} + +void btRSBroadphase::setAabb(btBroadphaseProxy* proxy, const btVector3& aabbMin, const btVector3& aabbMax, btCollisionDispatcher* /*dispatcher*/) { + btRSBroadphaseProxy* sbp = getRSProxyFromProxy(proxy); + + if (sbp->m_aabbMin != aabbMin || sbp->m_aabbMax != aabbMax) { + if (sbp->isStatic) { + _UpdateCellsStatic(this, sbp); + + sbp->m_aabbMin = aabbMin; + sbp->m_aabbMax = aabbMax; + + _UpdateCellsStatic(this, sbp); + } else { + + if (numDynProxies > 1) { + int oldIndex = sbp->cellIdx; + sbp->m_aabbMin = aabbMin; + sbp->m_aabbMax = aabbMax; + + int newIndex = GetCellIdx(aabbMin); + sbp->cellIdx = newIndex; + + if (oldIndex != newIndex) { + Cell& oldCell = cells[oldIndex]; + for (int i = 0; i < oldCell.dynHandles.size(); i++) { + if (oldCell.dynHandles[i] == sbp) { + oldCell.dynHandles.erase(oldCell.dynHandles.begin() + i); + break; + } + } + + Cell& newCell = cells[newIndex]; + newCell.dynHandles.push_back(sbp); + } + } + } + } +} + +void btRSBroadphase::rayTest(const btVector3& rayFrom, const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin, const btVector3& aabbMax) { + float rayLenSq = rayFrom.distance2(rayTo); + + if (rayLenSq > cellSizeSq) + THROW_ERR("Ray length may not exceed cellsize (" + std::to_string(sqrtf(rayLenSq)) + " > " + std::to_string(cellSize) + ")"); + + Cell& cell = cells[GetCellIdx(rayFrom)]; + for (auto& otherProxy : cell.staticHandles) + rayCallback.process(otherProxy); + + if (numDynProxies > 1) { + int ci, cj, ck; + GetCellIndices(rayFrom, ci, cj, ck); + + int mni = btMax(0, ci - 1), mnj = btMax(0, cj - 1), mnk = btMax(0, ck - 1); + int mxi = btMin(cellsX - 1, ci + 1), mxj = btMin(cellsY - 1, cj + 1), mxk = btMin(cellsZ - 1, ck + 1); + + for (int ci = mni; ci <= mxi; ci++) { + for (int cj = mnj; cj <= mxj; cj++) { + for (int ck = mnk; ck <= mxk; ck++) { + + Cell& otherCell = GetCell(ci, cj, ck); + for (auto& otherProxy : otherCell.dynHandles) + rayCallback.process(otherProxy); + } + } + } + } +} + +void btRSBroadphase::aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) { + for (int i = 0; i <= m_LastHandleIndex; i++) { + btRSBroadphaseProxy* proxy = &m_pHandles[i]; + if (!proxy->m_clientObject) { + continue; + } + if (TestAabbAgainstAabb2(aabbMin, aabbMax, proxy->m_aabbMin, proxy->m_aabbMax)) { + callback.process(proxy); + } + } +} + +bool btRSBroadphase::aabbOverlap(btRSBroadphaseProxy* proxy0, btRSBroadphaseProxy* proxy1) { + return proxy0->m_aabbMin[0] <= proxy1->m_aabbMax[0] && proxy1->m_aabbMin[0] <= proxy0->m_aabbMax[0] && + proxy0->m_aabbMin[1] <= proxy1->m_aabbMax[1] && proxy1->m_aabbMin[1] <= proxy0->m_aabbMax[1] && + proxy0->m_aabbMin[2] <= proxy1->m_aabbMax[2] && proxy1->m_aabbMin[2] <= proxy0->m_aabbMax[2]; +} + +//then remove non-overlapping ones +class CheckOverlapCallback : public btOverlapCallback +{ +public: + virtual bool processOverlap(btBroadphasePair& pair) { + return (!btRSBroadphase::aabbOverlap(static_cast(pair.m_pProxy0), static_cast(pair.m_pProxy1))); + } +}; + +void btRSBroadphase::calculateOverlappingPairs(btCollisionDispatcher* dispatcher) { + bool shouldRemove = !m_pairCache->hasDeferredRemoval(); + if (m_numHandles >= 0) { + int new_largest_index = -1; + for (int i = 0; i <= m_LastHandleIndex; i++) { + btRSBroadphaseProxy* proxy = &m_pHandles[i]; + if (proxy->isStatic) + continue; // TODO: Use separate list + + if (!proxy->m_clientObject) + continue; + + totalItrs++; + + new_largest_index = i; + + Cell& cell = cells[proxy->cellIdx]; + + for (auto& otherProxy : cell.staticHandles) { + totalStaticPairs++; + + if (aabbOverlap(proxy, otherProxy)) { + if (!m_pairCache->findPair(proxy, otherProxy)) { + m_pairCache->addOverlappingPair(proxy, otherProxy); + totalRealPairs++; + } + } else { + if (shouldRemove) { + if (m_pairCache->findPair(proxy, otherProxy)) { + m_pairCache->removeOverlappingPair(proxy, otherProxy, dispatcher); + } + } + } + } + + if (numDynProxies > 1) { + // TODO: Store these indices in proxy + int ci, cj, ck; + GetCellIndices(proxy->m_aabbMin, ci, cj, ck); + + int mni = btMax(0, ci - 1), mnj = btMax(0, cj - 1), mnk = btMax(0, ck - 1); + int mxi = btMin(cellsX - 1, ci + 1), mxj = btMin(cellsY - 1, cj + 1), mxk = btMin(cellsZ - 1, ck + 1); + + for (int ci = mni; ci <= mxi; ci++) { + for (int cj = mnj; cj <= mxj; cj++) { + for (int ck = mnk; ck <= mxk; ck++) { + + Cell& otherCell = GetCell(ci, cj, ck); + if (otherCell.dynHandles.size() < 2) + continue; + + for (auto& otherProxy : otherCell.dynHandles) { + if (otherProxy == proxy) + continue; + + totalDynPairs++; + + if (aabbOverlap(proxy, otherProxy)) { + if (!m_pairCache->findPair(proxy, otherProxy)) { + totalRealPairs++; + m_pairCache->addOverlappingPair(proxy, otherProxy); + } + } else { + if (shouldRemove) { + if (m_pairCache->findPair(proxy, otherProxy)) { + m_pairCache->removeOverlappingPair(proxy, otherProxy, dispatcher); + } + } + } + } + } + } + } + } + } + + m_LastHandleIndex = new_largest_index; + + if (m_ownsPairCache) + THROW_ERR("Cannot own pair cache!"); + } +} + +bool btRSBroadphase::testAabbOverlap(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) { + btRSBroadphaseProxy* p0 = getRSProxyFromProxy(proxy0); + btRSBroadphaseProxy* p1 = getRSProxyFromProxy(proxy1); + return aabbOverlap(p0, p1); +} + +void btRSBroadphase::resetPool(btCollisionDispatcher* dispatcher) { + //not yet +} diff --git a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.h b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.h new file mode 100644 index 00000000..b8bb842c --- /dev/null +++ b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.h @@ -0,0 +1,187 @@ +#pragma once + +#include "btOverlappingPairCache.h" +#include + +struct btRSBroadphaseProxy : public btBroadphaseProxy +{ + bool isStatic; + int cellIdx; + int shapeType; + int m_nextFree; + + // int m_handleId; + + btRSBroadphaseProxy() {}; + + btRSBroadphaseProxy( + const btVector3& minpt, const btVector3& maxpt, int shapeType, void* userPtr, int collisionFilterGroup, int collisionFilterMask, + bool isStatic, int cellIdx) + : btBroadphaseProxy(minpt, maxpt, userPtr, collisionFilterGroup, collisionFilterMask), + isStatic(isStatic), cellIdx(cellIdx), shapeType(shapeType) { + } + + SIMD_FORCE_INLINE void SetNextFree(int next) { m_nextFree = next; } + SIMD_FORCE_INLINE int GetNextFree() const { return m_nextFree; } +}; + +// Custom broadphase implementation for RocketSim +// Uses spacial division with a fixed voxel grid +// Somewhat based off of btSimpleBroadphase +class btRSBroadphase : public btBroadphaseInterface +{ +public: + int m_numHandles; // number of active handles + int m_maxHandles; // max number of handles + int m_LastHandleIndex; + + btVector3 minPos, maxPos; + float cellSize, cellSizeSq; + int cellsX, cellsY, cellsZ; + int totalCells; + + int numDynProxies = 0; + + int totalStaticPairs = 0, totalDynPairs = 0; + int totalRealPairs = 0; + int totalItrs = 0; + + struct Cell { + constexpr static int RESERVED_SIZE = 4; + std::vector dynHandles; + std::vector staticHandles; + Cell() { + dynHandles.reserve(RESERVED_SIZE); + staticHandles.reserve(RESERVED_SIZE); + } + + void RemoveDyn(btRSBroadphaseProxy* proxy) { + for (int i = 0; i < dynHandles.size(); i++) { + if (dynHandles[i] == proxy) { + dynHandles.erase(dynHandles.begin() + i); + return; + } + } + } + + void RemoveStatic(btRSBroadphaseProxy* proxy) { + for (int i = 0; i < staticHandles.size(); i++) { + if (staticHandles[i] == proxy) { + staticHandles.erase(staticHandles.begin() + i); + return; + } + } + } + }; + std::vector cells; + + Cell& GetCell(int i, int j, int k) { + int idx = i * cellsY * cellsZ + j * cellsZ + k; + return cells[idx]; + } + + void GetCellIndices(btVector3 pos, int& i, int& j, int& k) const { + btVector3 cellIdxF = (pos - minPos) / cellSize; + i = (int)cellIdxF.x(); + j = (int)cellIdxF.y(); + k = (int)cellIdxF.z(); + btClamp(i, 0, cellsX - 1); + btClamp(j, 0, cellsY - 1); + btClamp(k, 0, cellsZ - 1); + } + + int GetCellIdx(const btVector3& pos) const { + int i, j, k; + GetCellIndices(pos, i, j, k); + return i * cellsY * cellsZ + j * cellsZ + k; + } + + btRSBroadphaseProxy* m_pHandles; // handles pool + + void* m_pHandlesRawPtr; + int m_firstFreeHandle; // free handles list + + int allocHandle() { + btAssert(m_numHandles < m_maxHandles); + int freeHandle = m_firstFreeHandle; + m_firstFreeHandle = m_pHandles[freeHandle].GetNextFree(); + m_numHandles++; + if (freeHandle > m_LastHandleIndex) { + m_LastHandleIndex = freeHandle; + } + return freeHandle; + } + + void freeHandle(btRSBroadphaseProxy* proxy) { + int handle = int(proxy - m_pHandles); + btAssert(handle >= 0 && handle < m_maxHandles); + if (handle == m_LastHandleIndex) { + m_LastHandleIndex--; + } + proxy->SetNextFree(m_firstFreeHandle); + m_firstFreeHandle = handle; + + proxy->m_clientObject = 0; + + m_numHandles--; + } + + btOverlappingPairCache* m_pairCache; + bool m_ownsPairCache; + + int m_invalidPair; + + inline btRSBroadphaseProxy* getRSProxyFromProxy(btBroadphaseProxy* proxy) { + btRSBroadphaseProxy* proxy0 = static_cast(proxy); + return proxy0; + } + + inline const btRSBroadphaseProxy* getRSProxyFromProxy(btBroadphaseProxy* proxy) const { + const btRSBroadphaseProxy* proxy0 = static_cast(proxy); + return proxy0; + } + + ///reset broadphase internal structures, to ensure determinism/reproducability + virtual void resetPool(btCollisionDispatcher* dispatcher); + + void validate(); + +protected: +public: + btRSBroadphase(btVector3 min, btVector3 max, float cellSize, btOverlappingPairCache* overlappingPairCache, int maxProxies = 65536); + virtual ~btRSBroadphase(); + + static bool aabbOverlap(btRSBroadphaseProxy* proxy0, btRSBroadphaseProxy* proxy1); + + virtual btBroadphaseProxy* createProxy(const btVector3& aabbMin, const btVector3& aabbMax, int shapeType, void* userPtr, int collisionFilterGroup, int collisionFilterMask, btCollisionDispatcher* dispatcher); + + virtual void calculateOverlappingPairs(btCollisionDispatcher* dispatcher); + + virtual void destroyProxy(btBroadphaseProxy* proxy, btCollisionDispatcher* dispatcher); + virtual void setAabb(btBroadphaseProxy* proxy, const btVector3& aabbMin, const btVector3& aabbMax, btCollisionDispatcher* dispatcher); + virtual void getAabb(btBroadphaseProxy* proxy, btVector3& aabbMin, btVector3& aabbMax) const; + + virtual void rayTest(const btVector3& rayFrom, const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin = btVector3(0, 0, 0), const btVector3& aabbMax = btVector3(0, 0, 0)); + virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback); + + btOverlappingPairCache* getOverlappingPairCache() { + return m_pairCache; + } + const btOverlappingPairCache* getOverlappingPairCache() const { + return m_pairCache; + } + + bool testAabbOverlap(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1); + + ///getAabb returns the axis aligned bounding box in the 'global' coordinate frame + ///will add some transform later + virtual void getBroadphaseAabb(btVector3& aabbMin, btVector3& aabbMax) const { + aabbMin.setValue(-BT_LARGE_FLOAT, -BT_LARGE_FLOAT, -BT_LARGE_FLOAT); + aabbMax.setValue(BT_LARGE_FLOAT, BT_LARGE_FLOAT, BT_LARGE_FLOAT); + } + + virtual void printStats() { + // printf("btRSBroadphase.h\n"); + // printf("numHandles = %d, maxHandles = %d\n",m_numHandles,m_maxHandles); + } +}; \ No newline at end of file diff --git a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp new file mode 100644 index 00000000..8b4dd9b0 --- /dev/null +++ b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp @@ -0,0 +1,325 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "btSimpleBroadphase.h" +#include "btDispatcher.h" +#include "btCollisionAlgorithm.h" + +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btTransform.h" +#include "../../LinearMath/btMatrix3x3.h" +#include "../../LinearMath/btAabbUtil2.h" + +#include + +void btSimpleBroadphase::validate() +{ + for (int i = 0; i < m_numHandles; i++) + { + for (int j = i + 1; j < m_numHandles; j++) + { + btAssert(&m_pHandles[i] != &m_pHandles[j]); + } + } +} + +btSimpleBroadphase::btSimpleBroadphase(int maxProxies, btOverlappingPairCache* overlappingPairCache) + : m_pairCache(overlappingPairCache), + m_ownsPairCache(false), + m_invalidPair(0) +{ + if (!overlappingPairCache) + { + void* mem = btAlignedAlloc(sizeof(btHashedOverlappingPairCache), 16); + m_pairCache = new (mem) btHashedOverlappingPairCache(); + m_ownsPairCache = true; + } + + // allocate handles buffer and put all handles on free list + m_pHandlesRawPtr = btAlignedAlloc(sizeof(btSimpleBroadphaseProxy) * maxProxies, 16); + m_pHandles = new (m_pHandlesRawPtr) btSimpleBroadphaseProxy[maxProxies]; + m_maxHandles = maxProxies; + m_numHandles = 0; + m_firstFreeHandle = 0; + m_LastHandleIndex = -1; + + { + for (int i = m_firstFreeHandle; i < maxProxies; i++) + { + m_pHandles[i].SetNextFree(i + 1); + m_pHandles[i].m_uniqueId = i + 2; //any UID will do, we just avoid too trivial values (0,1) for debugging purposes + } + m_pHandles[maxProxies - 1].SetNextFree(0); + } +} + +btSimpleBroadphase::~btSimpleBroadphase() +{ + btAlignedFree(m_pHandlesRawPtr); + + if (m_ownsPairCache) + { + m_pairCache->~btOverlappingPairCache(); + btAlignedFree(m_pairCache); + } +} + +btBroadphaseProxy* btSimpleBroadphase::createProxy(const btVector3& aabbMin, const btVector3& aabbMax, int shapeType, void* userPtr, int collisionFilterGroup, int collisionFilterMask, btCollisionDispatcher* /*dispatcher*/) +{ + if (m_numHandles >= m_maxHandles) + { + btAssert(0); + return 0; //should never happen, but don't let the game crash ;-) + } + btAssert(aabbMin[0] <= aabbMax[0] && aabbMin[1] <= aabbMax[1] && aabbMin[2] <= aabbMax[2]); + + int newHandleIndex = allocHandle(); + btSimpleBroadphaseProxy* proxy = new (&m_pHandles[newHandleIndex]) btSimpleBroadphaseProxy(aabbMin, aabbMax, shapeType, userPtr, collisionFilterGroup, collisionFilterMask); + + return proxy; +} + +class RemovingOverlapCallback : public btOverlapCallback +{ +protected: + virtual bool processOverlap(btBroadphasePair& pair) + { + (void)pair; + btAssert(0); + return false; + } +}; + +class RemovePairContainingProxy +{ + btBroadphaseProxy* m_targetProxy; + +public: + virtual ~RemovePairContainingProxy() + { + } + +protected: + virtual bool processOverlap(btBroadphasePair& pair) + { + btSimpleBroadphaseProxy* proxy0 = static_cast(pair.m_pProxy0); + btSimpleBroadphaseProxy* proxy1 = static_cast(pair.m_pProxy1); + + return ((m_targetProxy == proxy0 || m_targetProxy == proxy1)); + }; +}; + +void btSimpleBroadphase::destroyProxy(btBroadphaseProxy* proxyOrg, btCollisionDispatcher* dispatcher) +{ + m_pairCache->removeOverlappingPairsContainingProxy(proxyOrg, dispatcher); + + btSimpleBroadphaseProxy* proxy0 = static_cast(proxyOrg); + freeHandle(proxy0); + + //validate(); +} + +void btSimpleBroadphase::getAabb(btBroadphaseProxy* proxy, btVector3& aabbMin, btVector3& aabbMax) const +{ + const btSimpleBroadphaseProxy* sbp = getSimpleProxyFromProxy(proxy); + aabbMin = sbp->m_aabbMin; + aabbMax = sbp->m_aabbMax; +} + +void btSimpleBroadphase::setAabb(btBroadphaseProxy* proxy, const btVector3& aabbMin, const btVector3& aabbMax, btCollisionDispatcher* /*dispatcher*/) +{ + btSimpleBroadphaseProxy* sbp = getSimpleProxyFromProxy(proxy); + sbp->m_aabbMin = aabbMin; + sbp->m_aabbMax = aabbMax; +} + +void btSimpleBroadphase::rayTest(const btVector3& rayFrom, const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin, const btVector3& aabbMax) +{ + for (int i = 0; i <= m_LastHandleIndex; i++) + { + btSimpleBroadphaseProxy* proxy = &m_pHandles[i]; + if (!proxy->m_clientObject) + { + continue; + } + rayCallback.process(proxy); + } +} + +void btSimpleBroadphase::aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) +{ + for (int i = 0; i <= m_LastHandleIndex; i++) + { + btSimpleBroadphaseProxy* proxy = &m_pHandles[i]; + if (!proxy->m_clientObject) + { + continue; + } + if (TestAabbAgainstAabb2(aabbMin, aabbMax, proxy->m_aabbMin, proxy->m_aabbMax)) + { + callback.process(proxy); + } + } +} + +bool btSimpleBroadphase::aabbOverlap(btSimpleBroadphaseProxy* proxy0, btSimpleBroadphaseProxy* proxy1) +{ + return proxy0->m_aabbMin[0] <= proxy1->m_aabbMax[0] && proxy1->m_aabbMin[0] <= proxy0->m_aabbMax[0] && + proxy0->m_aabbMin[1] <= proxy1->m_aabbMax[1] && proxy1->m_aabbMin[1] <= proxy0->m_aabbMax[1] && + proxy0->m_aabbMin[2] <= proxy1->m_aabbMax[2] && proxy1->m_aabbMin[2] <= proxy0->m_aabbMax[2]; +} + +//then remove non-overlapping ones +class CheckOverlapCallback : public btOverlapCallback +{ +public: + virtual bool processOverlap(btBroadphasePair& pair) + { + return (!btSimpleBroadphase::aabbOverlap(static_cast(pair.m_pProxy0), static_cast(pair.m_pProxy1))); + } +}; + +void btSimpleBroadphase::calculateOverlappingPairs(btCollisionDispatcher* dispatcher) +{ + //first check for new overlapping pairs + int i, j; + if (m_numHandles >= 0) + { + int new_largest_index = -1; + for (i = 0; i <= m_LastHandleIndex; i++) + { + btSimpleBroadphaseProxy* proxy0 = &m_pHandles[i]; + if (!proxy0->m_clientObject) + { + continue; + } + new_largest_index = i; + for (j = i + 1; j <= m_LastHandleIndex; j++) + { + btSimpleBroadphaseProxy* proxy1 = &m_pHandles[j]; + btAssert(proxy0 != proxy1); + if (!proxy1->m_clientObject) + { + continue; + } + + btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0); + btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1); + + if (aabbOverlap(p0, p1)) + { + if (!m_pairCache->findPair(proxy0, proxy1)) + { + m_pairCache->addOverlappingPair(proxy0, proxy1); + } + } + else + { + if (!m_pairCache->hasDeferredRemoval()) + { + if (m_pairCache->findPair(proxy0, proxy1)) + { + m_pairCache->removeOverlappingPair(proxy0, proxy1, dispatcher); + } + } + } + } + } + + m_LastHandleIndex = new_largest_index; + + if (m_ownsPairCache && m_pairCache->hasDeferredRemoval()) + { + btBroadphasePairArray& overlappingPairArray = m_pairCache->getOverlappingPairArray(); + + //perform a sort, to find duplicates and to sort 'invalid' pairs to the end + overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); + + overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); + m_invalidPair = 0; + + btBroadphasePair previousPair; + previousPair.m_pProxy0 = 0; + previousPair.m_pProxy1 = 0; + previousPair.m_algorithm = 0; + + for (i = 0; i < overlappingPairArray.size(); i++) + { + btBroadphasePair& pair = overlappingPairArray[i]; + + bool isDuplicate = (pair == previousPair); + + previousPair = pair; + + bool needsRemoval = false; + + if (!isDuplicate) + { + bool hasOverlap = testAabbOverlap(pair.m_pProxy0, pair.m_pProxy1); + + if (hasOverlap) + { + needsRemoval = false; //callback->processOverlap(pair); + } + else + { + needsRemoval = true; + } + } + else + { + //remove duplicate + needsRemoval = true; + //should have no algorithm + btAssert(!pair.m_algorithm); + } + + if (needsRemoval) + { + m_pairCache->cleanOverlappingPair(pair, dispatcher); + + // m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); + // m_overlappingPairArray.pop_back(); + pair.m_pProxy0 = 0; + pair.m_pProxy1 = 0; + m_invalidPair++; + } + } + + ///if you don't like to skip the invalid pairs in the array, execute following code: +#define CLEAN_INVALID_PAIRS 1 +#ifdef CLEAN_INVALID_PAIRS + + //perform a sort, to sort 'invalid' pairs to the end + overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); + + overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); + m_invalidPair = 0; +#endif //CLEAN_INVALID_PAIRS + } + } +} + +bool btSimpleBroadphase::testAabbOverlap(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) +{ + btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0); + btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1); + return aabbOverlap(p0, p1); +} + +void btSimpleBroadphase::resetPool(btCollisionDispatcher* dispatcher) +{ + //not yet +} diff --git a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h new file mode 100644 index 00000000..de2a1ef4 --- /dev/null +++ b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h @@ -0,0 +1,148 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef BT_SIMPLE_BROADPHASE_H +#define BT_SIMPLE_BROADPHASE_H + +#include "btOverlappingPairCache.h" + +struct btSimpleBroadphaseProxy : public btBroadphaseProxy +{ + int m_nextFree; + + // int m_handleId; + + btSimpleBroadphaseProxy(){}; + + btSimpleBroadphaseProxy(const btVector3& minpt, const btVector3& maxpt, int shapeType, void* userPtr, int collisionFilterGroup, int collisionFilterMask) + : btBroadphaseProxy(minpt, maxpt, userPtr, collisionFilterGroup, collisionFilterMask) + { + (void)shapeType; + } + + SIMD_FORCE_INLINE void SetNextFree(int next) { m_nextFree = next; } + SIMD_FORCE_INLINE int GetNextFree() const { return m_nextFree; } +}; + +///The SimpleBroadphase is just a unit-test for btAxisSweep3, bt32BitAxisSweep3, or btDbvtBroadphase, so use those classes instead. +///It is a brute force aabb culling broadphase based on O(n^2) aabb checks +class btSimpleBroadphase : public btBroadphaseInterface +{ +protected: + int m_numHandles; // number of active handles + int m_maxHandles; // max number of handles + int m_LastHandleIndex; + + btSimpleBroadphaseProxy* m_pHandles; // handles pool + + void* m_pHandlesRawPtr; + int m_firstFreeHandle; // free handles list + + int allocHandle() + { + btAssert(m_numHandles < m_maxHandles); + int freeHandle = m_firstFreeHandle; + m_firstFreeHandle = m_pHandles[freeHandle].GetNextFree(); + m_numHandles++; + if (freeHandle > m_LastHandleIndex) + { + m_LastHandleIndex = freeHandle; + } + return freeHandle; + } + + void freeHandle(btSimpleBroadphaseProxy* proxy) + { + int handle = int(proxy - m_pHandles); + btAssert(handle >= 0 && handle < m_maxHandles); + if (handle == m_LastHandleIndex) + { + m_LastHandleIndex--; + } + proxy->SetNextFree(m_firstFreeHandle); + m_firstFreeHandle = handle; + + proxy->m_clientObject = 0; + + m_numHandles--; + } + + btOverlappingPairCache* m_pairCache; + bool m_ownsPairCache; + + int m_invalidPair; + + inline btSimpleBroadphaseProxy* getSimpleProxyFromProxy(btBroadphaseProxy* proxy) + { + btSimpleBroadphaseProxy* proxy0 = static_cast(proxy); + return proxy0; + } + + inline const btSimpleBroadphaseProxy* getSimpleProxyFromProxy(btBroadphaseProxy* proxy) const + { + const btSimpleBroadphaseProxy* proxy0 = static_cast(proxy); + return proxy0; + } + + ///reset broadphase internal structures, to ensure determinism/reproducability + virtual void resetPool(btCollisionDispatcher* dispatcher); + + void validate(); + +protected: +public: + btSimpleBroadphase(int maxProxies = 16384, btOverlappingPairCache* overlappingPairCache = 0); + virtual ~btSimpleBroadphase(); + + static bool aabbOverlap(btSimpleBroadphaseProxy* proxy0, btSimpleBroadphaseProxy* proxy1); + + virtual btBroadphaseProxy* createProxy(const btVector3& aabbMin, const btVector3& aabbMax, int shapeType, void* userPtr, int collisionFilterGroup, int collisionFilterMask, btCollisionDispatcher* dispatcher); + + virtual void calculateOverlappingPairs(btCollisionDispatcher* dispatcher); + + virtual void destroyProxy(btBroadphaseProxy* proxy, btCollisionDispatcher* dispatcher); + virtual void setAabb(btBroadphaseProxy* proxy, const btVector3& aabbMin, const btVector3& aabbMax, btCollisionDispatcher* dispatcher); + virtual void getAabb(btBroadphaseProxy* proxy, btVector3& aabbMin, btVector3& aabbMax) const; + + virtual void rayTest(const btVector3& rayFrom, const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin = btVector3(0, 0, 0), const btVector3& aabbMax = btVector3(0, 0, 0)); + virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback); + + btOverlappingPairCache* getOverlappingPairCache() + { + return m_pairCache; + } + const btOverlappingPairCache* getOverlappingPairCache() const + { + return m_pairCache; + } + + bool testAabbOverlap(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1); + + ///getAabb returns the axis aligned bounding box in the 'global' coordinate frame + ///will add some transform later + virtual void getBroadphaseAabb(btVector3& aabbMin, btVector3& aabbMax) const + { + aabbMin.setValue(-BT_LARGE_FLOAT, -BT_LARGE_FLOAT, -BT_LARGE_FLOAT); + aabbMax.setValue(BT_LARGE_FLOAT, BT_LARGE_FLOAT, BT_LARGE_FLOAT); + } + + virtual void printStats() + { + // printf("btSimpleBroadphase.h\n"); + // printf("numHandles = %d, maxHandles = %d\n",m_numHandles,m_maxHandles); + } +}; + +#endif //BT_SIMPLE_BROADPHASE_H diff --git a/src/Framework.h b/src/Framework.h index 886aff8e..1f843df2 100644 --- a/src/Framework.h +++ b/src/Framework.h @@ -105,4 +105,7 @@ constexpr uint32_t __RS_GET_VERSION_ID() { } #define RS_VERSION_ID (__RS_GET_VERSION_ID()) -#define RS_IS_BIG_ENDIAN (std::endian::native == std::endian::big) \ No newline at end of file +#define RS_IS_BIG_ENDIAN (std::endian::native == std::endian::big) + +// TODO: Remove more permanently +#define RS_NO_SUSPCOLGRID \ No newline at end of file diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 80bda6e7..1dba81c3 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -1,6 +1,10 @@ #include "Arena.h" #include "../../RocketSim.h" +#include "../../../libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btAxisSweep3.h" +#include "../../../libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h" +#include "../../../libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" +#include "../../../libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.h" #include "../../../libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h" #include "../../../libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h" #include "../../../libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btBoxShape.h" @@ -443,11 +447,26 @@ Arena::Arena(GameMode gameMode, ArenaMemWeightMode memWeightMode, float tickRate _bulletWorldParams.constraintSolver = btSequentialImpulseConstraintSolver(); _bulletWorldParams.overlappingPairCache = new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache), 16)) btHashedOverlappingPairCache(); - _bulletWorldParams.broadphase = btDbvtBroadphase(_bulletWorldParams.overlappingPairCache); + + // TODO: Move to... somewhere! Maybe make ArenaConfig or something. + constexpr int + MAX_X = 4500, + MAX_Y = 6000, + MAX_Z = 2500, + + CELL_SIZE = 350, + MAX_OBJ_COUNT = 1024; + + _bulletWorldParams.broadphase = new btRSBroadphase( + btVector3(-MAX_X, -MAX_Y, 0) * UU_TO_BT, + btVector3(MAX_X, MAX_Y, MAX_Z) * UU_TO_BT, + CELL_SIZE * UU_TO_BT, + _bulletWorldParams.overlappingPairCache, + MAX_OBJ_COUNT); _bulletWorld.setup( &_bulletWorldParams.collisionDispatcher, - &_bulletWorldParams.broadphase, + _bulletWorldParams.broadphase, &_bulletWorldParams.constraintSolver, &_bulletWorldParams.collisionConfig ); @@ -955,6 +974,8 @@ Arena::~Arena() { _bulletWorldParams.overlappingPairCache->~btHashedOverlappingPairCache(); btAlignedFree(_bulletWorldParams.overlappingPairCache); + + delete _bulletWorldParams.broadphase; } void Arena::_SetupArenaCollisionShapes() { diff --git a/src/Sim/Arena/Arena.h b/src/Sim/Arena/Arena.h index 8f6a2956..dd2930ec 100644 --- a/src/Sim/Arena/Arena.h +++ b/src/Sim/Arena/Arena.h @@ -92,7 +92,7 @@ class Arena { btDefaultCollisionConfiguration collisionConfig; btCollisionDispatcher collisionDispatcher; btHashedOverlappingPairCache* overlappingPairCache; - btDbvtBroadphase broadphase; + btBroadphaseInterface* broadphase; btSequentialImpulseConstraintSolver constraintSolver; } _bulletWorldParams; diff --git a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h index 4922460a..e4cdf12b 100644 --- a/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h +++ b/src/Sim/SuspensionCollisionGrid/SuspensionCollisionGrid.h @@ -64,12 +64,6 @@ struct SuspensionCollisionGrid { return cellData[index]; } - template - Cell Get(int i, int j, int k) const { - int index = (i * CELL_AMOUNT_Y[LIGHT] * CELL_AMOUNT_Z[LIGHT]) + (j * CELL_AMOUNT_Z[LIGHT]) + k; - return cellData[index]; - } - template Vec GetCellMin(int xIndex, int yIndex, int zIndex) const { return Vec( From 322b490368c9c0be2aba25201729097fbb603e2c Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 8 May 2024 15:08:59 -0700 Subject: [PATCH 39/55] Make custom broadphase dynamic object updates bleed to surrounding cells to decrease lookup cost --- .../BroadphaseCollision/btRSBroadphase.cpp | 117 ++++++++---------- .../BroadphaseCollision/btRSBroadphase.h | 9 +- 2 files changed, 60 insertions(+), 66 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp index 3d622075..cd07385d 100644 --- a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp @@ -115,6 +115,26 @@ void _UpdateCellsStatic(btRSBroadphase* _this, btRSBroadphaseProxy* proxy) { } } +template +void _UpdateCellsDynamic(btRSBroadphase* _this, btRSBroadphaseProxy* proxy, int ci, int cj, int ck) { + + int mni = btMax(0, ci - 1), mnj = btMax(0, cj - 1), mnk = btMax(0, ck - 1); + int mxi = btMin(_this->cellsX - 1, ci + 1), mxj = btMin(_this->cellsY - 1, cj + 1), mxk = btMin(_this->cellsZ - 1, ck + 1); + + for (int ci = mni; ci <= mxi; ci++) { + for (int cj = mnj; cj <= mxj; cj++) { + for (int ck = mnk; ck <= mxk; ck++) { + auto& cell = _this->GetCell(ci, cj, ck); + if (ADD) { + cell.dynHandles.push_back(proxy); + } else { + cell.RemoveDyn(proxy); + } + } + } + } +} + btBroadphaseProxy* btRSBroadphase::createProxy(const btVector3& aabbMin, const btVector3& aabbMax, int shapeType, void* userPtr, int collisionFilterGroup, int collisionFilterMask, btCollisionDispatcher* /*dispatcher*/) { if (m_numHandles >= m_maxHandles) { btAssert(0); @@ -127,9 +147,13 @@ btBroadphaseProxy* btRSBroadphase::createProxy(const btVector3& aabbMin, const b int newHandleIndex = allocHandle(); int cellIdx = GetCellIdx(aabbMin); + int iIdx, jIdx, kIdx; + GetCellIndices(aabbMin, iIdx, jIdx, kIdx); + btRSBroadphaseProxy* proxy = new (&m_pHandles[newHandleIndex]) btRSBroadphaseProxy( aabbMin, aabbMax, shapeType, userPtr, collisionFilterGroup, collisionFilterMask, - isStatic, cellIdx + isStatic, + cellIdx, iIdx, jIdx, kIdx ); if (isStatic) { @@ -139,8 +163,7 @@ btBroadphaseProxy* btRSBroadphase::createProxy(const btVector3& aabbMin, const b if (aabbMin.distance2(aabbMax) > cellSizeSq) THROW_ERR("Object AABB size exceeds maximum cell size (" + std::to_string(aabbMin.distance(aabbMax)) + " > " + std::to_string(cellSize) + ")"); - int cellIdx = GetCellIdx(aabbMin); - cells[cellIdx].dynHandles.push_back(proxy); + _UpdateCellsDynamic(this, proxy, iIdx, jIdx, kIdx); numDynProxies++; } @@ -223,16 +246,17 @@ void btRSBroadphase::setAabb(btBroadphaseProxy* proxy, const btVector3& aabbMin, sbp->cellIdx = newIndex; if (oldIndex != newIndex) { - Cell& oldCell = cells[oldIndex]; - for (int i = 0; i < oldCell.dynHandles.size(); i++) { - if (oldCell.dynHandles[i] == sbp) { - oldCell.dynHandles.erase(oldCell.dynHandles.begin() + i); - break; - } - } - Cell& newCell = cells[newIndex]; - newCell.dynHandles.push_back(sbp); + _UpdateCellsDynamic(this, sbp, sbp->iIdx, sbp->jIdx, sbp->kIdx); + + // TODO: Can determine newIndex from these + int iNew, jNew, kNew; + GetCellIndices(aabbMin, iNew, jNew, kNew); + sbp->iIdx = iNew; + sbp->jIdx = jNew; + sbp->kIdx = kNew; + + _UpdateCellsDynamic(this, sbp, iNew, jNew, kNew); } } } @@ -248,25 +272,8 @@ void btRSBroadphase::rayTest(const btVector3& rayFrom, const btVector3& rayTo, b Cell& cell = cells[GetCellIdx(rayFrom)]; for (auto& otherProxy : cell.staticHandles) rayCallback.process(otherProxy); - - if (numDynProxies > 1) { - int ci, cj, ck; - GetCellIndices(rayFrom, ci, cj, ck); - - int mni = btMax(0, ci - 1), mnj = btMax(0, cj - 1), mnk = btMax(0, ck - 1); - int mxi = btMin(cellsX - 1, ci + 1), mxj = btMin(cellsY - 1, cj + 1), mxk = btMin(cellsZ - 1, ck + 1); - - for (int ci = mni; ci <= mxi; ci++) { - for (int cj = mnj; cj <= mxj; cj++) { - for (int ck = mnk; ck <= mxk; ck++) { - - Cell& otherCell = GetCell(ci, cj, ck); - for (auto& otherProxy : otherCell.dynHandles) - rayCallback.process(otherProxy); - } - } - } - } + for (auto& otherProxy : cell.dynHandles) + rayCallback.process(otherProxy); } void btRSBroadphase::aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) { @@ -332,39 +339,21 @@ void btRSBroadphase::calculateOverlappingPairs(btCollisionDispatcher* dispatcher } if (numDynProxies > 1) { - // TODO: Store these indices in proxy - int ci, cj, ck; - GetCellIndices(proxy->m_aabbMin, ci, cj, ck); - - int mni = btMax(0, ci - 1), mnj = btMax(0, cj - 1), mnk = btMax(0, ck - 1); - int mxi = btMin(cellsX - 1, ci + 1), mxj = btMin(cellsY - 1, cj + 1), mxk = btMin(cellsZ - 1, ck + 1); - - for (int ci = mni; ci <= mxi; ci++) { - for (int cj = mnj; cj <= mxj; cj++) { - for (int ck = mnk; ck <= mxk; ck++) { - - Cell& otherCell = GetCell(ci, cj, ck); - if (otherCell.dynHandles.size() < 2) - continue; - - for (auto& otherProxy : otherCell.dynHandles) { - if (otherProxy == proxy) - continue; - - totalDynPairs++; - - if (aabbOverlap(proxy, otherProxy)) { - if (!m_pairCache->findPair(proxy, otherProxy)) { - totalRealPairs++; - m_pairCache->addOverlappingPair(proxy, otherProxy); - } - } else { - if (shouldRemove) { - if (m_pairCache->findPair(proxy, otherProxy)) { - m_pairCache->removeOverlappingPair(proxy, otherProxy, dispatcher); - } - } - } + for (auto& otherProxy : cell.dynHandles) { + if (otherProxy == proxy) + continue; + + totalDynPairs++; + + if (aabbOverlap(proxy, otherProxy)) { + if (!m_pairCache->findPair(proxy, otherProxy)) { + m_pairCache->addOverlappingPair(proxy, otherProxy); + totalRealPairs++; + } + } else { + if (shouldRemove) { + if (m_pairCache->findPair(proxy, otherProxy)) { + m_pairCache->removeOverlappingPair(proxy, otherProxy, dispatcher); } } } diff --git a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.h b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.h index b8bb842c..ff72aa66 100644 --- a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.h +++ b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.h @@ -6,7 +6,10 @@ struct btRSBroadphaseProxy : public btBroadphaseProxy { bool isStatic; + int cellIdx; + int iIdx, jIdx, kIdx; + int shapeType; int m_nextFree; @@ -16,9 +19,11 @@ struct btRSBroadphaseProxy : public btBroadphaseProxy btRSBroadphaseProxy( const btVector3& minpt, const btVector3& maxpt, int shapeType, void* userPtr, int collisionFilterGroup, int collisionFilterMask, - bool isStatic, int cellIdx) + bool isStatic, int cellIdx, int i, int j, int k) : btBroadphaseProxy(minpt, maxpt, userPtr, collisionFilterGroup, collisionFilterMask), - isStatic(isStatic), cellIdx(cellIdx), shapeType(shapeType) { + isStatic(isStatic), + cellIdx(cellIdx), iIdx(i), jIdx(j), kIdx(k), + shapeType(shapeType) { } SIMD_FORCE_INLINE void SetNextFree(int next) { m_nextFree = next; } From 126deeec4ebea01deeda68f8b57161e8a89f2972 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 8 May 2024 15:29:53 -0700 Subject: [PATCH 40/55] Improve broadphase dynamic checks, add warning about long ray casts --- .../BroadphaseCollision/btRSBroadphase.cpp | 67 +++++++++++++------ 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp index cd07385d..c954880d 100644 --- a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp @@ -26,6 +26,8 @@ subject to the following restrictions: #include #include #include +#include + #define THROW_ERR(msg) { std::string fullMsg = std::string() + "btRSBroadphase fatal error: " msg; std::cout << msg << std::endl; throw std::runtime_error(fullMsg); } void btRSBroadphase::validate() { @@ -266,17 +268,38 @@ void btRSBroadphase::setAabb(btBroadphaseProxy* proxy, const btVector3& aabbMin, void btRSBroadphase::rayTest(const btVector3& rayFrom, const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin, const btVector3& aabbMax) { float rayLenSq = rayFrom.distance2(rayTo); - if (rayLenSq > cellSizeSq) - THROW_ERR("Ray length may not exceed cellsize (" + std::to_string(sqrtf(rayLenSq)) + " > " + std::to_string(cellSize) + ")"); - - Cell& cell = cells[GetCellIdx(rayFrom)]; - for (auto& otherProxy : cell.staticHandles) - rayCallback.process(otherProxy); - for (auto& otherProxy : cell.dynHandles) - rayCallback.process(otherProxy); + if (rayLenSq < cellSizeSq) { + + Cell& cell = cells[GetCellIdx(rayFrom)]; + for (auto& otherProxy : cell.staticHandles) + rayCallback.process(otherProxy); + for (auto& otherProxy : cell.dynHandles) + rayCallback.process(otherProxy); + } else { + static std::once_flag onceFlag; + std::call_once(onceFlag, + [this]() { + std::cout << + "[!] btRSBroadphase WARNING:" << + "\nRay casts in RocketSim that are longer than " << this->cellSize << "uu are very expensive and not properly optimized." << + "\nIf you have a project that requires these long rays, tell ZealanL to implement proper DDA for the custom voxel broadphase." << + std::endl; + } + ); + + for (int i = 0; i <= m_LastHandleIndex; i++) { + btRSBroadphaseProxy* proxy = &m_pHandles[i]; + if (!proxy->m_clientObject) { + continue; + } + rayCallback.process(proxy); + } + } } void btRSBroadphase::aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) { + // TODO: Optimize + for (int i = 0; i <= m_LastHandleIndex; i++) { btRSBroadphaseProxy* proxy = &m_pHandles[i]; if (!proxy->m_clientObject) { @@ -339,21 +362,23 @@ void btRSBroadphase::calculateOverlappingPairs(btCollisionDispatcher* dispatcher } if (numDynProxies > 1) { - for (auto& otherProxy : cell.dynHandles) { - if (otherProxy == proxy) - continue; + if (cell.dynHandles.size() > 1) { // We are dynamic, so there will always be 1 + for (auto& otherProxy : cell.dynHandles) { + if (otherProxy == proxy) + continue; - totalDynPairs++; + totalDynPairs++; - if (aabbOverlap(proxy, otherProxy)) { - if (!m_pairCache->findPair(proxy, otherProxy)) { - m_pairCache->addOverlappingPair(proxy, otherProxy); - totalRealPairs++; - } - } else { - if (shouldRemove) { - if (m_pairCache->findPair(proxy, otherProxy)) { - m_pairCache->removeOverlappingPair(proxy, otherProxy, dispatcher); + if (aabbOverlap(proxy, otherProxy)) { + if (!m_pairCache->findPair(proxy, otherProxy)) { + m_pairCache->addOverlappingPair(proxy, otherProxy); + totalRealPairs++; + } + } else { + if (shouldRemove) { + if (m_pairCache->findPair(proxy, otherProxy)) { + m_pairCache->removeOverlappingPair(proxy, otherProxy, dispatcher); + } } } } From 6fd1dbd2b86678fcc75f2f1c45c33219bcb8b800 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 8 May 2024 16:14:34 -0700 Subject: [PATCH 41/55] Disable sphere rotation updates, add to mutator config --- .../CollisionDispatch/btCollisionObject.h | 3 +++ .../BulletDynamics/ConstraintSolver/btSolverBody.h | 9 +++++++-- .../bullet3-3.24/BulletDynamics/Dynamics/btRigidBody.cpp | 7 ++++++- libsrc/bullet3-3.24/LinearMath/btTransformUtil.h | 5 +++++ src/Sim/Ball/Ball.cpp | 3 +++ src/Sim/MutatorConfig/MutatorConfig.cpp | 4 ++++ src/Sim/MutatorConfig/MutatorConfig.h | 4 ++++ 7 files changed, 32 insertions(+), 3 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionObject.h b/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionObject.h index b72c4077..9780d0d5 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionObject.h +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btCollisionObject.h @@ -90,6 +90,9 @@ btCollisionObject btScalar m_contactDamping; btScalar m_contactStiffness; + // Rotation updates will be skipped + int m_noRot = false; + ///m_internalType is reserved to distinguish Bullet's btCollisionObject, btRigidBody, btSoftBody, btGhostObject etc. ///do not assign your own m_internalType unless you write a new dynamics object class. int m_internalType; diff --git a/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSolverBody.h b/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSolverBody.h index 40d72116..0c5265a8 100644 --- a/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSolverBody.h +++ b/libsrc/bullet3-3.24/BulletDynamics/ConstraintSolver/btSolverBody.h @@ -23,6 +23,8 @@ class btRigidBody; #include "../../LinearMath/btAlignedAllocator.h" #include "../../LinearMath/btTransformUtil.h" +#include "../Dynamics/btRigidBody.h" + ///Until we get other contributions, only use SIMD on Windows, when using Visual Studio 2008 or later, and not double precision #ifdef BT_USE_SSE #define USE_SIMD 1 @@ -272,8 +274,11 @@ btSolverBody btTransform newTransform; if (m_pushVelocity[0] != 0.f || m_pushVelocity[1] != 0 || m_pushVelocity[2] != 0 || m_turnVelocity[0] != 0.f || m_turnVelocity[1] != 0 || m_turnVelocity[2] != 0) { - // btQuaternion orn = m_worldTransform.getRotation(); - btTransformUtil::integrateTransform(m_worldTransform, m_pushVelocity, m_turnVelocity * splitImpulseTurnErp, timeStep, newTransform); + if (m_originalBody->m_noRot) { + btTransformUtil::integrateTransformNoRot(m_worldTransform, m_pushVelocity, m_turnVelocity * splitImpulseTurnErp, timeStep, newTransform); + } else { + btTransformUtil::integrateTransform(m_worldTransform, m_pushVelocity, m_turnVelocity * splitImpulseTurnErp, timeStep, newTransform); + } m_worldTransform = newTransform; } //m_worldTransform.setRotation(orn); diff --git a/libsrc/bullet3-3.24/BulletDynamics/Dynamics/btRigidBody.cpp b/libsrc/bullet3-3.24/BulletDynamics/Dynamics/btRigidBody.cpp index 96f7358c..7f28bcec 100644 --- a/libsrc/bullet3-3.24/BulletDynamics/Dynamics/btRigidBody.cpp +++ b/libsrc/bullet3-3.24/BulletDynamics/Dynamics/btRigidBody.cpp @@ -98,7 +98,12 @@ void btRigidBody::setupRigidBody(const btRigidBody::btRigidBodyConstructionInfo& void btRigidBody::predictIntegratedTransform(btScalar timeStep, btTransform& predictedTransform) { - btTransformUtil::integrateTransform(m_worldTransform, m_linearVelocity, m_angularVelocity, timeStep, predictedTransform); + + if (m_noRot) { + btTransformUtil::integrateTransformNoRot(m_worldTransform, m_linearVelocity, m_angularVelocity, timeStep, predictedTransform); + } else { + btTransformUtil::integrateTransform(m_worldTransform, m_linearVelocity, m_angularVelocity, timeStep, predictedTransform); + } } void btRigidBody::saveKinematicState(btScalar timeStep) diff --git a/libsrc/bullet3-3.24/LinearMath/btTransformUtil.h b/libsrc/bullet3-3.24/LinearMath/btTransformUtil.h index a5aab208..66e8c58f 100644 --- a/libsrc/bullet3-3.24/LinearMath/btTransformUtil.h +++ b/libsrc/bullet3-3.24/LinearMath/btTransformUtil.h @@ -29,6 +29,11 @@ SIMD_FORCE_INLINE btVector3 btAabbSupport(const btVector3& halfExtents, const bt class btTransformUtil { public: + static void integrateTransformNoRot(const btTransform& curTrans, const btVector3& linvel, const btVector3& angvel, btScalar timeStep, btTransform& predictedTransform) { + predictedTransform.setOrigin(curTrans.getOrigin() + linvel * timeStep); + predictedTransform.setBasis(curTrans.getBasis()); + } + static void integrateTransform(const btTransform& curTrans, const btVector3& linvel, const btVector3& angvel, btScalar timeStep, btTransform& predictedTransform) { predictedTransform.setOrigin(curTrans.getOrigin() + linvel * timeStep); diff --git a/src/Sim/Ball/Ball.cpp b/src/Sim/Ball/Ball.cpp index a59a8efd..8b5b0e9f 100644 --- a/src/Sim/Ball/Ball.cpp +++ b/src/Sim/Ball/Ball.cpp @@ -103,6 +103,9 @@ void Ball::_BulletSetup(GameMode gameMode, btDynamicsWorld* bulletWorld, const M _rigidBody.m_rigidbodyFlags = 0; + if (mutatorConfig.noBallRot) + _rigidBody.m_noRot = true; + bulletWorld->addRigidBody(&_rigidBody, btBroadphaseProxy::DefaultFilter | CollisionMasks::HOOPS_NET, btBroadphaseProxy::AllFilter); } diff --git a/src/Sim/MutatorConfig/MutatorConfig.cpp b/src/Sim/MutatorConfig/MutatorConfig.cpp index b0a3f3b7..7798bf35 100644 --- a/src/Sim/MutatorConfig/MutatorConfig.cpp +++ b/src/Sim/MutatorConfig/MutatorConfig.cpp @@ -31,6 +31,10 @@ MutatorConfig::MutatorConfig(GameMode gameMode) { carSpawnBoostAmount = 100; boostUsedPerSecond = 0; } + + if (gameMode == GameMode::SNOWDAY) { + noBallRot = false; + } } void MutatorConfig::Serialize(DataStreamOut& out) const { diff --git a/src/Sim/MutatorConfig/MutatorConfig.h b/src/Sim/MutatorConfig/MutatorConfig.h index 702a6268..94d9b116 100644 --- a/src/Sim/MutatorConfig/MutatorConfig.h +++ b/src/Sim/MutatorConfig/MutatorConfig.h @@ -57,6 +57,10 @@ struct MutatorConfig { float ballRadius; + // Ball rotation updates are skipped to improve performance + // Disabled in snowday + bool noBallRot = true; + bool unlimitedFlips = false, unlimitedDoubleJumps = false; From 2acf73fcef48347aa86044e890fa77819502493d Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 8 May 2024 16:18:27 -0700 Subject: [PATCH 42/55] Add AABB caching to btTriangleMeshShape --- .../CollisionShapes/btTriangleMeshShape.cpp | 37 +++++++++++++------ .../CollisionShapes/btTriangleMeshShape.h | 6 ++- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp index 5c1d9637..ba04e788 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp @@ -20,6 +20,8 @@ subject to the following restrictions: #include "../../LinearMath/btAabbUtil2.h" #include "../CollisionShapes/btCollisionMargin.h" +#include + btTriangleMeshShape::btTriangleMeshShape(btStridingMeshInterface* meshInterface) : btConcaveShape(), m_meshInterface(meshInterface) { @@ -38,19 +40,32 @@ btTriangleMeshShape::~btTriangleMeshShape() { } -void btTriangleMeshShape::getAabb(const btTransform& trans, btVector3& aabbMin, btVector3& aabbMax) const +void btTriangleMeshShape::getAabb(const btTransform& trans, btVector3& aabbMin, btVector3& aabbMax) { - btVector3 localHalfExtents = btScalar(0.5) * (m_localAabbMax - m_localAabbMin); - localHalfExtents += btVector3(getMargin(), getMargin(), getMargin()); - btVector3 localCenter = btScalar(0.5) * (m_localAabbMax + m_localAabbMin); - - btMatrix3x3 abs_b = trans.getBasis().absolute(); - - btVector3 center = trans(localCenter); + if (!m_aabbCached || m_aabbCacheTrans != trans) { + btVector3 localHalfExtents = btScalar(0.5) * (m_localAabbMax - m_localAabbMin); + localHalfExtents += btVector3(getMargin(), getMargin(), getMargin()); + btVector3 localCenter = btScalar(0.5) * (m_localAabbMax + m_localAabbMin); + + btMatrix3x3 abs_b = trans.getBasis().absolute(); + + btVector3 center = trans(localCenter); + + btVector3 extent = localHalfExtents.dot3(abs_b[0], abs_b[1], abs_b[2]); + aabbMin = center - extent; + aabbMax = center + extent; + + btVector3 + newMin = center - extent, + newMax = center - extent; + m_aabbMinCache = newMin; + m_aabbMaxCache = newMax; + m_aabbCacheTrans = trans; + m_aabbCached = true; + } - btVector3 extent = localHalfExtents.dot3(abs_b[0], abs_b[1], abs_b[2]); - aabbMin = center - extent; - aabbMax = center + extent; + aabbMin = m_aabbMinCache; + aabbMax = m_aabbMaxCache; } void btTriangleMeshShape::recalcLocalAabb() diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.h b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.h index f7abd574..bcc4dac4 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.h +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.h @@ -28,6 +28,10 @@ btTriangleMeshShape : public btConcaveShape btVector3 m_localAabbMax; btStridingMeshInterface* m_meshInterface; + bool m_aabbCached = false; + btVector3 m_aabbMinCache, m_aabbMaxCache; + btTransform m_aabbCacheTrans; + ///btTriangleMeshShape constructor has been disabled/protected, so that users will not mistakenly use this class. ///Don't use btTriangleMeshShape but use btBvhTriangleMeshShape instead! btTriangleMeshShape(btStridingMeshInterface * meshInterface); @@ -49,7 +53,7 @@ btTriangleMeshShape : public btConcaveShape void recalcLocalAabb(); - void getAabb(const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const; + void getAabb(const btTransform& t, btVector3& aabbMin, btVector3& aabbMax); void processAllTriangles(btTriangleCallback * callback, const btVector3& aabbMin, const btVector3& aabbMax) const; From e775833f635743a8df656762c86d994fedb1a187 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 8 May 2024 16:22:35 -0700 Subject: [PATCH 43/55] Disable boostpad updates with ball-only simulation --- src/Sim/Arena/Arena.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 1dba81c3..55d1ef62 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -700,8 +700,10 @@ void Arena::Step(int ticksToSimulate) { } } + bool ballOnly = _cars.empty(); + bool hasArenaStuff = (gameMode != GameMode::THE_VOID); - bool shouldUpdateSuspColGrid = hasArenaStuff && !_cars.empty(); + bool shouldUpdateSuspColGrid = hasArenaStuff && !ballOnly; if (shouldUpdateSuspColGrid) { #ifndef RS_NO_SUSPCOLGRID { // Add dynamic bodies to suspension grid @@ -741,7 +743,7 @@ void Arena::Step(int ticksToSimulate) { #endif } - if (hasArenaStuff) { + if (hasArenaStuff && !ballOnly) { for (BoostPad* pad : _boostPads) pad->_PreTickUpdate(tickTime); } @@ -759,7 +761,7 @@ void Arena::Step(int ticksToSimulate) { _boostPadGrid.CheckCollision(car); } - if (hasArenaStuff) + if (hasArenaStuff && !ballOnly) for (BoostPad* pad : _boostPads) pad->_PostTickUpdate(tickTime, _mutatorConfig); From 6f85e493ebaffaeaabacb2209554ee9a5282eb45 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 8 May 2024 16:26:07 -0700 Subject: [PATCH 44/55] Make custom broadphase optional, add to mutator config --- src/Sim/Arena/Arena.cpp | 16 ++++++++++------ src/Sim/MutatorConfig/MutatorConfig.h | 15 ++++++++++----- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 55d1ef62..4fdeaa31 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -457,12 +457,16 @@ Arena::Arena(GameMode gameMode, ArenaMemWeightMode memWeightMode, float tickRate CELL_SIZE = 350, MAX_OBJ_COUNT = 1024; - _bulletWorldParams.broadphase = new btRSBroadphase( - btVector3(-MAX_X, -MAX_Y, 0) * UU_TO_BT, - btVector3(MAX_X, MAX_Y, MAX_Z) * UU_TO_BT, - CELL_SIZE * UU_TO_BT, - _bulletWorldParams.overlappingPairCache, - MAX_OBJ_COUNT); + if (_mutatorConfig.useCustomBroadphase) { + _bulletWorldParams.broadphase = new btRSBroadphase( + btVector3(-MAX_X, -MAX_Y, 0) * UU_TO_BT, + btVector3(MAX_X, MAX_Y, MAX_Z) * UU_TO_BT, + CELL_SIZE * UU_TO_BT, + _bulletWorldParams.overlappingPairCache, + MAX_OBJ_COUNT); + } else { + _bulletWorldParams.broadphase = new btDbvtBroadphase(_bulletWorldParams.overlappingPairCache); + } _bulletWorld.setup( &_bulletWorldParams.collisionDispatcher, diff --git a/src/Sim/MutatorConfig/MutatorConfig.h b/src/Sim/MutatorConfig/MutatorConfig.h index 94d9b116..79f45361 100644 --- a/src/Sim/MutatorConfig/MutatorConfig.h +++ b/src/Sim/MutatorConfig/MutatorConfig.h @@ -57,17 +57,22 @@ struct MutatorConfig { float ballRadius; - // Ball rotation updates are skipped to improve performance - // Disabled in snowday - bool noBallRot = true; - - bool + bool unlimitedFlips = false, unlimitedDoubleJumps = false; DemoMode demoMode = DemoMode::NORMAL; bool enableTeamDemos = false; + // Ball rotation updates are skipped to improve performance + // Disabled in snowday + bool noBallRot = true; + + // Use a custom broadphase designed for RocketSim + // Improves performance, but becomes inefficient on giant maps + // Turn this off if you want to use a giant map + bool useCustomBroadphase = true; + MutatorConfig(GameMode gameMode); RSAPI void Serialize(DataStreamOut& out) const; From 41bf42c8280925e0d868259516c002d988097366 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 8 May 2024 16:30:33 -0700 Subject: [PATCH 45/55] Slightly optimize btSphereShape.localGetSupportingVertex() --- .../BulletCollision/CollisionShapes/btSphereShape.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btSphereShape.cpp b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btSphereShape.cpp index 0783f6f8..984a3508 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btSphereShape.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btSphereShape.cpp @@ -42,9 +42,12 @@ btVector3 btSphereShape::localGetSupportingVertex(const btVector3& vec) const btVector3 vecnorm = vec; if (vecnorm.length2() < (SIMD_EPSILON * SIMD_EPSILON)) { - vecnorm.setValue(btScalar(-1.), btScalar(-1.), btScalar(-1.)); + static thread_local btVector3 invalidVecNorm = btVector3(-1, -1, -1).normalized(); + vecnorm = invalidVecNorm; + } else { + vecnorm.normalize(); } - vecnorm.normalize(); + supVertex += getMargin() * vecnorm; return supVertex; } From 14bab4c2ec2b7e262068798204a274e4478925a2 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 8 May 2024 22:45:13 -0700 Subject: [PATCH 46/55] Fix typo in btTriangleMeshShape caching --- .../BulletCollision/CollisionShapes/btTriangleMeshShape.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp index ba04e788..dfda91fb 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp @@ -52,12 +52,10 @@ void btTriangleMeshShape::getAabb(const btTransform& trans, btVector3& aabbMin, btVector3 center = trans(localCenter); btVector3 extent = localHalfExtents.dot3(abs_b[0], abs_b[1], abs_b[2]); - aabbMin = center - extent; - aabbMax = center + extent; - btVector3 newMin = center - extent, - newMax = center - extent; + newMax = center + extent; + m_aabbMinCache = newMin; m_aabbMaxCache = newMax; m_aabbCacheTrans = trans; From 71a37b32b372a32d361bb3ddef8bd666d01adbb2 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 8 May 2024 23:37:35 -0700 Subject: [PATCH 47/55] Improve AABB calculation of axis-aligned static planes --- .../CollisionShapes/btStaticPlaneShape.cpp | 39 ++++++++++++------- .../CollisionShapes/btStaticPlaneShape.h | 7 +++- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp index d746af1b..b557987d 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp @@ -4,8 +4,8 @@ Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -18,18 +18,26 @@ subject to the following restrictions: #include "../../LinearMath/btTransformUtil.h" btStaticPlaneShape::btStaticPlaneShape(const btVector3& planeNormal, btScalar planeConstant) - : btConcaveShape(), m_planeNormal(planeNormal.normalized()), m_planeConstant(planeConstant) -{ + : btConcaveShape(), m_planeNormal(planeNormal.normalized()), m_planeConstant(planeConstant) { m_shapeType = STATIC_PLANE_PROXYTYPE; // btAssert( btFuzzyZero(m_planeNormal.length() - btScalar(1.)) ); + + int numAxis = 0; + for (int i = 0; i < 3; i++) + if (!btFuzzyZero(m_planeNormal[i])) + numAxis++; + + if (numAxis == 1) { + m_isSingleAxis = true; + m_singleAxisIdx = m_planeNormal.closestAxis(); + m_singleAxisBackwards = m_planeNormal[m_singleAxisIdx] < 0; + } } -btStaticPlaneShape::~btStaticPlaneShape() -{ +btStaticPlaneShape::~btStaticPlaneShape() { } -void btStaticPlaneShape::getAabb(const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const -{ +void btStaticPlaneShape::getAabb(const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const { (void)t; /* btVector3 infvec (btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); @@ -38,15 +46,19 @@ void btStaticPlaneShape::getAabb(const btTransform& t, btVector3& aabbMin, btVec aabbMin = center + infvec*m_planeNormal; aabbMax = aabbMin; aabbMin.setMin(center - infvec*m_planeNormal); - aabbMax.setMax(center - infvec*m_planeNormal); + aabbMax.setMax(center - infvec*m_planeNormal); */ aabbMin.setValue(btScalar(-BT_LARGE_FLOAT), btScalar(-BT_LARGE_FLOAT), btScalar(-BT_LARGE_FLOAT)); aabbMax.setValue(btScalar(BT_LARGE_FLOAT), btScalar(BT_LARGE_FLOAT), btScalar(BT_LARGE_FLOAT)); + + if (m_isSingleAxis) { + aabbMin[m_singleAxisIdx] = t.getOrigin()[m_singleAxisIdx] + (m_planeConstant - 1); + aabbMax[m_singleAxisIdx] = t.getOrigin()[m_singleAxisIdx] + (m_planeConstant + 1); + } } -void btStaticPlaneShape::processAllTriangles(btTriangleCallback* callback, const btVector3& aabbMin, const btVector3& aabbMax) const -{ +void btStaticPlaneShape::processAllTriangles(btTriangleCallback* callback, const btVector3& aabbMin, const btVector3& aabbMax) const { btVector3 halfExtents = (aabbMax - aabbMin) * btScalar(0.5); btScalar radius = halfExtents.length(); btVector3 center = (aabbMax + aabbMin) * btScalar(0.5); @@ -74,11 +86,10 @@ void btStaticPlaneShape::processAllTriangles(btTriangleCallback* callback, const callback->processTriangle(triangle, 0, 1); } -void btStaticPlaneShape::calculateLocalInertia(btScalar mass, btVector3& inertia) const -{ +void btStaticPlaneShape::calculateLocalInertia(btScalar mass, btVector3& inertia) const { (void)mass; //moving concave objects not supported inertia.setValue(btScalar(0.), btScalar(0.), btScalar(0.)); -} +} \ No newline at end of file diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.h b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.h index e000417f..0b54cda2 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.h +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.h @@ -22,12 +22,17 @@ subject to the following restrictions: ATTRIBUTE_ALIGNED16(class) btStaticPlaneShape : public btConcaveShape { -protected: +public: btVector3 m_localAabbMin; btVector3 m_localAabbMax; btVector3 m_planeNormal; btScalar m_planeConstant; + + // Plane only exists along a single axis + bool m_isSingleAxis; + int m_singleAxisIdx; + bool m_singleAxisBackwards; public: BT_DECLARE_ALIGNED_ALLOCATOR(); From 6847f7f94c6cc3662a5c0ae688a86d6340255fd5 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Wed, 8 May 2024 23:37:57 -0700 Subject: [PATCH 48/55] Fix potentially unused calculation in btConvexPlaneCollisionAlgorithm --- .../btConvexPlaneCollisionAlgorithm.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp b/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp index 7090a4e3..b40270b0 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp @@ -104,22 +104,22 @@ void btConvexPlaneCollisionAlgorithm::processCollision(const btCollisionObjectWr bool hasCollision = false; const btVector3& planeNormal = planeShape->getPlaneNormal(); const btScalar& planeConstant = planeShape->getPlaneConstant(); + btTransform planeInConvex; - planeInConvex = convexObjWrap->getWorldTransform().inverse() * planeObjWrap->getWorldTransform(); btTransform convexInPlaneTrans; + planeInConvex = convexObjWrap->getWorldTransform().inverse() * planeObjWrap->getWorldTransform(); convexInPlaneTrans = planeObjWrap->getWorldTransform().inverse() * convexObjWrap->getWorldTransform(); btVector3 vtx = convexShape->localGetSupportingVertex(planeInConvex.getBasis() * -planeNormal); btVector3 vtxInPlane = convexInPlaneTrans(vtx); btScalar distance = (planeNormal.dot(vtxInPlane) - planeConstant); - - btVector3 vtxInPlaneProjected = vtxInPlane - distance * planeNormal; - btVector3 vtxInPlaneWorld = planeObjWrap->getWorldTransform() * vtxInPlaneProjected; - hasCollision = distance < m_manifoldPtr->getContactBreakingThreshold()+ resultOut->m_closestPointDistanceThreshold; resultOut->setPersistentManifold(m_manifoldPtr); if (hasCollision) { + btVector3 vtxInPlaneProjected = vtxInPlane - distance * planeNormal; + btVector3 vtxInPlaneWorld = planeObjWrap->getWorldTransform() * vtxInPlaneProjected; + /// report a contact. internally this will be kept persistent, and contact reduction is done btVector3 normalOnSurfaceB = planeObjWrap->getWorldTransform().getBasis() * planeNormal; btVector3 pOnB = vtxInPlaneWorld; From 9887d857f6271d8aad3f27e8c05c0ddd706791bb Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 9 May 2024 00:19:23 -0700 Subject: [PATCH 49/55] Decrease axis plane constant offset --- .../BulletCollision/CollisionShapes/btStaticPlaneShape.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp index b557987d..0308b24f 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp @@ -51,10 +51,12 @@ void btStaticPlaneShape::getAabb(const btTransform& t, btVector3& aabbMin, btVec aabbMin.setValue(btScalar(-BT_LARGE_FLOAT), btScalar(-BT_LARGE_FLOAT), btScalar(-BT_LARGE_FLOAT)); aabbMax.setValue(btScalar(BT_LARGE_FLOAT), btScalar(BT_LARGE_FLOAT), btScalar(BT_LARGE_FLOAT)); + + constexpr float PLANE_CONSTANT_OFFSET = 0.01f; if (m_isSingleAxis) { - aabbMin[m_singleAxisIdx] = t.getOrigin()[m_singleAxisIdx] + (m_planeConstant - 1); - aabbMax[m_singleAxisIdx] = t.getOrigin()[m_singleAxisIdx] + (m_planeConstant + 1); + aabbMin[m_singleAxisIdx] = t.getOrigin()[m_singleAxisIdx] + (m_planeConstant - PLANE_CONSTANT_OFFSET); + aabbMax[m_singleAxisIdx] = t.getOrigin()[m_singleAxisIdx] + (m_planeConstant + PLANE_CONSTANT_OFFSET); } } From beb05b77dce1eb0fce02bf427ffebb0b9c2f229c Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 9 May 2024 00:19:54 -0700 Subject: [PATCH 50/55] Create ArenaConfig, move several arena settings there --- src/Sim/Arena/Arena.cpp | 45 +++++++++----------- src/Sim/Arena/Arena.h | 23 +++++----- src/Sim/Arena/ArenaConfig/ArenaConfig.cpp | 13 ++++++ src/Sim/Arena/ArenaConfig/ArenaConfig.h | 47 +++++++++++++++++++++ src/Sim/Ball/Ball.cpp | 5 +-- src/Sim/Ball/Ball.h | 2 +- src/Sim/BallPredTracker/BallPredTracker.cpp | 2 +- src/Sim/MutatorConfig/MutatorConfig.cpp | 4 -- src/Sim/MutatorConfig/MutatorConfig.h | 15 ++----- 9 files changed, 99 insertions(+), 57 deletions(-) create mode 100644 src/Sim/Arena/ArenaConfig/ArenaConfig.cpp create mode 100644 src/Sim/Arena/ArenaConfig/ArenaConfig.h diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 4fdeaa31..828ffca3 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -27,7 +27,7 @@ RSAPI void Arena::SetMutatorConfig(const MutatorConfig& mutatorConfig) { // We'll need to remake the ball _bulletWorld.removeCollisionObject(&ball->_rigidBody); delete ball->_collisionShape; - ball->_BulletSetup(gameMode, &_bulletWorld, mutatorConfig); + ball->_BulletSetup(gameMode, &_bulletWorld, mutatorConfig, _config.noBallRot); } if (carMassChanged) { @@ -418,7 +418,7 @@ void Arena::_BtCallback_OnCarWorldCollision(Car* car, btCollisionObject* world, manifoldPoint.m_combinedRestitution = _mutatorConfig.carWorldRestitution; } -Arena::Arena(GameMode gameMode, ArenaMemWeightMode memWeightMode, float tickRate) : _mutatorConfig(gameMode), _suspColGrid(gameMode) { +Arena::Arena(GameMode gameMode, const ArenaConfig& config, float tickRate) : _mutatorConfig(gameMode), _config(config), _suspColGrid(gameMode) { // Tickrate must be from 15 to 120tps assert(tickRate >= 15 && tickRate <= 120); @@ -433,7 +433,8 @@ Arena::Arena(GameMode gameMode, ArenaMemWeightMode memWeightMode, float tickRate btDefaultCollisionConstructionInfo collisionConfigConstructionInfo = {}; // These take up a ton of memory normally - if (memWeightMode == ArenaMemWeightMode::LIGHT) { + // TODO: Heavy is slow + if (_config.memWeightMode == ArenaMemWeightMode::LIGHT) { collisionConfigConstructionInfo.m_defaultMaxPersistentManifoldPoolSize /= 16; collisionConfigConstructionInfo.m_defaultMaxCollisionAlgorithmPoolSize /= 32; } else { @@ -447,23 +448,14 @@ Arena::Arena(GameMode gameMode, ArenaMemWeightMode memWeightMode, float tickRate _bulletWorldParams.constraintSolver = btSequentialImpulseConstraintSolver(); _bulletWorldParams.overlappingPairCache = new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache), 16)) btHashedOverlappingPairCache(); - - // TODO: Move to... somewhere! Maybe make ArenaConfig or something. - constexpr int - MAX_X = 4500, - MAX_Y = 6000, - MAX_Z = 2500, - - CELL_SIZE = 350, - MAX_OBJ_COUNT = 1024; - if (_mutatorConfig.useCustomBroadphase) { + if (_config.useCustomBroadphase) { _bulletWorldParams.broadphase = new btRSBroadphase( - btVector3(-MAX_X, -MAX_Y, 0) * UU_TO_BT, - btVector3(MAX_X, MAX_Y, MAX_Z) * UU_TO_BT, - CELL_SIZE * UU_TO_BT, + _config.minPos * UU_TO_BT, + _config.maxPos * UU_TO_BT, + _config.maxAABBLen * UU_TO_BT, _bulletWorldParams.overlappingPairCache, - MAX_OBJ_COUNT); + _config.maxObjects); } else { _bulletWorldParams.broadphase = new btDbvtBroadphase(_bulletWorldParams.overlappingPairCache); } @@ -512,7 +504,7 @@ Arena::Arena(GameMode gameMode, ArenaMemWeightMode memWeightMode, float tickRate { // Initialize ball ball = Ball::_AllocBall(); - ball->_BulletSetup(gameMode, &_bulletWorld, _mutatorConfig); + ball->_BulletSetup(gameMode, &_bulletWorld, _mutatorConfig, _config.noBallRot); ball->SetState(BallState()); } @@ -548,12 +540,14 @@ Arena::Arena(GameMode gameMode, ArenaMemWeightMode memWeightMode, float tickRate gContactAddedCallback = &Arena::_BulletContactAddedCallback; } -Arena* Arena::Create(GameMode gameMode, ArenaMemWeightMode memWeightMode, float tickRate) { - return new Arena(gameMode, memWeightMode, tickRate); +Arena* Arena::Create(GameMode gameMode, const ArenaConfig& arenaConfig, float tickRate) { + return new Arena(gameMode, arenaConfig, tickRate); } void Arena::Serialize(DataStreamOut& out) const { - out.WriteMultiple(gameMode, tickTime, tickCount, _lastCarID, _memWeightMode); + out.WriteMultiple(gameMode, tickTime, tickCount, _lastCarID); + + _config.Serialize(out); { // Serialize cars out.Write(_cars.size()); @@ -588,9 +582,12 @@ Arena* Arena::DeserializeNew(DataStreamIn& in) { uint32_t lastCarID; ArenaMemWeightMode memWeightMode; - in.ReadMultiple(gameMode, tickTime, tickCount, lastCarID, memWeightMode); + in.ReadMultiple(gameMode, tickTime, tickCount, lastCarID); + + ArenaConfig newConfig = {}; + newConfig.Deserialize(in); - Arena* newArena = new Arena(gameMode, memWeightMode, 1.f / tickTime); + Arena* newArena = new Arena(gameMode, newConfig, 1.f / tickTime); newArena->tickCount = tickCount; { // Deserialize cars @@ -649,7 +646,7 @@ Arena* Arena::DeserializeNew(DataStreamIn& in) { } Arena* Arena::Clone(bool copyCallbacks) { - Arena* newArena = new Arena(this->gameMode, this->_memWeightMode, this->GetTickRate()); + Arena* newArena = new Arena(this->gameMode, this->_config, this->GetTickRate()); if (copyCallbacks) { newArena->_goalScoreCallback = this->_goalScoreCallback; diff --git a/src/Sim/Arena/Arena.h b/src/Sim/Arena/Arena.h index dd2930ec..39d6656e 100644 --- a/src/Sim/Arena/Arena.h +++ b/src/Sim/Arena/Arena.h @@ -9,6 +9,7 @@ #include "../BoostPad/BoostPadGrid/BoostPadGrid.h" #include "../SuspensionCollisionGrid/SuspensionCollisionGrid.h" #include "../MutatorConfig/MutatorConfig.h" +#include "ArenaConfig/ArenaConfig.h" #include "../../../libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h" #include "../../../libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.h" @@ -20,13 +21,6 @@ RS_NS_START -// Mode of speed/memory optimization for the arena -// Will affect whether high memory consumption is used to slightly increase speed or not -enum class ArenaMemWeightMode : byte { - HEAVY, // ~611KB per arena with 4 cars - LIGHT // ~397KB per arena with 4 cars -}; - typedef std::function GoalScoreEventFn; typedef std::function CarBumpEventFn; @@ -114,7 +108,7 @@ class Arena { RSAPI void SetCarBumpCallback(CarBumpEventFn callbackFn, void* userInfo = NULL); // NOTE: Arena should be destroyed after use - RSAPI static Arena* Create(GameMode gameMode, ArenaMemWeightMode memWeightMode = ArenaMemWeightMode::HEAVY, float tickRate = 120); + RSAPI static Arena* Create(GameMode gameMode, const ArenaConfig& arenaConfig = {}, float tickRate = 120); // Serialize entire arena state including cars, ball, and boostpads RSAPI void Serialize(DataStreamOut& out) const; @@ -187,17 +181,22 @@ class Arena { void _BtCallback_OnCarCarCollision(Car* car1, Car* car2, btManifoldPoint& manifoldPoint); void _BtCallback_OnCarWorldCollision(Car* car, btCollisionObject* worldObject, btManifoldPoint& manifoldPoint); + const ArenaConfig& GetArenaConfig() const { + return _config; + } + + // Backwards compatability ArenaMemWeightMode GetMemWeightMode() { - return _memWeightMode; + return _config.memWeightMode; } private: // Constructor for use by Arena::Create() - Arena(GameMode gameMode, ArenaMemWeightMode memWeightMode, float tickRate = 120); + Arena(GameMode gameMode, const ArenaConfig& config, float tickRate = 120); - // Making this private because horrible memory overflows would happen if you changed it - ArenaMemWeightMode _memWeightMode; + // Making this private because horrible memory overflows can happen if you changed it + ArenaConfig _config; }; RS_NS_END \ No newline at end of file diff --git a/src/Sim/Arena/ArenaConfig/ArenaConfig.cpp b/src/Sim/Arena/ArenaConfig/ArenaConfig.cpp new file mode 100644 index 00000000..688e48d7 --- /dev/null +++ b/src/Sim/Arena/ArenaConfig/ArenaConfig.cpp @@ -0,0 +1,13 @@ +#include "ArenaConfig.h" + +RS_NS_START + +void ArenaConfig::Serialize(DataStreamOut& out) const { + out.WriteMultiple(ARENA_CONFIG_SERIALIZATION_FIELDS); +} + +void ArenaConfig::Deserialize(DataStreamIn& in) { + in.ReadMultiple(ARENA_CONFIG_SERIALIZATION_FIELDS); +} + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/Arena/ArenaConfig/ArenaConfig.h b/src/Sim/Arena/ArenaConfig/ArenaConfig.h new file mode 100644 index 00000000..bb1c1ef1 --- /dev/null +++ b/src/Sim/Arena/ArenaConfig/ArenaConfig.h @@ -0,0 +1,47 @@ +#pragma once +#include "../../../Math/MathTypes/MathTypes.h" +#include "../../../DataStream/DataStreamOut.h" +#include "../../../DataStream/DataStreamIn.h" + +RS_NS_START + +// Mode of speed/memory optimization for the arena +// Will affect whether high memory consumption is used to slightly increase speed or not +enum class ArenaMemWeightMode : byte { + HEAVY, // ~611KB per arena with 4 cars + LIGHT // ~397KB per arena with 4 cars +}; + +struct ArenaConfig { + + ArenaMemWeightMode memWeightMode = ArenaMemWeightMode::LIGHT; + + // Mininimum and maximum positions all physics objects + Vec minPos = Vec(-4500, -6000, 0), + maxPos = Vec( 4500, 6000, 2500); + + // Maximum length of any object + // Calculated as the distance from AABB min to AABB max + float + maxAABBLen = 370; + + // Ball rotation updates are skipped to improve performance + // Disabled in snowday + bool noBallRot = true; + + // Use a custom broadphase designed for RocketSim + // Improves performance, but becomes inefficient on giant maps + // Turn this off if you want to use a giant map + bool useCustomBroadphase = true; + + // Maximum number of objects + int maxObjects = 512; + + void Serialize(DataStreamOut& out) const; + void Deserialize(DataStreamIn& in); +}; + +#define ARENA_CONFIG_SERIALIZATION_FIELDS \ +minPos, maxPos, maxAABBLen, noBallRot, useCustomBroadphase + +RS_NS_END \ No newline at end of file diff --git a/src/Sim/Ball/Ball.cpp b/src/Sim/Ball/Ball.cpp index 8b5b0e9f..74128dcd 100644 --- a/src/Sim/Ball/Ball.cpp +++ b/src/Sim/Ball/Ball.cpp @@ -79,7 +79,7 @@ btCollisionShape* MakeBallCollisionShape(GameMode gameMode, const MutatorConfig& } } -void Ball::_BulletSetup(GameMode gameMode, btDynamicsWorld* bulletWorld, const MutatorConfig& mutatorConfig) { +void Ball::_BulletSetup(GameMode gameMode, btDynamicsWorld* bulletWorld, const MutatorConfig& mutatorConfig, bool noRot) { btVector3 localIneria; _collisionShape = MakeBallCollisionShape(gameMode, mutatorConfig, localIneria); @@ -103,8 +103,7 @@ void Ball::_BulletSetup(GameMode gameMode, btDynamicsWorld* bulletWorld, const M _rigidBody.m_rigidbodyFlags = 0; - if (mutatorConfig.noBallRot) - _rigidBody.m_noRot = true; + _rigidBody.m_noRot = noRot && (_collisionShape->getShapeType() == SPHERE_SHAPE_PROXYTYPE); bulletWorld->addRigidBody(&_rigidBody, btBroadphaseProxy::DefaultFilter | CollisionMasks::HOOPS_NET, btBroadphaseProxy::AllFilter); } diff --git a/src/Sim/Ball/Ball.h b/src/Sim/Ball/Ball.h index a0fadc5b..d73ebff9 100644 --- a/src/Sim/Ball/Ball.h +++ b/src/Sim/Ball/Ball.h @@ -61,7 +61,7 @@ class Ball { // For removal by Arena static void _DestroyBall(Ball* ball) { delete ball; } - void _BulletSetup(GameMode gameMode, btDynamicsWorld* bulletWorld, const MutatorConfig& mutatorConfig); + void _BulletSetup(GameMode gameMode, btDynamicsWorld* bulletWorld, const MutatorConfig& mutatorConfig, bool noRot); bool groundStickApplied = false; Vec _velocityImpulseCache = { 0,0,0 }; diff --git a/src/Sim/BallPredTracker/BallPredTracker.cpp b/src/Sim/BallPredTracker/BallPredTracker.cpp index 90a43d60..a2293f00 100644 --- a/src/Sim/BallPredTracker/BallPredTracker.cpp +++ b/src/Sim/BallPredTracker/BallPredTracker.cpp @@ -4,7 +4,7 @@ RS_NS_START BallPredTracker::BallPredTracker(Arena* arena, size_t numPredTicks) : numPredTicks(numPredTicks) { // Make ball pred arena - this->ballPredArena = Arena::Create(arena->gameMode, ArenaMemWeightMode::LIGHT, arena->GetTickRate()); + this->ballPredArena = Arena::Create(arena->gameMode, arena->GetArenaConfig(), arena->GetTickRate()); this->ballPredArena->tickCount = arena->tickCount; predData.reserve(numPredTicks); diff --git a/src/Sim/MutatorConfig/MutatorConfig.cpp b/src/Sim/MutatorConfig/MutatorConfig.cpp index 7798bf35..b0a3f3b7 100644 --- a/src/Sim/MutatorConfig/MutatorConfig.cpp +++ b/src/Sim/MutatorConfig/MutatorConfig.cpp @@ -31,10 +31,6 @@ MutatorConfig::MutatorConfig(GameMode gameMode) { carSpawnBoostAmount = 100; boostUsedPerSecond = 0; } - - if (gameMode == GameMode::SNOWDAY) { - noBallRot = false; - } } void MutatorConfig::Serialize(DataStreamOut& out) const { diff --git a/src/Sim/MutatorConfig/MutatorConfig.h b/src/Sim/MutatorConfig/MutatorConfig.h index 79f45361..e5645eff 100644 --- a/src/Sim/MutatorConfig/MutatorConfig.h +++ b/src/Sim/MutatorConfig/MutatorConfig.h @@ -13,7 +13,7 @@ enum class DemoMode : byte { DISABLED }; -struct MutatorConfig { +RSAPI struct MutatorConfig { Vec gravity = Vec(0, 0, RLConst::GRAVITY_Z); @@ -64,19 +64,10 @@ struct MutatorConfig { DemoMode demoMode = DemoMode::NORMAL; bool enableTeamDemos = false; - // Ball rotation updates are skipped to improve performance - // Disabled in snowday - bool noBallRot = true; - - // Use a custom broadphase designed for RocketSim - // Improves performance, but becomes inefficient on giant maps - // Turn this off if you want to use a giant map - bool useCustomBroadphase = true; - MutatorConfig(GameMode gameMode); - RSAPI void Serialize(DataStreamOut& out) const; - RSAPI void Deserialize(DataStreamIn& in); + void Serialize(DataStreamOut& out) const; + void Deserialize(DataStreamIn& in); }; #define MUTATOR_CONFIG_SERIALIZATION_FIELDS \ From 35bb23065070067f33537ece67017202702d30ff Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 9 May 2024 01:39:55 -0700 Subject: [PATCH 51/55] Add AABB caching for all collision shapes --- .../CollisionShapes/btCollisionShape.cpp | 70 ++++++++++++------- .../CollisionShapes/btCollisionShape.h | 12 +++- .../CollisionShapes/btTriangleMeshShape.cpp | 27 +++---- .../CollisionShapes/btTriangleMeshShape.h | 4 -- 4 files changed, 60 insertions(+), 53 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.cpp b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.cpp index 47c2bc01..95e33383 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.cpp @@ -4,8 +4,8 @@ Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -35,23 +35,43 @@ extern "C" } void btCollisionShape::getAabb(const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const { - switch (m_shapeType) { - case BOX_SHAPE_PROXYTYPE: - return ((btBoxShape*)this)->getAabb(t, aabbMin, aabbMax); - case TRIANGLE_SHAPE_PROXYTYPE: - return ((btTriangleShape*)this)->getAabb(t, aabbMin, aabbMax); - case SPHERE_SHAPE_PROXYTYPE: - return ((btSphereShape*)this)->getAabb(t, aabbMin, aabbMax); - case STATIC_PLANE_PROXYTYPE: - return ((btStaticPlaneShape*)this)->getAabb(t, aabbMin, aabbMax); - case TRIANGLE_MESH_SHAPE_PROXYTYPE: - return ((btTriangleMeshShape*)this)->getAabb(t, aabbMin, aabbMax); - case COMPOUND_SHAPE_PROXYTYPE: - return ((btCompoundShape*)this)->getAabb(t, aabbMin, aabbMax); - case CONVEX_HULL_SHAPE_PROXYTYPE: - return ((btConvexHullShape*)this)->getAabb(t, aabbMin, aabbMax); - default: - btAssert(false); + + if ((m_aabbCacheTrans != t) || !m_aabbCached) { + switch (m_shapeType) { + case BOX_SHAPE_PROXYTYPE: + ((btBoxShape*)this)->getAabb(t, aabbMin, aabbMax); + break; + case TRIANGLE_SHAPE_PROXYTYPE: + ((btTriangleShape*)this)->getAabb(t, aabbMin, aabbMax); + break; + case SPHERE_SHAPE_PROXYTYPE: + ((btSphereShape*)this)->getAabb(t, aabbMin, aabbMax); + break; + case STATIC_PLANE_PROXYTYPE: + ((btStaticPlaneShape*)this)->getAabb(t, aabbMin, aabbMax); + break; + case TRIANGLE_MESH_SHAPE_PROXYTYPE: + ((btTriangleMeshShape*)this)->getAabb(t, aabbMin, aabbMax); + break; + case COMPOUND_SHAPE_PROXYTYPE: + ((btCompoundShape*)this)->getAabb(t, aabbMin, aabbMax); + break; + case CONVEX_HULL_SHAPE_PROXYTYPE: + ((btConvexHullShape*)this)->getAabb(t, aabbMin, aabbMax); + break; + default: + btAssert(false); + } + + // TODO: Dumb const bypass hack + auto _this = (btCollisionShape*)this; + _this->m_aabbCached = true; + _this->m_aabbMinCache = aabbMin; + _this->m_aabbMaxCache = aabbMax; + _this->m_aabbCacheTrans = t; + } else { + aabbMin = m_aabbMinCache; + aabbMax = m_aabbMaxCache; } } @@ -95,8 +115,7 @@ void btCollisionShape::setMargin(btScalar margin) { } } -void btCollisionShape::getBoundingSphere(btVector3& center, btScalar& radius) const -{ +void btCollisionShape::getBoundingSphere(btVector3& center, btScalar& radius) const { switch (m_shapeType) { case SPHERE_SHAPE_PROXYTYPE: center = btVector3(0, 0, 0); @@ -114,13 +133,11 @@ void btCollisionShape::getBoundingSphere(btVector3& center, btScalar& radius) co } } -btScalar btCollisionShape::getContactBreakingThreshold(btScalar defaultContactThreshold) const -{ +btScalar btCollisionShape::getContactBreakingThreshold(btScalar defaultContactThreshold) const { return getAngularMotionDisc() * defaultContactThreshold; } -btScalar btCollisionShape::getAngularMotionDisc() const -{ +btScalar btCollisionShape::getAngularMotionDisc() const { ///@todo cache this value, to improve performance btVector3 center; btScalar disc; @@ -129,8 +146,7 @@ btScalar btCollisionShape::getAngularMotionDisc() const return disc; } -void btCollisionShape::calculateTemporalAabb(const btTransform& curTrans, const btVector3& linvel, const btVector3& angvel, btScalar timeStep, btVector3& temporalAabbMin, btVector3& temporalAabbMax) const -{ +void btCollisionShape::calculateTemporalAabb(const btTransform& curTrans, const btVector3& linvel, const btVector3& angvel, btScalar timeStep, btVector3& temporalAabbMin, btVector3& temporalAabbMax) const { //start with static aabb getAabb(curTrans, temporalAabbMin, temporalAabbMax); diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.h b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.h index e77d2801..10d12f81 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.h +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.h @@ -25,16 +25,22 @@ subject to the following restrictions: ATTRIBUTE_ALIGNED16(class) btCollisionShape { -protected: +public: + int m_shapeType; void* m_userPointer; int m_userIndex; int m_userIndex2; -public: + bool m_aabbCached; + btVector3 m_aabbMinCache, m_aabbMaxCache; + btTransform m_aabbCacheTrans; + BT_DECLARE_ALIGNED_ALLOCATOR(); - btCollisionShape() : m_shapeType(INVALID_SHAPE_PROXYTYPE), m_userPointer(0), m_userIndex(-1), m_userIndex2(-1) + btCollisionShape() : + m_shapeType(INVALID_SHAPE_PROXYTYPE), m_userPointer(0), m_userIndex(-1), m_userIndex2(-1), + m_aabbCached(false) { } diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp index dfda91fb..dceefdcb 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp @@ -42,28 +42,17 @@ btTriangleMeshShape::~btTriangleMeshShape() void btTriangleMeshShape::getAabb(const btTransform& trans, btVector3& aabbMin, btVector3& aabbMax) { - if (!m_aabbCached || m_aabbCacheTrans != trans) { - btVector3 localHalfExtents = btScalar(0.5) * (m_localAabbMax - m_localAabbMin); - localHalfExtents += btVector3(getMargin(), getMargin(), getMargin()); - btVector3 localCenter = btScalar(0.5) * (m_localAabbMax + m_localAabbMin); + btVector3 localHalfExtents = btScalar(0.5) * (m_localAabbMax - m_localAabbMin); + localHalfExtents += btVector3(getMargin(), getMargin(), getMargin()); + btVector3 localCenter = btScalar(0.5) * (m_localAabbMax + m_localAabbMin); - btMatrix3x3 abs_b = trans.getBasis().absolute(); + btMatrix3x3 abs_b = trans.getBasis().absolute(); - btVector3 center = trans(localCenter); + btVector3 center = trans(localCenter); - btVector3 extent = localHalfExtents.dot3(abs_b[0], abs_b[1], abs_b[2]); - btVector3 - newMin = center - extent, - newMax = center + extent; - - m_aabbMinCache = newMin; - m_aabbMaxCache = newMax; - m_aabbCacheTrans = trans; - m_aabbCached = true; - } - - aabbMin = m_aabbMinCache; - aabbMax = m_aabbMaxCache; + btVector3 extent = localHalfExtents.dot3(abs_b[0], abs_b[1], abs_b[2]); + aabbMin = center - extent; + aabbMax = center + extent; } void btTriangleMeshShape::recalcLocalAabb() diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.h b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.h index bcc4dac4..677a79e9 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.h +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btTriangleMeshShape.h @@ -28,10 +28,6 @@ btTriangleMeshShape : public btConcaveShape btVector3 m_localAabbMax; btStridingMeshInterface* m_meshInterface; - bool m_aabbCached = false; - btVector3 m_aabbMinCache, m_aabbMaxCache; - btTransform m_aabbCacheTrans; - ///btTriangleMeshShape constructor has been disabled/protected, so that users will not mistakenly use this class. ///Don't use btTriangleMeshShape but use btBvhTriangleMeshShape instead! btTriangleMeshShape(btStridingMeshInterface * meshInterface); From a741141d04da9a669791d4735173540e6a0608c9 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 9 May 2024 01:54:56 -0700 Subject: [PATCH 52/55] Add faster checks in btCollisionShape::getAabb() --- .../CollisionShapes/btCollisionShape.cpp | 14 +++++++++++++- .../CollisionShapes/btCollisionShape.h | 5 ++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.cpp b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.cpp index 95e33383..9e53e0aa 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.cpp @@ -36,7 +36,19 @@ extern "C" void btCollisionShape::getAabb(const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const { - if ((m_aabbCacheTrans != t) || !m_aabbCached) { + // If we're a sphere, its faster to just re-calculate + if (m_shapeType == SPHERE_SHAPE_PROXYTYPE) + return ((btSphereShape*)this)->getAabb(t, aabbMin, aabbMax); + + constexpr auto fnFastCompareTransforms = [](const btTransform& a, const btTransform& b) -> bool { + return + (a.m_origin == b.m_origin) && + (a.m_basis[0] == b.m_basis[0]) && + (a.m_basis[1] == b.m_basis[1]); + // Don't need to compare the last row of the basis + }; + + if (!fnFastCompareTransforms(t, m_aabbCacheTrans) || !m_aabbCached) { switch (m_shapeType) { case BOX_SHAPE_PROXYTYPE: ((btBoxShape*)this)->getAabb(t, aabbMin, aabbMax); diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.h b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.h index 10d12f81..25255699 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.h +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btCollisionShape.h @@ -32,15 +32,14 @@ btCollisionShape int m_userIndex; int m_userIndex2; - bool m_aabbCached; + bool m_aabbCached = false; btVector3 m_aabbMinCache, m_aabbMaxCache; btTransform m_aabbCacheTrans; BT_DECLARE_ALIGNED_ALLOCATOR(); btCollisionShape() : - m_shapeType(INVALID_SHAPE_PROXYTYPE), m_userPointer(0), m_userIndex(-1), m_userIndex2(-1), - m_aabbCached(false) + m_shapeType(INVALID_SHAPE_PROXYTYPE), m_userPointer(0), m_userIndex(-1), m_userIndex2(-1) { } From fac1266fb13020f4ef64c0531b7cc4d5502b97ff Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 9 May 2024 01:58:55 -0700 Subject: [PATCH 53/55] Fix light arenas out-performing heavy arenas, greatly increase cell size on heavy arenas --- src/Sim/Arena/Arena.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Sim/Arena/Arena.cpp b/src/Sim/Arena/Arena.cpp index 828ffca3..99a83c9c 100644 --- a/src/Sim/Arena/Arena.cpp +++ b/src/Sim/Arena/Arena.cpp @@ -433,13 +433,12 @@ Arena::Arena(GameMode gameMode, const ArenaConfig& config, float tickRate) : _mu btDefaultCollisionConstructionInfo collisionConfigConstructionInfo = {}; // These take up a ton of memory normally - // TODO: Heavy is slow if (_config.memWeightMode == ArenaMemWeightMode::LIGHT) { + collisionConfigConstructionInfo.m_defaultMaxPersistentManifoldPoolSize /= 32; + collisionConfigConstructionInfo.m_defaultMaxCollisionAlgorithmPoolSize /= 64; + } else { collisionConfigConstructionInfo.m_defaultMaxPersistentManifoldPoolSize /= 16; collisionConfigConstructionInfo.m_defaultMaxCollisionAlgorithmPoolSize /= 32; - } else { - collisionConfigConstructionInfo.m_defaultMaxPersistentManifoldPoolSize /= 8; - collisionConfigConstructionInfo.m_defaultMaxCollisionAlgorithmPoolSize /= 16; } _bulletWorldParams.collisionConfig.setup(collisionConfigConstructionInfo); @@ -450,10 +449,16 @@ Arena::Arena(GameMode gameMode, const ArenaConfig& config, float tickRate) : _mu _bulletWorldParams.overlappingPairCache = new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache), 16)) btHashedOverlappingPairCache(); if (_config.useCustomBroadphase) { + float cellSizeMultiplier = 1; + if (_config.memWeightMode == ArenaMemWeightMode::LIGHT) { + // Increase cell size + cellSizeMultiplier = 2.0f; + } + _bulletWorldParams.broadphase = new btRSBroadphase( _config.minPos * UU_TO_BT, _config.maxPos * UU_TO_BT, - _config.maxAABBLen * UU_TO_BT, + _config.maxAABBLen * UU_TO_BT * cellSizeMultiplier, _bulletWorldParams.overlappingPairCache, _config.maxObjects); } else { From 4bc458b0d727bc93c091eccf6ce7675ded21660c Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 9 May 2024 02:01:09 -0700 Subject: [PATCH 54/55] Update ArenaMemWeightMode memory estimates --- src/Sim/Arena/ArenaConfig/ArenaConfig.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Sim/Arena/ArenaConfig/ArenaConfig.h b/src/Sim/Arena/ArenaConfig/ArenaConfig.h index bb1c1ef1..82d1d662 100644 --- a/src/Sim/Arena/ArenaConfig/ArenaConfig.h +++ b/src/Sim/Arena/ArenaConfig/ArenaConfig.h @@ -8,8 +8,9 @@ RS_NS_START // Mode of speed/memory optimization for the arena // Will affect whether high memory consumption is used to slightly increase speed or not enum class ArenaMemWeightMode : byte { - HEAVY, // ~611KB per arena with 4 cars - LIGHT // ~397KB per arena with 4 cars + HEAVY, // ~1,263KB per arena with 4 cars + LIGHT // ~383KB per arena with 4 cars + // Measurements last updated 2024/5/9 }; struct ArenaConfig { From 91fe7575459a92c3194602dc8df619cd7f4ede06 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 9 May 2024 12:00:22 -0700 Subject: [PATCH 55/55] [v2.1.0] Update version number, self-merge from dev --- README.md | 14 ++++++-------- src/Framework.h | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4de55034..87dcb1bf 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,11 @@ RocketSim supports the game modes: Soccar, Hoops, Heatseeker, and Snowday. # Speed RocketSim is designed to run extremely fast, even when complex collisions and suspension calculations are happening every tick. -On an average PC running a single thread of RocketSim with two cars, RocketSim can simulate around 10 minutes of game time every second. -This means that with 12 threads running RocketSim, you can simulate around 5 days of game time every minute! +On an average PC running a single thread of RocketSim with two cars, RocketSim can simulate around 20 minutes of game time every second. +This means that with 12 threads running RocketSim, you can simulate around 10 days of game time every minute! # Accuracy -RocketSim is not a perfectly accurate replication of Rocket League, but is close enough for most applications. +RocketSim is not a perfectly accurate replication of Rocket League, but is close enough for most applications (such as training ML bots). Perceivable differences between the simulation and the real game usually take at least a second to accumulate from an initial state. This means RocketSim is accurate enough to: - *Train machine learning bots* @@ -20,7 +20,7 @@ This means RocketSim is accurate enough to: - *Simulate ground and floor pinches* However, RocketSim is NOT accurate enough to: -- *Simulate entire games from inputs alone* +- *Accurately re-create entire games from inputs alone* - *Perfectly simulate long sequences of jumps and landings* ## Installation @@ -57,12 +57,10 @@ Single-thread performance (calculated using average CPU cycles per tick on the R v1.0.0 = 30,334tps v1.1.0 = 48,191tps v1.2.0 = 50,763tps +v2.0.0 = ~50,000tps +v2.1.0 = 114,481tps ``` -## Simulation Accuracy -RocketSim is not perfectly accurate, but it's close enough that it shouldn't matter (for ML bots or humans). -Bots that work well in RocketSim will work well in the actual game and visa-versa. - ## Issues & PRs Feel free to make issues and pull requests if you encounter any issues! diff --git a/src/Framework.h b/src/Framework.h index 1f843df2..d789d3c5 100644 --- a/src/Framework.h +++ b/src/Framework.h @@ -1,6 +1,6 @@ #pragma once -#define RS_VERSION "pre-2.1.0" +#define RS_VERSION "2.1.0" #include #include