From b86e7d7120de43c39c67ff4b9315dcef96072d97 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Tue, 14 May 2024 02:58:01 -0700 Subject: [PATCH 1/3] Support loading arena meshes from memory instead of file system --- src/CollisionMeshFile/CollisionMeshFile.cpp | 7 +- src/CollisionMeshFile/CollisionMeshFile.h | 4 +- src/RocketSim.cpp | 112 +++++++++++++------- src/RocketSim.h | 9 ++ 4 files changed, 88 insertions(+), 44 deletions(-) diff --git a/src/CollisionMeshFile/CollisionMeshFile.cpp b/src/CollisionMeshFile/CollisionMeshFile.cpp index 2db589e6..37cdf35d 100644 --- a/src/CollisionMeshFile/CollisionMeshFile.cpp +++ b/src/CollisionMeshFile/CollisionMeshFile.cpp @@ -8,11 +8,10 @@ RS_NS_START -void CollisionMeshFile::ReadFromFile(std::string filePath) { - constexpr char ERROR_PREFIX_STR[] = " > CollisionMeshFile::ReadFromFile(): "; - - DataStreamIn in = DataStreamIn(filePath, false); +void CollisionMeshFile::ReadFromStream(DataStreamIn& in, std::string filePath) { + constexpr char ERROR_PREFIX_STR[] = " > CollisionMeshFile::ReadFromStream(): "; + // If you have more verts or tris then this, I have no idea what you are doing, godspeed constexpr int MAX_VERT_OR_TRI_COUNT = 1000 * 1000; // Read triangle/vertex counts diff --git a/src/CollisionMeshFile/CollisionMeshFile.h b/src/CollisionMeshFile/CollisionMeshFile.h index 7c0cd1b3..971245a8 100644 --- a/src/CollisionMeshFile/CollisionMeshFile.h +++ b/src/CollisionMeshFile/CollisionMeshFile.h @@ -2,6 +2,8 @@ #include "../Framework.h" #include "../BulletLink.h" +#include "../DataStream/DataStreamIn.h" + #define COLLISION_MESH_BASE_PATH "./collision_meshes/" #define COLLISION_MESH_FILE_EXTENSION ".cmf" @@ -30,7 +32,7 @@ struct CollisionMeshFile { uint32_t hash; - void ReadFromFile(std::string filePath); + void ReadFromStream(DataStreamIn& in, std::string filePath = ""); btTriangleMesh* MakeBulletMesh(); void UpdateHash(); }; diff --git a/src/RocketSim.cpp b/src/RocketSim.cpp index 34b7ed37..85cf83ec 100644 --- a/src/RocketSim.cpp +++ b/src/RocketSim.cpp @@ -69,8 +69,42 @@ static SuspensionCollisionGrid void RocketSim::Init(std::filesystem::path collisionMeshesFolder) { + std::map> meshFileMap = {}; + + for (int i = 0; i < 2; i++) { // Load collision meshes for soccar and hoops + GameMode gameMode = (i > 0) ? GameMode::HOOPS : GameMode::SOCCAR; + auto& meshes = GetArenaCollisionShapes(gameMode); + + std::filesystem::path basePath = collisionMeshesFolder; + std::filesystem::path soccarMeshesFolder = basePath / GAMEMODE_STRS[(int)gameMode]; + + if (!std::filesystem::exists(soccarMeshesFolder)) + continue; + + MeshHashSet targetHashes = MeshHashSet(gameMode); + + // Load collision meshes + auto dirItr = std::filesystem::directory_iterator(soccarMeshesFolder); + for (auto& entry : dirItr) { + auto entryPath = entry.path(); + if (entryPath.has_extension() && entryPath.extension() == COLLISION_MESH_FILE_EXTENSION) { + DataStreamIn streamIn = DataStreamIn(entryPath, false); + meshFileMap[gameMode].push_back(streamIn.data); + } + } + } + + RocketSim::InitFromMem(meshFileMap); + + _collisionMeshesFolder = collisionMeshesFolder; +} + +void RocketSim::InitFromMem(const std::map>& meshFilesMap) { + constexpr char MSG_PREFIX[] = "RocketSim::Init(): "; + _collisionMeshesFolder = ""; + _beginInitMutex.lock(); { if (stage != RocketSimStage::UNINITIALIZED) { @@ -81,56 +115,56 @@ void RocketSim::Init(std::filesystem::path collisionMeshesFolder) { RS_LOG("Initializing RocketSim version " RS_VERSION ", created by ZealanL..."); - _collisionMeshesFolder = collisionMeshesFolder; + stage = RocketSimStage::INITIALIZING; uint64_t startMS = RS_CUR_MS(); - for (int i = 0; i < 2; i++) { // Load collision meshes for soccar and hoops - GameMode gameMode = (i > 0) ? GameMode::HOOPS : GameMode::SOCCAR; - auto& meshes = GetArenaCollisionShapes(gameMode); - - std::filesystem::path basePath = collisionMeshesFolder; - std::filesystem::path soccarMeshesFolder = basePath / GAMEMODE_STRS[(int)gameMode]; + for (auto& mapPair : meshFilesMap) { // Load collision meshes for soccar and hoops + GameMode gameMode = mapPair.first; + auto& meshFiles = mapPair.second; - RS_LOG("Loading arena meshes from " << soccarMeshesFolder << "..."); + RS_LOG("Loading arena meshes for " << GAMEMODE_STRS[(int)gameMode] << "..."); - if (!std::filesystem::exists(soccarMeshesFolder)) { - RS_LOG("No arena meshes for " << GAMEMODE_STRS[(int)gameMode] << ", skipping..."); + if (meshFiles.empty()) { + RS_LOG(" > No meshes, skipping"); continue; } + auto& meshes = GetArenaCollisionShapes(gameMode); + MeshHashSet targetHashes = MeshHashSet(gameMode); // Load collision meshes - auto dirItr = std::filesystem::directory_iterator(soccarMeshesFolder); - for (auto& entry : dirItr) { - auto entryPath = entry.path(); - if (entryPath.has_extension() && entryPath.extension() == COLLISION_MESH_FILE_EXTENSION) { - CollisionMeshFile meshFile = {}; - meshFile.ReadFromFile(entryPath.string()); - int& hashCount = targetHashes[meshFile.hash]; - - if (hashCount > 0) { - RS_WARN(MSG_PREFIX << "Collision mesh " << entryPath << " is a duplicate (0x" << std::hex << meshFile.hash << "), " << - "already loaded a mesh with the same hash." - ); - } else if (targetHashes.hashes.count(meshFile.hash) == 0) { - RS_WARN(MSG_PREFIX << - "Collision mesh " << entryPath << " does not match any known soccar collision file (0x" << std::hex << meshFile.hash << "), " << - "make sure they were dumped from a normal soccar arena." - ) - } - hashCount++; - - btTriangleMesh* triMesh = meshFile.MakeBulletMesh(); - - auto bvtMesh = new btBvhTriangleMeshShape(triMesh, true); - btTriangleInfoMap* infoMap = new btTriangleInfoMap(); - btGenerateInternalEdgeInfo(bvtMesh, infoMap); - bvtMesh->setTriangleInfoMap(infoMap); - meshes.push_back(bvtMesh); + int idx = 0; + for (auto& entry : meshFiles) { + DataStreamIn dataStream = {}; + dataStream.data = entry; + CollisionMeshFile meshFile = {}; + meshFile.ReadFromStream(dataStream); + int& hashCount = targetHashes[meshFile.hash]; + + if (hashCount > 0) { + RS_WARN(MSG_PREFIX << "Collision mesh [" << idx << "] is a duplicate (0x" << std::hex << meshFile.hash << "), " << + "already loaded a mesh with the same hash." + ); + } else if (targetHashes.hashes.count(meshFile.hash) == 0) { + RS_WARN(MSG_PREFIX << + "Collision mesh [" << idx << "] does not match any known " << GAMEMODE_STRS[(int)gameMode] << " collision mesh (0x" << std::hex << meshFile.hash << "), " << + "make sure they were dumped from a normal " << GAMEMODE_STRS[(int)gameMode] << " arena." + ) } + hashCount++; + + btTriangleMesh* triMesh = meshFile.MakeBulletMesh(); + + auto bvtMesh = new btBvhTriangleMeshShape(triMesh, true); + btTriangleInfoMap* infoMap = new btTriangleInfoMap(); + btGenerateInternalEdgeInfo(bvtMesh, infoMap); + bvtMesh->setTriangleInfoMap(infoMap); + meshes.push_back(bvtMesh); + + idx++; } } @@ -151,8 +185,8 @@ void RocketSim::Init(std::filesystem::path collisionMeshesFolder) { auto& grid = GetDefaultSuspColGrid(gameMode, j); grid.Allocate(); grid.SetupWorldCollision(meshes); - } - } + } +} } } #endif diff --git a/src/RocketSim.h b/src/RocketSim.h index 4cfa4cc3..2c9b1dfd 100644 --- a/src/RocketSim.h +++ b/src/RocketSim.h @@ -20,10 +20,19 @@ namespace RocketSim { INITIALIZED }; + typedef std::vector FileData; + extern std::filesystem::path _collisionMeshesFolder; extern std::mutex _beginInitMutex; + void Init(std::filesystem::path collisionMeshesFolder); + + // Instead of loading a collision meshes folder, you can pass in the meshes in this memory-only format + // The map sorts mesh files to their respective game modes, where each game mode has a list of mesh files + // The mesh files themselves are just byte arrays + void InitFromMem(const std::map>& meshFilesMap); + void AssertInitialized(const char* errorMsgPrefix); RocketSimStage GetStage(); From 0e39f58c8746987ad6c2054b50b2bfa53c77061b Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 16 May 2024 15:09:09 -0700 Subject: [PATCH 2/3] Add comment to CarState.isOnGround --- src/Sim/Car/Car.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Sim/Car/Car.h b/src/Sim/Car/Car.h index 2fd61c19..c7cd6e1b 100644 --- a/src/Sim/Car/Car.h +++ b/src/Sim/Car/Car.h @@ -21,6 +21,7 @@ struct CarState : public PhysState { // Not serialized uint64_t updateCounter = 0; + // True if 3 or more wheels have contact bool isOnGround = true; // Whether each of the 4 wheels have contact From 25b27d764ee415bcbbde0fc5eaf39fad16e151e3 Mon Sep 17 00:00:00 2001 From: ZealanL Date: Thu, 16 May 2024 15:09:33 -0700 Subject: [PATCH 3/3] Fix custom broadphase not bleeding static meshes to surrounding cells --- .../BroadphaseCollision/btRSBroadphase.cpp | 37 +++++++++++++++---- .../CollisionShapes/btStaticPlaneShape.cpp | 2 +- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp index ba162376..68aaaed9 100644 --- a/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/BroadphaseCollision/btRSBroadphase.cpp @@ -126,9 +126,21 @@ void _UpdateCellsStatic(btRSBroadphase* _this, btRSBroadphaseProxy* proxy) { 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 0 // TODO: This check misses certain cells for some reason + std::vector cells = {}; + for (int i1 = -1; i1 <= 1; i1++) { + for (int j1 = -1; j1 <= 1; j1++) { + for (int k1 = -1; k1 <= 1; k1++) { + int ci = i + i1; + int cj = j + j1; + int ck = k + k1; + if (ci < 0 || cj < 0 || ck < 0) + continue; + if (ci >= _this->cellsX || cj >= _this->cellsY || ck >= _this->cellsZ) + continue; + cells.push_back(&_this->GetCell(ci, cj, ck)); + } + } + } if (isTriMesh) { auto triMeshShape = (btTriangleMeshShape*)colObj->m_collisionShape; @@ -148,12 +160,21 @@ void _UpdateCellsStatic(btRSBroadphase* _this, btRSBroadphaseProxy* proxy) { } } } -#endif - if (ADD) { - cell.staticHandles.push_back(proxy); - } else { - cell.RemoveStatic(proxy); + for (auto cell : cells) { + if (ADD) { + bool alreadyExists = false; + for (auto staticHandle : cell->staticHandles) { + if (staticHandle == proxy) { + alreadyExists = true; + break; + } + } + if (!alreadyExists) + cell->staticHandles.push_back(proxy); + } else { + cell->RemoveStatic(proxy); + } } } } diff --git a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp index 9bfb6214..3509391f 100644 --- a/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp +++ b/libsrc/bullet3-3.24/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp @@ -43,7 +43,7 @@ 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; + constexpr float PLANE_CONSTANT_OFFSET = 0.2f; if (m_isSingleAxis) { aabbMin[m_singleAxisIdx] = t.getOrigin()[m_singleAxisIdx] + (m_planeConstant - PLANE_CONSTANT_OFFSET);