Пример #1
0
        ulong GetPolyByLocation(float[] point, ref float distance)
        {
            // first we check the current path
            // if the current path doesn't contain the current poly,
            // we need to use the expensive navMesh.findNearestPoly
            ulong polyRef = GetPathPolyByPosition(_pathPolyRefs, _polyLength, point, ref distance);

            if (polyRef != 0)
            {
                return(polyRef);
            }

            // we don't have it in our old path
            // try to get it by findNearestPoly()
            // first try with low search box
            float[] extents      = { 3.0f, 5.0f, 3.0f }; // bounds of poly search area
            float[] closestPoint = { 0.0f, 0.0f, 0.0f };
            if (Detour.dtStatusSucceed(_navMeshQuery.findNearestPoly(point, extents, _filter, ref polyRef, ref closestPoint)) && polyRef != 0)
            {
                distance = Detour.dtVdist(closestPoint, point);
                return(polyRef);
            }

            // still nothing ..
            // try with bigger search box
            // Note that the extent should not overlap more than 128 polygons in the navmesh (see dtNavMeshQuery.findNearestPoly)
            extents[1] = 50.0f;
            if (Detour.dtStatusSucceed(_navMeshQuery.findNearestPoly(point, extents, _filter, ref polyRef, ref closestPoint)) && polyRef != 0)
            {
                distance = Detour.dtVdist(closestPoint, point);
                return(polyRef);
            }

            return(0);
        }
Пример #2
0
        void AddSwap(PhasedTile ptile, uint swap, uint packedXY)
        {
            uint x = (packedXY >> 16);
            uint y = (packedXY & 0x0000FFFF);

            if (!loadedTileRefs.ContainsKey(packedXY))
            {
                Log.outDebug(LogFilter.Maps, "MMapData.AddSwap: phased mmtile {0:D4}[{1:D2}, {2:D2}] load skipped, due to not loaded base tile on map {3}", swap, x, y, _mapId);
                return;
            }
            if (loadedPhasedTiles[swap].Contains(packedXY))
            {
                Log.outDebug(LogFilter.Maps, "MMapData.AddSwap: WARNING! phased mmtile {0:D4}[{1:D2}, {2:D2}] load skipped, due to already loaded on map {3}", swap, x, y, _mapId);
                return;
            }

            Detour.dtMeshHeader header = ptile.data.header;

            Detour.dtMeshTile oldTile = navMesh.getTileByRef(loadedTileRefs[packedXY]);
            if (oldTile == null)
            {
                Log.outDebug(LogFilter.Maps, "MMapData.AddSwap: phased mmtile {0:D4}[{1:D2}, {2:D2}] load skipped, due to not loaded base tile ref on map {3}", swap, x, y, _mapId);
                return;
            }

            // header xy is based on the swap map's tile set, wich doesn't have all the same tiles as root map, so copy the xy from the orignal header
            header.x = oldTile.header.x;
            header.y = oldTile.header.y;

            Detour.dtRawTileData data;
            // remove old tile
            if (Detour.dtStatusFailed(navMesh.removeTile(loadedTileRefs[packedXY], out data)))
            {
                Log.outError(LogFilter.Maps, "MMapData.AddSwap: Could not unload {0:D4}{1:D2}{2:D2}.mmtile from navmesh", _mapId, x, y);
            }
            else
            {
                Log.outDebug(LogFilter.Maps, "MMapData.AddSwap: Unloaded {0:D4}{1:D2}{2:D2}.mmtile from navmesh", _mapId, x, y);

                _activeSwaps.Add(swap);
                loadedPhasedTiles.Add(swap, packedXY);

                // add new swapped tile
                ulong loadedRef = 0;
                if (Detour.dtStatusSucceed(navMesh.addTile(ptile.data, 0, 0, ref loadedRef)))
                {
                    Log.outDebug(LogFilter.Maps, "MMapData.AddSwap: Loaded phased mmtile {0:D4}[{1:D2}, {2:D2}] into {0:D4}[{1:D2}, {2:D2}]", swap, x, y, _mapId, header.x, header.y);
                }
                else
                {
                    Log.outError(LogFilter.Maps, "MMapData.AddSwap: Could not load {0:D4}{1:D2}{2:D2}.mmtile to navmesh", swap, x, y);
                }

                loadedTileRefs[packedXY] = loadedRef;
            }
        }
