bool TileCachedRecastMeshManager::addTile(const ObjectId id, const btCollisionShape& shape,
     const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, float border,
     std::map<TilePosition, CachedRecastMeshManager>& tiles)
 {
     auto tile = tiles.find(tilePosition);
     if (tile == tiles.end())
     {
         auto tileBounds = makeTileBounds(mSettings, tilePosition);
         tileBounds.mMin -= osg::Vec2f(border, border);
         tileBounds.mMax += osg::Vec2f(border, border);
         tile = tiles.insert(std::make_pair(tilePosition, CachedRecastMeshManager(mSettings, tileBounds))).first;
     }
     return tile->second.addObject(id, shape, transform, areaType);
 }
    bool TileCachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize,
        const btTransform& transform)
    {
        const auto border = getBorderSize(mSettings);

        auto& tilesPositions = mWaterTilesPositions[cellPosition];

        bool result = false;

        if (cellSize == std::numeric_limits<int>::max())
        {
            const auto tiles = mTiles.lock();
            for (auto& tile : *tiles)
            {
                if (tile.second.addWater(cellPosition, cellSize, transform))
                {
                    tilesPositions.push_back(tile.first);
                    result = true;
                }
            }
        }
        else
        {
            getTilesPositions(cellSize, transform, mSettings, [&] (const TilePosition& tilePosition)
                {
                    const auto tiles = mTiles.lock();
                    auto tile = tiles->find(tilePosition);
                    if (tile == tiles->end())
                    {
                        auto tileBounds = makeTileBounds(mSettings, tilePosition);
                        tileBounds.mMin -= osg::Vec2f(border, border);
                        tileBounds.mMax += osg::Vec2f(border, border);
                        tile = tiles->insert(std::make_pair(tilePosition,
                                CachedRecastMeshManager(mSettings, tileBounds))).first;
                    }
                    if (tile->second.addWater(cellPosition, cellSize, transform))
                    {
                        tilesPositions.push_back(tilePosition);
                        result = true;
                    }
                });
        }

        if (result)
            ++mRevision;

        return result;
    }
Esempio n. 3
0
    UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh* recastMesh,
        const TilePosition& changedTile, const TilePosition& playerTile,
        const std::vector<OffMeshConnection>& offMeshConnections, const Settings& settings,
        const SharedNavMeshCacheItem& navMeshCacheItem, NavMeshTilesCache& navMeshTilesCache)
    {
        log("update NavMesh with mutiple tiles:",
            " agentHeight=", std::setprecision(std::numeric_limits<float>::max_exponent10),
            getHeight(settings, agentHalfExtents),
            " agentMaxClimb=", std::setprecision(std::numeric_limits<float>::max_exponent10),
            getMaxClimb(settings),
            " agentRadius=", std::setprecision(std::numeric_limits<float>::max_exponent10),
            getRadius(settings, agentHalfExtents),
            " changedTile=", changedTile,
            " playerTile=", playerTile,
            " changedTileDistance=", getDistance(changedTile, playerTile));

        const auto params = *navMeshCacheItem.lockConst()->getValue().getParams();
        const osg::Vec3f origin(params.orig[0], params.orig[1], params.orig[2]);

        const auto x = changedTile.x();
        const auto y = changedTile.y();

        const auto removeTile = [&] {
            const auto locked = navMeshCacheItem.lock();
            auto& navMesh = locked->getValue();
            const auto tileRef = navMesh.getTileRefAt(x, y, 0);
            const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, nullptr, nullptr));
            if (removed)
                locked->removeUsedTile(changedTile);
            return makeUpdateNavMeshStatus(removed, false);
        };

        if (!recastMesh)
        {
            log("ignore add tile: recastMesh is null");
            return removeTile();
        }

        auto recastMeshBounds = recastMesh->getBounds();

        for (const auto& water : recastMesh->getWater())
        {
            const auto waterBounds = getWaterBounds(water, settings, agentHalfExtents);
            recastMeshBounds.mMin.y() = std::min(recastMeshBounds.mMin.y(), waterBounds.mMin.y());
            recastMeshBounds.mMax.y() = std::max(recastMeshBounds.mMax.y(), waterBounds.mMax.y());
        }

        if (isEmpty(recastMeshBounds))
        {
            log("ignore add tile: recastMesh is empty");
            return removeTile();
        }

        if (!shouldAddTile(changedTile, playerTile, params.maxTiles))
        {
            log("ignore add tile: too far from player");
            return removeTile();
        }

        auto cachedNavMeshData = navMeshTilesCache.get(agentHalfExtents, changedTile, *recastMesh, offMeshConnections);

        if (!cachedNavMeshData)
        {
            const auto tileBounds = makeTileBounds(settings, changedTile);
            const osg::Vec3f tileBorderMin(tileBounds.mMin.x(), recastMeshBounds.mMin.y() - 1, tileBounds.mMin.y());
            const osg::Vec3f tileBorderMax(tileBounds.mMax.x(), recastMeshBounds.mMax.y() + 1, tileBounds.mMax.y());

            auto navMeshData = makeNavMeshTileData(agentHalfExtents, *recastMesh, offMeshConnections, changedTile,
                tileBorderMin, tileBorderMax, settings);

            if (!navMeshData.mValue)
            {
                log("ignore add tile: NavMeshData is null");
                return removeTile();
            }

            try
            {
                cachedNavMeshData = navMeshTilesCache.set(agentHalfExtents, changedTile, *recastMesh,
                                                          offMeshConnections, std::move(navMeshData));
            }
            catch (const InvalidArgument&)
            {
                cachedNavMeshData = navMeshTilesCache.get(agentHalfExtents, changedTile, *recastMesh,
                                                          offMeshConnections);
            }

            if (!cachedNavMeshData)
            {
                log("cache overflow");

                const auto locked = navMeshCacheItem.lock();
                auto& navMesh = locked->getValue();
                const auto tileRef = navMesh.getTileRefAt(x, y, 0);
                const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, nullptr, nullptr));
                const auto addStatus = navMesh.addTile(navMeshData.mValue.get(), navMeshData.mSize,
                                                       doNotTransferOwnership, 0, 0);

                if (dtStatusSucceed(addStatus))
                {
                    locked->setUsedTile(changedTile, std::move(navMeshData));
                    return makeUpdateNavMeshStatus(removed, true);
                }
                else
                {
                    if (removed)
                        locked->removeUsedTile(changedTile);
                    log("failed to add tile with status=", WriteDtStatus {addStatus});
                    return makeUpdateNavMeshStatus(removed, false);
                }
            }
        }

        const auto locked = navMeshCacheItem.lock();
        auto& navMesh = locked->getValue();
        const auto tileRef = navMesh.getTileRefAt(x, y, 0);
        const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, nullptr, nullptr));
        const auto addStatus = navMesh.addTile(cachedNavMeshData.get().mValue, cachedNavMeshData.get().mSize,
                                               doNotTransferOwnership, 0, 0);

        if (dtStatusSucceed(addStatus))
        {
            locked->setUsedTile(changedTile, std::move(cachedNavMeshData));
            return makeUpdateNavMeshStatus(removed, true);
        }
        else
        {
            if (removed)
                locked->removeUsedTile(changedTile);
            log("failed to add tile with status=", WriteDtStatus {addStatus});
            return makeUpdateNavMeshStatus(removed, false);
        }
    }