Пример #3
0
        void RemoveSwap(PhasedTile ptile, uint swap, uint packedXY)
        {
            uint x = (packedXY >> 16);
            uint y = (packedXY & 0x0000FFFF);

            if (!loadedPhasedTiles[swap].Contains(packedXY))
            {
                Log.outDebug(LogFilter.Maps, "MMapData.RemoveSwap: mmtile {0:D4}[{1:D2}, {2:D2}] unload skipped, due to not loaded", swap, x, y);
                return;
            }
            Detour.dtMeshHeader header = ptile.data.header;

            Detour.dtRawTileData data;
            // remove old tile
            if (Detour.dtStatusFailed(navMesh.removeTile(loadedTileRefs[packedXY], out data)))
            {
                Log.outError(LogFilter.Maps, "MMapData.RemoveSwap: Could not unload phased {0:D4}{1:D2}{2:D2}.mmtile from navmesh", swap, x, y);
            }
            else
            {
                Log.outDebug(LogFilter.Maps, "MMapData.RemoveSwap: Unloaded phased {0:D4}{1:D2}{2:D2}.mmtile from navmesh", swap, x, y);

                // restore base tile
                ulong loadedRef = 0;
                if (Detour.dtStatusSucceed(navMesh.addTile(_baseTiles[packedXY].data, 0, 0, ref loadedRef)))
                {
                    Log.outDebug(LogFilter.Maps, "MMapData.RemoveSwap: Loaded base mmtile {0:D4}[{1:D2}, {2:D2}] into {0:D4}[{1:D2}, {2:D2}]", _mapId, x, y, _mapId, header.x, header.y);
                }
                else
                {
                    Log.outError(LogFilter.Maps, "MMapData.RemoveSwap: Could not load base {0:D4}{1:D2}{2:D2}.mmtile to navmesh", _mapId, x, y);
                }

                loadedTileRefs[packedXY] = loadedRef;
            }

            loadedPhasedTiles.Remove(swap, packedXY);

            if (loadedPhasedTiles[swap].Empty())
            {
                _activeSwaps.Remove(swap);
                Log.outDebug(LogFilter.Maps, "MMapData.RemoveSwap: Fully removed swap {0} from map {1}", swap, _mapId);
            }
        }
Пример #4
0
        uint FindSmoothPath(float[] startPos, float[] endPos, ulong[] polyPath, uint polyPathSize, out float[] smoothPath, out int smoothPathSize, uint maxSmoothPathSize)
        {
            smoothPathSize = 0;
            int nsmoothPath = 0;

            smoothPath = new float[74 * 3];

            ulong[] polys = new ulong[74];
            Array.Copy(polyPath, polys, polyPathSize);
            uint npolys = polyPathSize;

            float[] iterPos   = new float[3];
            float[] targetPos = new float[3];
            if (Detour.dtStatusFailed(_navMeshQuery.closestPointOnPolyBoundary(polys[0], startPos, iterPos)))
            {
                return(Detour.DT_FAILURE);
            }

            if (Detour.dtStatusFailed(_navMeshQuery.closestPointOnPolyBoundary(polys[npolys - 1], endPos, targetPos)))
            {
                return(Detour.DT_FAILURE);
            }

            Detour.dtVcopy(smoothPath, nsmoothPath * 3, iterPos, 0);
            nsmoothPath++;

            // Move towards target a small advancement at a time until target reached or
            // when ran out of memory to store the path.
            while (npolys != 0 && nsmoothPath < maxSmoothPathSize)
            {
                // Find location to steer towards.
                float[] steerPos;
                Detour.dtStraightPathFlags steerPosFlag;
                ulong steerPosRef = 0;

                if (!GetSteerTarget(iterPos, targetPos, 0.3f, polys, npolys, out steerPos, out steerPosFlag, out steerPosRef))
                {
                    break;
                }

                bool endOfPath         = steerPosFlag.HasAnyFlag(Detour.dtStraightPathFlags.DT_STRAIGHTPATH_END);
                bool offMeshConnection = steerPosFlag.HasAnyFlag(Detour.dtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION);

                // Find movement delta.
                float[] delta = new float[3];
                Detour.dtVsub(delta, steerPos, iterPos);
                float len = (float)Math.Sqrt(Detour.dtVdot(delta, delta));
                // If the steer target is end of path or off-mesh link, do not move past the location.
                if ((endOfPath || offMeshConnection) && len < 4.0f)
                {
                    len = 1.0f;
                }
                else
                {
                    len = 4.0f / len;
                }

                float[] moveTgt = new float[3];
                Detour.dtVmad(moveTgt, iterPos, delta, len);

                // Move
                float[] result         = new float[3];
                int     MAX_VISIT_POLY = 16;
                ulong[] visited        = new ulong[MAX_VISIT_POLY];

                int nvisited = 0;
                _navMeshQuery.moveAlongSurface(polys[0], iterPos, moveTgt, _filter, result, visited, ref nvisited, MAX_VISIT_POLY);
                npolys = FixupCorridor(polys, npolys, 74, visited, nvisited);

                _navMeshQuery.getPolyHeight(polys[0], result, ref result[1]);
                result[1] += 0.5f;
                Detour.dtVcopy(iterPos, result);

                // Handle end of path and off-mesh links when close enough.
                if (endOfPath && InRangeYZX(iterPos, steerPos, 0.3f, 1.0f))
                {
                    // Reached end of path.
                    Detour.dtVcopy(iterPos, targetPos);
                    if (nsmoothPath < maxSmoothPathSize)
                    {
                        Detour.dtVcopy(smoothPath, nsmoothPath * 3, iterPos, 0);
                        nsmoothPath++;
                    }
                    break;
                }
                else if (offMeshConnection && InRangeYZX(iterPos, steerPos, 0.3f, 1.0f))
                {
                    // Advance the path up to and over the off-mesh connection.
                    ulong prevRef = 0;
                    ulong polyRef = polys[0];
                    uint  npos    = 0;
                    while (npos < npolys && polyRef != steerPosRef)
                    {
                        prevRef = polyRef;
                        polyRef = polys[npos];
                        npos++;
                    }

                    for (uint i = npos; i < npolys; ++i)
                    {
                        polys[i - npos] = polys[i];
                    }

                    npolys -= npos;

                    // Handle the connection.
                    float[] connectionStartPos = new float[3];
                    float[] connectionEndPos   = new float[3];
                    if (Detour.dtStatusSucceed(_navMesh.getOffMeshConnectionPolyEndPoints(prevRef, polyRef, connectionStartPos, connectionEndPos)))
                    {
                        if (nsmoothPath < maxSmoothPathSize)
                        {
                            Detour.dtVcopy(smoothPath, nsmoothPath * 3, connectionStartPos, 0);
                            nsmoothPath++;
                        }
                        // Move position at the other side of the off-mesh link.
                        Detour.dtVcopy(iterPos, connectionEndPos);
                        _navMeshQuery.getPolyHeight(polys[0], iterPos, ref iterPos[1]);
                        iterPos[1] += 0.5f;
                    }
                }

                // Store results.
                if (nsmoothPath < maxSmoothPathSize)
                {
                    Detour.dtVcopy(smoothPath, nsmoothPath * 3, iterPos, 0);
                    nsmoothPath++;
                }
            }

            smoothPathSize = nsmoothPath;

            // this is most likely a loop
            return(nsmoothPath < 74 ? Detour.DT_SUCCESS : Detour.DT_FAILURE);
        }
Пример #5
0
        void BuildPolyPath(Vector3 startPos, Vector3 endPos)
        {
            // *** getting start/end poly logic ***

            float distToStartPoly = 0;
            float distToEndPoly   = 0;

            float[] startPoint = { startPos.Y, startPos.Z, startPos.X };
            float[] endPoint   = { endPos.Y, endPos.Z, endPos.X };

            ulong startPoly = GetPolyByLocation(startPoint, ref distToStartPoly);
            ulong endPoly   = GetPolyByLocation(endPoint, ref distToEndPoly);

            // we have a hole in our mesh
            // make shortcut path and mark it as NOPATH ( with flying and swimming exception )
            // its up to caller how he will use this info
            if (startPoly == 0 || endPoly == 0)
            {
                Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . (startPoly == 0 || endPoly == 0)\n");
                BuildShortcut();
                bool path = _sourceUnit.IsTypeId(TypeId.Unit) && _sourceUnit.ToCreature().CanFly();

                bool waterPath = _sourceUnit.IsTypeId(TypeId.Unit) && _sourceUnit.ToCreature().CanSwim();
                if (waterPath)
                {
                    // Check both start and end points, if they're both in water, then we can *safely* let the creature move
                    for (uint i = 0; i < _pathPoints.Length; ++i)
                    {
                        ZLiquidStatus status = _sourceUnit.GetMap().getLiquidStatus(_pathPoints[i].X, _pathPoints[i].Y, _pathPoints[i].Z, MapConst.MapAllLiquidTypes);
                        // One of the points is not in the water, cancel movement.
                        if (status == ZLiquidStatus.NoWater)
                        {
                            waterPath = false;
                            break;
                        }
                    }
                }

                pathType = (path || waterPath) ? (PathType.Normal | PathType.NotUsingPath) : PathType.NoPath;
                return;
            }

            // we may need a better number here
            bool farFromPoly = (distToStartPoly > 7.0f || distToEndPoly > 7.0f);

            if (farFromPoly)
            {
                Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . farFromPoly distToStartPoly={0:F3} distToEndPoly={1:F3}\n", distToStartPoly, distToEndPoly);

                bool buildShotrcut = false;
                if (_sourceUnit.IsTypeId(TypeId.Unit))
                {
                    Creature owner = _sourceUnit.ToCreature();

                    Vector3 p = (distToStartPoly > 7.0f) ? startPos : endPos;
                    if (_sourceUnit.GetMap().IsUnderWater(p.X, p.Y, p.Z))
                    {
                        Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . underWater case\n");
                        if (owner.CanSwim())
                        {
                            buildShotrcut = true;
                        }
                    }
                    else
                    {
                        Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . flying case\n");
                        if (owner.CanFly())
                        {
                            buildShotrcut = true;
                        }
                    }
                }

                if (buildShotrcut)
                {
                    BuildShortcut();
                    pathType = (PathType.Normal | PathType.NotUsingPath);
                    return;
                }
                else
                {
                    float[] closestPoint = new float[3];
                    // we may want to use closestPointOnPolyBoundary instead
                    bool posOverPoly = false;
                    if (Detour.dtStatusSucceed(_navMeshQuery.closestPointOnPoly(endPoly, endPoint, closestPoint, ref posOverPoly)))
                    {
                        Detour.dtVcopy(endPoint, closestPoint);
                        SetActualEndPosition(new Vector3(endPoint[2], endPoint[0], endPoint[1]));
                    }

                    pathType = PathType.Incomplete;
                }
            }

            // *** poly path generating logic ***

            // start and end are on same polygon
            // just need to move in straight line
            if (startPoly == endPoly)
            {
                Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . (startPoly == endPoly)\n");

                BuildShortcut();

                _pathPolyRefs[0] = startPoly;
                _polyLength      = 1;

                pathType = farFromPoly ? PathType.Incomplete : PathType.Normal;
                Log.outDebug(LogFilter.Maps, "BuildPolyPath . path type {0}\n", pathType);
                return;
            }

            // look for startPoly/endPoly in current path
            /// @todo we can merge it with getPathPolyByPosition() loop
            bool startPolyFound = false;
            bool endPolyFound   = false;
            uint pathStartIndex = 0;
            uint pathEndIndex   = 0;

            if (_polyLength != 0)
            {
                for (; pathStartIndex < _polyLength; ++pathStartIndex)
                {
                    // here to carch few bugs
                    if (_pathPolyRefs[pathStartIndex] == 0)
                    {
                        Log.outError(LogFilter.Maps, "Invalid poly ref in BuildPolyPath. _polyLength: {0}, pathStartIndex: {1}," +
                                     " startPos: {2}, endPos: {3}, mapid: {4}", _polyLength, pathStartIndex, startPos, endPos, _sourceUnit.GetMapId());
                        break;
                    }

                    if (_pathPolyRefs[pathStartIndex] == startPoly)
                    {
                        startPolyFound = true;
                        break;
                    }
                }

                for (pathEndIndex = _polyLength - 1; pathEndIndex > pathStartIndex; --pathEndIndex)
                {
                    if (_pathPolyRefs[pathEndIndex] == endPoly)
                    {
                        endPolyFound = true;
                        break;
                    }
                }
            }

            if (startPolyFound && endPolyFound)
            {
                Log.outDebug(LogFilter.Maps, "BuildPolyPath : (startPolyFound && endPolyFound)\n");

                // we moved along the path and the target did not move out of our old poly-path
                // our path is a simple subpath case, we have all the data we need
                // just "cut" it out

                _polyLength = pathEndIndex - pathStartIndex + 1;
                Array.Copy(_pathPolyRefs, pathStartIndex, _pathPolyRefs, 0, _polyLength);
            }
            else if (startPolyFound && !endPolyFound)
            {
                Log.outDebug(LogFilter.Maps, "BuildPolyPath : (startPolyFound && !endPolyFound)\n");

                // we are moving on the old path but target moved out
                // so we have atleast part of poly-path ready

                _polyLength -= pathStartIndex;

                // try to adjust the suffix of the path instead of recalculating entire length
                // at given interval the target cannot get too far from its last location
                // thus we have less poly to cover
                // sub-path of optimal path is optimal

                // take ~80% of the original length
                /// @todo play with the values here
                uint prefixPolyLength = (uint)(_polyLength * 0.8f + 0.5f);
                Array.Copy(_pathPolyRefs, pathStartIndex, _pathPolyRefs, 0, prefixPolyLength);

                ulong suffixStartPoly = _pathPolyRefs[prefixPolyLength - 1];

                // we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data
                float[] suffixEndPoint = new float[3];
                bool    posOverPoly    = false;
                if (Detour.dtStatusFailed(_navMeshQuery.closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint, ref posOverPoly)))
                {
                    // we can hit offmesh connection as last poly - closestPointOnPoly() don't like that
                    // try to recover by using prev polyref
                    --prefixPolyLength;
                    suffixStartPoly = _pathPolyRefs[prefixPolyLength - 1];
                    if (Detour.dtStatusFailed(_navMeshQuery.closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint, ref posOverPoly)))
                    {
                        // suffixStartPoly is still invalid, error state
                        BuildShortcut();
                        pathType = PathType.NoPath;
                        return;
                    }
                }

                // generate suffix
                uint suffixPolyLength = 0;

                uint dtResult;
                if (_straightLine)
                {
                    float   hit       = 0;
                    float[] hitNormal = new float[3];

                    dtResult = _navMeshQuery.raycast(
                        suffixStartPoly,
                        suffixEndPoint,
                        endPoint,
                        _filter,
                        ref hit,
                        hitNormal,
                        _pathPolyRefs,
                        ref suffixPolyLength,
                        74 - (int)prefixPolyLength);

                    // raycast() sets hit to FLT_MAX if there is a ray between start and end
                    if (hit != float.MaxValue)
                    {
                        // the ray hit something, return no path instead of the incomplete one
                        pathType = PathType.NoPath;
                        return;
                    }
                }
                else
                {
                    dtResult = _navMeshQuery.findPath(
                        suffixStartPoly,    // start polygon
                        endPoly,            // end polygon
                        suffixEndPoint,     // start position
                        endPoint,           // end position
                        _filter,            // polygon search filter
                        _pathPolyRefs,
                        ref suffixPolyLength,
                        74 - (int)prefixPolyLength);
                }

                if (suffixPolyLength == 0 || Detour.dtStatusFailed(dtResult))
                {
                    // this is probably an error state, but we'll leave it
                    // and hopefully recover on the next Update
                    // we still need to copy our preffix
                    Log.outError(LogFilter.Maps, "{0}'s Path Build failed: 0 length path", _sourceUnit.GetGUID().ToString());
                }

                Log.outDebug(LogFilter.Maps, "m_polyLength={0} prefixPolyLength={1} suffixPolyLength={2} \n", _polyLength, prefixPolyLength, suffixPolyLength);

                // new path = prefix + suffix - overlap
                _polyLength = prefixPolyLength + suffixPolyLength - 1;
            }
            else
            {
                Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . (!startPolyFound && !endPolyFound)\n");

                // either we have no path at all . first run
                // or something went really wrong . we aren't moving along the path to the target
                // just generate new path

                // free and invalidate old path data
                Clear();

                uint dtResult;
                if (_straightLine)
                {
                    float   hit       = 0;
                    float[] hitNormal = new float[3];

                    dtResult = _navMeshQuery.raycast(
                        startPoly,
                        startPoint,
                        endPoint,
                        _filter,
                        ref hit,
                        hitNormal,
                        _pathPolyRefs,
                        ref _polyLength,
                        74);

                    // raycast() sets hit to FLT_MAX if there is a ray between start and end
                    if (hit != float.MaxValue)
                    {
                        // the ray hit something, return no path instead of the incomplete one
                        pathType = PathType.NoPath;
                        return;
                    }
                }
                else
                {
                    dtResult = _navMeshQuery.findPath(
                        startPoly,     // start polygon
                        endPoly,       // end polygon
                        startPoint,    // start position
                        endPoint,      // end position
                        _filter,       // polygon search filter
                        _pathPolyRefs, // [out] path
                        ref _polyLength,
                        74);           // max number of polygons in output path
                }

                if (_polyLength == 0 || Detour.dtStatusFailed(dtResult))
                {
                    // only happens if we passed bad data to findPath(), or navmesh is messed up
                    Log.outError(LogFilter.Maps, "{0}'s Path Build failed: 0 length path", _sourceUnit.GetGUID().ToString());
                    BuildShortcut();
                    pathType = PathType.NoPath;
                    return;
                }
            }

            // by now we know what type of path we can get
            if (_pathPolyRefs[_polyLength - 1] == endPoly && !pathType.HasAnyFlag(PathType.Incomplete))
            {
                pathType = PathType.Normal;
            }
            else
            {
                pathType = PathType.Incomplete;
            }

            // generate the point-path out of our up-to-date poly-path
            BuildPointPath(startPoint, endPoint);
        }
Пример #6
0
    public static SmoothPath ComputeSmoothPath(Detour.dtNavMeshQuery navQuery, float[] startWorldPos, float[] endWorldPos, float distance = 10)
    {
        SmoothPath smoothPath = new SmoothPath();

        if (navQuery == null)
        {
            return(smoothPath);
        }

        float[] extents = new float[3];
        for (int i = 0; i < 3; ++i)
        {
            extents[i] = distance;
        }

        dtPolyRef startRef = 0;
        dtPolyRef endRef   = 0;

        float[] startPt = new float[3];
        float[] endPt   = new float[3];

        Detour.dtQueryFilter filter = new Detour.dtQueryFilter();

        navQuery.findNearestPoly(startWorldPos, extents, filter, ref startRef, ref startPt);
        navQuery.findNearestPoly(endWorldPos, extents, filter, ref endRef, ref endPt);

        const int maxPath = SmoothPath.MAX_POLYS;

        dtPolyRef[] path = new dtPolyRef[maxPath];

        int pathCount = -1;

        navQuery.findPath(startRef, endRef, startPt, endPt, filter, path, ref pathCount, maxPath);

        smoothPath.m_nsmoothPath = 0;

        if (pathCount > 0)
        {
            // Iterate over the path to find smooth path on the detail mesh surface.
            dtPolyRef[] polys = new dtPolyRef[SmoothPath.MAX_POLYS];
            for (int i = 0; i < pathCount; ++i)
            {
                polys[i] = path[i];
            }
            int npolys = pathCount;

            float[] iterPos           = new float[3];
            float[] targetPos         = new float[3];
            bool    posOverPoly_dummy = false;
            navQuery.closestPointOnPoly(startRef, startPt, iterPos, ref posOverPoly_dummy);
            navQuery.closestPointOnPoly(polys[npolys - 1], endPt, targetPos, ref posOverPoly_dummy);

            const float STEP_SIZE = 0.5f;
            const float SLOP      = 0.01f;

            smoothPath.m_nsmoothPath = 0;

            Detour.dtVcopy(smoothPath.m_smoothPath, smoothPath.m_nsmoothPath * 3, iterPos, 0);
            smoothPath.m_nsmoothPath++;

            // Move towards target a small advancement at a time until target reached or
            // when ran out of memory to store the path.
            while (npolys != 0 && smoothPath.m_nsmoothPath < SmoothPath.MAX_SMOOTH)
            {
                // Find location to steer towards.
                float[]   steerPos     = new float[3];
                byte      steerPosFlag = 0;
                dtPolyRef steerPosRef  = 0;

                if (!getSteerTarget(navQuery, iterPos, targetPos, SLOP,
                                    polys, npolys, steerPos, ref steerPosFlag, ref steerPosRef))
                {
                    break;
                }

                bool endOfPath         = (steerPosFlag & (byte)Detour.dtStraightPathFlags.DT_STRAIGHTPATH_END) != 0 ? true : false;
                bool offMeshConnection = (steerPosFlag & (byte)Detour.dtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0 ? true : false;

                // Find movement delta.
                float[] delta = new float[3];                //, len;
                float   len   = .0f;
                Detour.dtVsub(delta, steerPos, iterPos);
                len = (float)Mathf.Sqrt(Detour.dtVdot(delta, delta));
                // If the steer target is end of path or off-mesh link, do not move past the location.
                if ((endOfPath || offMeshConnection) && len < STEP_SIZE)
                {
                    len = 1;
                }
                else
                {
                    len = STEP_SIZE / len;
                }
                float[] moveTgt = new float[3];
                Detour.dtVmad(moveTgt, iterPos, delta, len);

                // Move
                float[]     result   = new float[3];
                dtPolyRef[] visited  = new dtPolyRef[16];
                int         nvisited = 0;
                navQuery.moveAlongSurface(polys[0], iterPos, moveTgt, filter,
                                          result, visited, ref nvisited, 16);

                npolys = fixupCorridor(polys, npolys, SmoothPath.MAX_POLYS, visited, nvisited);
                npolys = fixupShortcuts(polys, npolys, navQuery);

                float    h = 0;
                dtStatus getHeightStatus = navQuery.getPolyHeight(polys[0], result, ref h);
                result[1] = h;

                if ((getHeightStatus & Detour.DT_FAILURE) != 0)
                {
                    Debug.LogError("Failed to getPolyHeight " + polys[0] + " pos " + result[0] + " " + result[1] + " " + result[2] + " h " + h);
                }

                Detour.dtVcopy(iterPos, result);

                // Handle end of path and off-mesh links when close enough.
                if (endOfPath && inRange(iterPos, 0, steerPos, 0, SLOP, 1.0f))
                {
                    // Reached end of path.
                    Detour.dtVcopy(iterPos, targetPos);
                    if (smoothPath.m_nsmoothPath < SmoothPath.MAX_SMOOTH)
                    {
                        Detour.dtVcopy(smoothPath.m_smoothPath, smoothPath.m_nsmoothPath * 3, iterPos, 0);
                        smoothPath.m_nsmoothPath++;
                    }
                    break;
                }
                else if (offMeshConnection && inRange(iterPos, 0, steerPos, 0, SLOP, 1.0f))
                {
                    // Reached off-mesh connection.
                    float[] startPos = new float[3];                    //, endPos[3];
                    float[] endPos   = new float[3];

                    // Advance the path up to and over the off-mesh connection.
                    dtPolyRef prevRef = 0, polyRef = polys[0];
                    int       npos = 0;
                    while (npos < npolys && polyRef != steerPosRef)
                    {
                        prevRef = polyRef;
                        polyRef = polys[npos];
                        npos++;
                    }
                    for (int i = npos; i < npolys; ++i)
                    {
                        polys[i - npos] = polys[i];
                    }

                    npolys -= npos;

                    // Handle the connection.

                    dtStatus status = navQuery.getAttachedNavMesh().getOffMeshConnectionPolyEndPoints(prevRef, polyRef, startPos, endPos);
                    if (Detour.dtStatusSucceed(status))
                    {
                        if (smoothPath.m_nsmoothPath < SmoothPath.MAX_SMOOTH)
                        {
                            Detour.dtVcopy(smoothPath.m_smoothPath, smoothPath.m_nsmoothPath * 3, startPos, 0);
                            smoothPath.m_nsmoothPath++;
                            // Hack to make the dotted path not visible during off-mesh connection.
                            if ((smoothPath.m_nsmoothPath & 1) != 0)
                            {
                                Detour.dtVcopy(smoothPath.m_smoothPath, smoothPath.m_nsmoothPath * 3, startPos, 0);
                                smoothPath.m_nsmoothPath++;
                            }
                        }
                        // Move position at the other side of the off-mesh link.
                        Detour.dtVcopy(iterPos, endPos);
                        float eh = 0.0f;
                        navQuery.getPolyHeight(polys[0], iterPos, ref eh);
                        iterPos[1] = eh;
                    }
                }

                // Store results.
                if (smoothPath.m_nsmoothPath < SmoothPath.MAX_SMOOTH)
                {
                    Detour.dtVcopy(smoothPath.m_smoothPath, smoothPath.m_nsmoothPath * 3, iterPos, 0);
                    smoothPath.m_nsmoothPath++;
                }
            }
        }
        return(smoothPath);
    }
Пример #7
0
        public bool loadMap(uint mapId, int x, int y)
        {
            // make sure the mmap is loaded and ready to load tiles
            if (!loadMapData(mapId))
            {
                return(false);
            }

            // get this mmap data
            MMapData mmap = loadedMMaps[mapId];

            Contract.Assert(mmap.navMesh != null);

            // check if we already have this tile loaded
            uint packedGridPos = packTileID(x, y);

            if (mmap.loadedTileRefs.ContainsKey(packedGridPos))
            {
                return(false);
            }

            // load this tile . mmaps/MMMXXYY.mmtile
            string filename = string.Format(TILE_FILE_NAME_FORMAT, Global.WorldMgr.GetDataPath(), mapId, x, y);

            if (!File.Exists(filename))
            {
                Log.outDebug(LogFilter.Maps, "MMAP:loadMap: Could not open mmtile file '{0}'", filename);
                return(false);
            }

            using (BinaryReader reader = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read)))
            {
                MmapTileHeader fileHeader = reader.ReadStruct <MmapTileHeader>();
                Array.Reverse(fileHeader.mmapMagic);
                if (new string(fileHeader.mmapMagic) != MapConst.mmapMagic)
                {
                    Log.outError(LogFilter.Maps, "MMAP:loadMap: Bad header in mmap {0:D4}{1:D2}{2:D2}.mmtile", mapId, x, y);
                    return(false);
                }
                if (fileHeader.mmapVersion != MapConst.mmapVersion)
                {
                    Log.outError(LogFilter.Maps, "MMAP:loadMap: {0:D4}{1:D2}{2:D2}.mmtile was built with generator v{3}, expected v{4}",
                                 mapId, x, y, fileHeader.mmapVersion, MapConst.mmapVersion);
                    return(false);
                }

                var bytes = reader.ReadBytes((int)fileHeader.size);

                Detour.dtRawTileData data = new Detour.dtRawTileData();
                data.FromBytes(bytes, 0);

                ulong tileRef = 0;
                // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed
                if (Detour.dtStatusSucceed(mmap.navMesh.addTile(data, 0, 0, ref tileRef)))
                {
                    mmap.loadedTileRefs.Add(packedGridPos, tileRef);
                    ++loadedTiles;
                    Log.outInfo(LogFilter.Maps, "MMAP:loadMap: Loaded mmtile {0:D4}[{1:D2}, {2:D2}]", mapId, x, y);

                    var phasedMaps = phaseMapData.LookupByKey(mapId);
                    if (!phasedMaps.Empty())
                    {
                        mmap.AddBaseTile(packedGridPos, data, fileHeader, fileHeader.size);
                        LoadPhaseTiles(phasedMaps, x, y);
                    }

                    return(true);
                }

                Log.outError(LogFilter.Maps, "MMAP:loadMap: Could not load {0:D4}{1:D2}{2:D2}.mmtile into navmesh", mapId, x, y);
                return(false);
            }
        }
Пример #8
0
        static bool LocCommand(StringArguments args, CommandHandler handler)
        {
            handler.SendSysMessage("mmap tileloc:");

            // grid tile location
            Player player = handler.GetPlayer();

            int gx = (int)(32 - player.GetPositionX() / MapConst.SizeofGrids);
            int gy = (int)(32 - player.GetPositionY() / MapConst.SizeofGrids);

            float x, y, z;

            player.GetPosition(out x, out y, out z);

            handler.SendSysMessage("{0:D4}{1:D2}{2:D2}.mmtile", player.GetMapId(), gy, gx);
            handler.SendSysMessage("gridloc [{0}, {1}]", gx, gy);

            // calculate navmesh tile location
            uint terrainMapId = PhasingHandler.GetTerrainMapId(player.GetPhaseShift(), player.GetMap(), x, y);

            Detour.dtNavMesh      navmesh      = Global.MMapMgr.GetNavMesh(terrainMapId);
            Detour.dtNavMeshQuery navmeshquery = Global.MMapMgr.GetNavMeshQuery(terrainMapId, player.GetInstanceId());
            if (navmesh == null || navmeshquery == null)
            {
                handler.SendSysMessage("NavMesh not loaded for current map.");
                return(true);
            }

            float[] min      = navmesh.getParams().orig;
            float[] location = { y, z, x };
            float[] extents  = { 3.0f, 5.0f, 3.0f };

            int tilex = (int)((y - min[0]) / MapConst.SizeofGrids);
            int tiley = (int)((x - min[2]) / MapConst.SizeofGrids);

            handler.SendSysMessage("Calc   [{0:D2}, {1:D2}]", tilex, tiley);

            // navmesh poly . navmesh tile location
            Detour.dtQueryFilter filter = new Detour.dtQueryFilter();
            float[] nothing             = new float[3];
            ulong   polyRef             = 0;

            if (Detour.dtStatusFailed(navmeshquery.findNearestPoly(location, extents, filter, ref polyRef, ref nothing)))
            {
                handler.SendSysMessage("Dt     [??,??] (invalid poly, probably no tile loaded)");
                return(true);
            }

            if (polyRef == 0)
            {
                handler.SendSysMessage("Dt     [??, ??] (invalid poly, probably no tile loaded)");
            }
            else
            {
                Detour.dtMeshTile tile = new Detour.dtMeshTile();
                Detour.dtPoly     poly = new Detour.dtPoly();
                if (Detour.dtStatusSucceed(navmesh.getTileAndPolyByRef(polyRef, ref tile, ref poly)))
                {
                    if (tile != null)
                    {
                        handler.SendSysMessage("Dt     [{0:D2},{1:D2}]", tile.header.x, tile.header.y);
                        return(false);
                    }
                }

                handler.SendSysMessage("Dt     [??,??] (no tile loaded)");
            }
            return(true);
        }
Пример #9
0
        bool LoadMapImpl(string basePath, uint mapId, uint x, uint y)
        {
            // make sure the mmap is loaded and ready to load tiles
            if (!LoadMapData(basePath, mapId))
            {
                return(false);
            }

            // get this mmap data
            MMapData mmap = loadedMMaps[mapId];

            Cypher.Assert(mmap.navMesh != null);

            // check if we already have this tile loaded
            uint packedGridPos = PackTileID(x, y);

            if (mmap.loadedTileRefs.ContainsKey(packedGridPos))
            {
                return(false);
            }

            // load this tile . mmaps/MMMXXYY.mmtile
            string fileName = string.Format(TILE_FILE_NAME_FORMAT, basePath, mapId, x, y);

            if (!File.Exists(fileName))
            {
                if (parentMapData.ContainsKey(mapId))
                {
                    fileName = string.Format(TILE_FILE_NAME_FORMAT, basePath, parentMapData[mapId], x, y);
                }
            }

            if (!File.Exists(fileName))
            {
                Log.outDebug(LogFilter.Maps, "MMAP:loadMap: Could not open mmtile file '{0}'", fileName);
                return(false);
            }

            using (BinaryReader reader = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read)))
            {
                MmapTileHeader fileHeader = reader.Read <MmapTileHeader>();
                if (fileHeader.mmapMagic != MapConst.mmapMagic)
                {
                    Log.outError(LogFilter.Maps, "MMAP:loadMap: Bad header in mmap {0:D4}{1:D2}{2:D2}.mmtile", mapId, x, y);
                    return(false);
                }
                if (fileHeader.mmapVersion != MapConst.mmapVersion)
                {
                    Log.outError(LogFilter.Maps, "MMAP:loadMap: {0:D4}{1:D2}{2:D2}.mmtile was built with generator v{3}, expected v{4}",
                                 mapId, x, y, fileHeader.mmapVersion, MapConst.mmapVersion);
                    return(false);
                }

                var bytes = reader.ReadBytes((int)fileHeader.size);
                Detour.dtRawTileData data = new Detour.dtRawTileData();
                data.FromBytes(bytes, 0);

                ulong tileRef = 0;
                // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed
                if (Detour.dtStatusSucceed(mmap.navMesh.addTile(data, 1, 0, ref tileRef)))
                {
                    mmap.loadedTileRefs.Add(packedGridPos, tileRef);
                    ++loadedTiles;
                    Log.outInfo(LogFilter.Maps, "MMAP:loadMap: Loaded mmtile {0:D4}[{1:D2}, {2:D2}]", mapId, x, y);
                    return(true);
                }

                Log.outError(LogFilter.Maps, "MMAP:loadMap: Could not load {0:D4}{1:D2}{2:D2}.mmtile into navmesh", mapId, x, y);
                return(false);
            }
        }