public void handle_partial_result() { using (var ctx = new RecastContext()) { var navMesh = LoadNavMeshBinFile(ctx); var navMeshQuery = ctx.CreateNavMeshQuery(navMesh); var stopwatch = Stopwatch.StartNew(); var pointA = new PolyPointResult { status = 1073741824, point = new[] { -373.413f, 107.4798f, -271.1656f }, polyRef = 281474994536448 }; var pointB = new PolyPointResult { status = 1073741824, point = new[] { -370.4435f, 100.7469f, -221.2217f }, polyRef = 281475063742464 }; var result = FindPathSafer(pointA, pointB, ctx, navMeshQuery, stopwatch); var smoothResult = ctx.FindSmoothPath(navMeshQuery, navMesh, result, pointA, pointB); Assert.AreEqual(5, result.pathCount); Assert.True(PartialResult(result.status)); Assert.AreEqual(3, smoothResult.pathCount); } }
private InputGeom GetInputGeom(RecastContext ctx) { var mesh = ctx.LoadInputGeom(TestUtils.ResolveResource("./Resources/Tile_+007_+006_L21.obj"), true); ctx.CalcGridSize(ref _config, mesh); return(mesh); }
private float be_fast_work(RecastContext ctx, NavMesh navMesh) { var navMeshQuery = ctx.CreateNavMeshQuery(navMesh); const int N = 10000; var NRan = 0; var stopwatch = Stopwatch.StartNew(); stopwatch.Stop(); for (var i = 0; i < N; i++) { var pointA = FindRandomPointSafer(ctx, navMeshQuery); var pointB = FindRandomPointSafer(ctx, navMeshQuery); var result = FindPathSafer(pointA, pointB, ctx, navMeshQuery, stopwatch); if (Success(result.status)) { var smoothResult = ctx.FindSmoothPath(navMeshQuery, navMesh, result, pointA, pointB); if (!PartialResult(result.status)) { Assert.GreaterOrEqual(smoothResult.pathCount, result.pathCount, $"smoothResult.pathCount [{smoothResult.pathCount}] < result.pathCount [{result.pathCount}]. PointA = {pointA}, PointB={pointB}"); } } NRan++; } float avg = (float)stopwatch.ElapsedMilliseconds / NRan; Console.WriteLine($"\nAverage time (ms) for {NRan} run(s): {avg}"); return(avg); }
public void create_a_context() { using (var ctx = new RecastContext()) { Assert.IsNotNull(ctx); } }
public void load_nav_mesh_tiled_bin_file() { using (var ctx = new RecastContext()) { NavMesh navMesh = LoadNavMeshBinFile(ctx); Assert.IsNotNull(navMesh); } }
private NavMesh LoadNavMeshBinFile(RecastContext ctx) { var navMesh = ctx.LoadTiledNavMeshBinFile(TestUtils.ResolveResource("./Resources/Tile_+007_+006_L21.obj.tiled.bin64")); Assert.IsNotNull(navMesh); return(navMesh); }
public void load_a_mesh() { using (var ctx = new RecastContext()) { var mesh = GetInputGeom(ctx); Assert.IsNotNull(mesh); } }
public void be_fast_from_obj() { using (var ctx = new RecastContext()) { var navMesh = CreateNavMesh(ctx); var avg = be_fast_work(ctx, navMesh); Assert.LessOrEqual(avg, 0.1); } }
public void create_compact_heightfield() { using (var ctx = new RecastContext()) { var mesh = GetInputGeom(ctx); var chf = ctx.CreateCompactHeightfield(_config, mesh); Assert.IsNotNull(chf); } }
public void be_fast_from_bin() { using (var ctx = new RecastContext()) { var navMesh = LoadNavMeshBinFile(ctx); var avg = be_fast_work(ctx, navMesh); Assert.LessOrEqual(avg, 0.1); } }
public void create_polymesh_detail() { using (var ctx = new RecastContext()) { var mesh = GetInputGeom(ctx); var chf = ctx.CreateCompactHeightfield(_config, mesh); var polyMesh = ctx.CreatePolyMesh(_config, chf); var polyMeshDetail = ctx.CreatePolyMeshDetail(_config, polyMesh, chf); } }
public void find_random_point() { using (var ctx = new RecastContext()) { var navMesh = CreateNavMesh(ctx); var navMeshQuery = ctx.CreateNavMeshQuery(navMesh); var result = ctx.FindRandomPoint(navMeshQuery); Assert.IsTrue(Success(result.status)); Assert.AreEqual(result.point.Length, 3); } }
public void find_path() { using (var ctx = new RecastContext()) { var navMesh = CreateNavMesh(ctx); var navMeshQuery = ctx.CreateNavMeshQuery(navMesh); var pointA = FindRandomPointSafer(ctx, navMeshQuery); var pointB = FindRandomPointSafer(ctx, navMeshQuery); var result = FindPathSafer(pointA, pointB, ctx, navMeshQuery); Assert.IsTrue(Success(result.status)); } }
private PolyPointResult FindRandomPointSafer(RecastContext ctx, NavMeshQuery navMeshQuery) { int retries = 10; PolyPointResult result; do { result = ctx.FindRandomPoint(navMeshQuery); retries--; } while ((!Success(result.status)) && (0 < retries)); return(result); }
/// <summary> /// Initialize a new DefaultMeshNavigator given a mesh file and halfExtents parameters. /// </summary> /// <param name="navMeshFile">Mesh file</param> /// <param name="halfExtents">Half extents</param> /// <exception cref="Exception">Throws an exception if the mesh file cannot be loaded.</exception> public DefaultMeshNavigator(string navMeshFile, float[] halfExtents) { _ctx = new RecastContext(); _navMesh = _ctx.LoadTiledNavMeshBinFile(navMeshFile); if (_navMesh.IsInvalid) { throw new Exception("Failed to load nav mesh"); } _navMeshQuery = _ctx.CreateNavMeshQuery(_navMesh); _halfExtents = halfExtents; }
public void find_nearest_poly() { using (var ctx = new RecastContext()) { var navMesh = CreateNavMesh(ctx); var navMeshQuery = ctx.CreateNavMeshQuery(navMesh); var point = new float[] { -575f, -69.1874f, 54f }; var halfExtents = new float[] { 10.0f, 10.0f, 10.0f }; var result = ctx.FindNearestPoly(navMeshQuery, point, halfExtents); Assert.AreEqual(result.polyRef, 281474976711211L); } }
public void create_navmesh() { using (var ctx = new RecastContext()) { var mesh = GetInputGeom(ctx); var chf = ctx.CreateCompactHeightfield(_config, mesh); var polyMesh = ctx.CreatePolyMesh(_config, chf); var polyMeshDetail = ctx.CreatePolyMeshDetail(_config, polyMesh, chf); var navMeshData = ctx.CreateNavMeshData(_config, polyMeshDetail, polyMesh, mesh, 0, 0, BuildSettings.agentHeight, BuildSettings.agentRadius, BuildSettings.agentMaxClimb); var navMesh = ctx.CreateNavMesh(navMeshData); Assert.IsNotNull(navMesh); } }
private NavMesh CreateNavMesh(RecastContext ctx) { var mesh = ctx.LoadInputGeom(TestUtils.ResolveResource("Resources/Tile_+007_+006_L21.obj"), true); Assert.IsNotNull(mesh); ctx.CalcGridSize(ref _config, mesh); var chf = ctx.CreateCompactHeightfield(_config, mesh); var polyMesh = ctx.CreatePolyMesh(_config, chf); var polyMeshDetail = ctx.CreatePolyMeshDetail(_config, polyMesh, chf); var navMeshData = ctx.CreateNavMeshData(_config, polyMeshDetail, polyMesh, mesh, 0, 0, BuildSettings.agentHeight, BuildSettings.agentRadius, BuildSettings.agentMaxClimb); return(ctx.CreateNavMesh(navMeshData)); }
public void create_navmesh_data() { using (var ctx = new RecastContext()) { var mesh = GetInputGeom(ctx); var chf = ctx.CreateCompactHeightfield(_config, mesh); var polyMesh = ctx.CreatePolyMesh(_config, chf); var polyMeshDetail = ctx.CreatePolyMeshDetail(_config, polyMesh, chf); var navMeshData = ctx.CreateNavMeshData(_config, polyMeshDetail, polyMesh, mesh, 0, 0, BuildSettings.agentHeight, BuildSettings.agentRadius, BuildSettings.agentMaxClimb); // TODO: This is different to Java!! Assert.AreEqual(114764, navMeshData.size); var bytes = navMeshData.GetData(); Assert.AreEqual(bytes.Length, navMeshData.size); } }
public void find_nearest_poly_fail() { using (var ctx = new RecastContext()) { var navMesh = CreateNavMesh(ctx); var navMeshQuery = ctx.CreateNavMeshQuery(navMesh); var point = new float[] { -5750.0f, -6900.1874f, 5400.0f }; var halfExtents = new float[] { 10.0f, 10.0f, 10.0f }; var result = ctx.FindNearestPoly(navMeshQuery, point, halfExtents); Assert.IsFalse(Success(result.status)); Assert.AreEqual(result.polyRef, 0); Assert.AreEqual(result.point[0], 0); Assert.AreEqual(result.point[1], 0); Assert.AreEqual(result.point[2], 0); } }
public void find_smooth_path() { using (var ctx = new RecastContext()) { var navMesh = CreateNavMesh(ctx); var navMeshQuery = ctx.CreateNavMeshQuery(navMesh); var pointA = FindRandomPointSafer(ctx, navMeshQuery); var pointB = FindRandomPointSafer(ctx, navMeshQuery); var result = FindPathSafer(pointA, pointB, ctx, navMeshQuery); Assert.IsTrue(Success(result.status)); var smoothResult = ctx.FindSmoothPath(navMeshQuery, navMesh, result, pointA, pointB); Assert.IsNotNull(smoothResult); Assert.GreaterOrEqual(smoothResult.pathCount, result.pathCount); Assert.AreEqual(3 * Constants.MaxSmoothPathLength, smoothResult.path.Length); Assert.IsTrue(smoothResult.pathCount < Constants.MaxSmoothPathLength * 3); Assert.AreEqual(smoothResult.path[0], pointA.point[0], 0.00001); Assert.AreEqual(smoothResult.path[1], pointA.point[1], 0.00001); Assert.AreEqual(smoothResult.path[2], pointA.point[2], 0.00001); } }
private FindPathResult FindPathSafer(PolyPointResult pointA, PolyPointResult pointB, RecastContext ctx, NavMeshQuery navMeshQuery, Stopwatch stopwatch = null) { Assert.IsTrue(Success(pointA.status), "Point A not a success."); Assert.IsTrue(Success(pointB.status), "Point A not a success."); if (null != stopwatch) { stopwatch.Start(); } int retries = 10; FindPathResult result; do { result = ctx.FindPath(navMeshQuery, pointA, pointB); retries--; } while ((!Success(result.status)) && (0 < retries)); if (null != stopwatch) { stopwatch.Stop(); } if (Success(result.status)) { Assert.IsNotNull(result, "result NULL"); Assert.AreEqual(Constants.MaxPathLength, result.path.Length, $"Constants.MaxPathLength != result.path.Length [{Constants.MaxPathLength} != {result.path.Length}]"); Assert.GreaterOrEqual(result.pathCount, 1, $"result.pathCount [{result.pathCount}] < 1"); Assert.AreEqual(pointA.polyRef, result.path[0], $"point A polyref does not match [{pointA.polyRef} != {result.path[0]}]"); if (!PartialResult(result.status)) { Assert.AreEqual(pointB.polyRef, result.path[result.pathCount - 1], $"point B polyref does not match [{pointA.polyRef} != {result.path[result.pathCount - 1]}] (status={result.status} [{Convert.ToString(result.status, 2)}])"); } } return(result); }
public void disposes_work() { var ctx = new RecastContext(); var mesh = GetInputGeom(ctx); var chf = ctx.CreateCompactHeightfield(_config, mesh); var polyMesh = ctx.CreatePolyMesh(_config, chf); var polyMeshDetail = ctx.CreatePolyMeshDetail(_config, polyMesh, chf); var navMeshData = ctx.CreateNavMeshData(_config, polyMeshDetail, polyMesh, mesh, 0, 0, BuildSettings.agentHeight, BuildSettings.agentRadius, BuildSettings.agentMaxClimb); var navMesh = ctx.CreateNavMesh(navMeshData); var navMeshQuery = ctx.CreateNavMeshQuery(navMesh); Assert.IsNotNull(navMeshQuery); navMeshQuery.Dispose(); navMesh.Dispose(); polyMeshDetail.Dispose(); polyMesh.Dispose(); chf.Dispose(); mesh.Dispose(); ctx.Dispose(); }
public byte[] Build() { Geometry = new Geometry.Geometry {Transform = true }; { var main = new ADT(World, X, Y); main.Read(); // main.Generate(); Geometry.AddADT(main); } if (Geometry.Vertices.Count == 0 && Geometry.Indices.Count == 0) throw new InvalidOperationException("Can't build tile with empty geometry"); float[] bbMin, bbMax; CalculateTileBounds(out bbMin, out bbMax); Geometry.CalculateMinMaxHeight(out bbMin[1], out bbMax[1]); // again, we load everything - wasteful but who cares /* for (int ty = Y - 1; ty <= Y + 1; ty++) { for (int tx = X - 1; tx <= X + 1; tx++) { try { // don't load main tile again if (tx == X && ty == Y) continue; var adt = new ADT(World, tx, ty); adt.Read(); Geometry.AddADT(adt); } catch (FileNotFoundException) { // don't care - no file means no geometry } } }*/ Context = new RecastContext(); // Context.SetContextHandler(Log); // get raw geometry - lots of slowness here float[] vertices; int[] triangles; byte[] areas; Geometry.GetRawData(out vertices, out triangles, out areas); Geometry.SaveWavefrontObject($"{World}_{X}_{Y}.obj"); Geometry.Indices.Clear(); Geometry.Vertices.Clear(); // add border bbMin[0] -= Config.BorderSize * Config.CellSize; bbMin[2] -= Config.BorderSize * Config.CellSize; bbMax[0] += Config.BorderSize * Config.CellSize; bbMax[2] += Config.BorderSize * Config.CellSize; Heightfield hf; int width = Config.TileWidth + (Config.BorderSize * 2); if (!Context.CreateHeightfield(out hf, width, width, bbMin, bbMax, Config.CellSize, Config.CellHeight)) throw new OutOfMemoryException("CreateHeightfield ran out of memory"); Context.MarkWalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles,out areas); // Context.ClearUnwalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles, areas); Context.RasterizeTriangles(ref vertices, ref triangles, ref areas, hf, Config.WalkableClimb); // Once all geometry is rasterized, we do initial pass of filtering to // remove unwanted overhangs caused by the conservative rasterization // as well as filter spans where the character cannot possibly stand. Context.FilterLowHangingWalkableObstacles(Config.WalkableClimb, hf); Context.FilterLedgeSpans(Config.WalkableHeight, Config.WalkableClimb, hf); Context.FilterWalkableLowHeightSpans(Config.WalkableHeight, hf); // Compact the heightfield so that it is faster to handle from now on. // This will result in more cache coherent data as well as the neighbours // between walkable cells will be calculated. CompactHeightfield chf; if (!Context.BuildCompactHeightfield(Config.WalkableHeight, Config.WalkableClimb, hf, out chf)) throw new OutOfMemoryException("BuildCompactHeightfield ran out of memory"); hf.Delete(); // Erode the walkable area by agent radius. if (!Context.ErodeWalkableArea(Config.WalkableRadius, chf)) throw new OutOfMemoryException("ErodeWalkableArea ran out of memory"); // Prepare for region partitioning, by calculating distance field along the walkable surface. if (!Context.BuildDistanceField(chf)) throw new OutOfMemoryException("BuildDistanceField ran out of memory"); // Partition the walkable surface into simple regions without holes. if (!Context.BuildRegions(chf, Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea)) throw new OutOfMemoryException("BuildRegionsMonotone ran out of memory"); // Create contours. ContourSet cset; if (!Context.BuildContours(chf, Config.MaxSimplificationError, Config.MaxEdgeLength, out cset)) throw new OutOfMemoryException("BuildContours ran out of memory"); // Build polygon navmesh from the contours. PolyMesh pmesh; if (!Context.BuildPolyMesh(cset, Config.MaxVertsPerPoly, out pmesh)) throw new OutOfMemoryException("BuildPolyMesh ran out of memory"); // Build detail mesh. PolyMeshDetail dmesh; if ( !Context.BuildPolyMeshDetail(pmesh, chf, Config.DetailSampleDistance, Config.DetailSampleMaxError, out dmesh)) throw new OutOfMemoryException("BuildPolyMeshDetail ran out of memory"); chf.Delete(); cset.Delete(); // Remove padding from the polymesh data. (Remove this odditity) pmesh.RemovePadding(Config.BorderSize); // Set flags according to area types (e.g. Swim for Water) pmesh.MarkAll(); // get original bounds float[] tilebMin, tilebMax; CalculateTileBounds(out tilebMin, out tilebMax); tilebMin[1] = bbMin[1]; tilebMax[1] = bbMax[1]; // build off mesh connections for flightmasters // bMax and bMin are switched here because of the coordinate system transformation var connections = new List<OffMeshConnection>(); byte[] tileData; if (!Detour.CreateNavMeshData(out tileData, pmesh, dmesh, X, Y, tilebMin, tilebMax, Config.WorldWalkableHeight, Config.WorldWalkableRadius, Config.WorldWalkableClimb, Config.CellSize, Config.CellHeight, Config.TileWidth, connections.ToArray())) { pmesh.Delete(); dmesh.Delete(); return null; } pmesh.Delete(); dmesh.Delete(); GC.Collect(); return tileData; }
public void PrepareData(BaseLog log) { if (log == null) { throw new ArgumentNullException("log"); } Log = log; Cache.Clear(); Geometry = new Geometry { Transform = true }; //List<ADT> adtList = new List<ADT>(); bool hasHandle = false; try { try { hasHandle = _mutex.WaitOne(Timeout.Infinite, false); if (hasHandle == false) { throw new TimeoutException("Timeout waiting for exclusive access"); } } catch (AbandonedMutexException) { // The mutex was abandoned in another process, it will still get aquired hasHandle = true; } // Do the work which require this mutex locking (useless with CACS) //{ ADT main = GetAdt(World, X, Y); Geometry.AddAdt(main); InsertAllGameobjectGeometry(X, Y, MapId); // Geometry.CreateDemoDump("X:\\Meshes\\" + MapId + "_" + X + "_" + Y + ".obj"); //} if (Geometry.Vertices.Count == 0 && Geometry.Triangles.Count == 0) { throw new InvalidOperationException("Can't build tile with empty geometry"); } // again, we load everything - wasteful but who cares for (int ty = Y - 1; ty <= Y + 1; ty++) { for (int tx = X - 1; tx <= X + 1; tx++) { // don't load main tile again if (tx == X && ty == Y) { continue; } ADT adt = GetAdt(World, tx, ty); if (adt.HasObjectData) { //Console.WriteLine("-> " + World + "_" + tx + "_" + ty); Geometry.AddAdt(adt); InsertAllGameobjectGeometry(tx, ty, MapId); } else { string parentMap = PhaseHelper.GetParentMap(World); if (parentMap != string.Empty) { ADT adtParent = GetAdt(parentMap, tx, ty); if (adtParent.HasObjectData) { Console.WriteLine("-> " + parentMap + "_" + tx + "_" + ty); Geometry.AddAdt(adtParent); InsertAllGameobjectGeometry(tx, ty, PhaseHelper.GetMapIdByName(parentMap)); } } } } } } finally { if (hasHandle) { _mutex.ReleaseMutex(); } } Context = new RecastContext(); Context.SetContextHandler(Log); }
public byte[] Build(BaseLog log) { Log = log; Geometry = new Geometry { Transform = true }; { var main = GetAdt(World, X, Y); Geometry.AddAdt(main); } if (Geometry.Vertices.Count == 0 && Geometry.Triangles.Count == 0) { throw new InvalidOperationException("Can't build tile with empty geometry"); } float[] bbMin, bbMax; CalculateTileBounds(out bbMin, out bbMax); Geometry.CalculateMinMaxHeight(out bbMin[1], out bbMax[1]); // again, we load everything - wasteful but who cares for (int ty = Y - 1; ty <= Y + 1; ty++) { for (int tx = X - 1; tx <= X + 1; tx++) { try { // don't load main tile again if (tx == X && ty == Y) { continue; } var adt = GetAdt(World, tx, ty); Geometry.AddAdt(adt); } catch (FileNotFoundException) { // don't care - no file means no geometry } } } Context = new RecastContext(); Context.SetContextHandler(Log); // get raw geometry - lots of slowness here float[] vertices; int[] triangles; byte[] areas; Geometry.GetRawData(out vertices, out triangles, out areas); Geometry.Triangles.Clear(); Geometry.Vertices.Clear(); // add border bbMin[0] -= Config.BorderSize * Config.CellSize; bbMin[2] -= Config.BorderSize * Config.CellSize; bbMax[0] += Config.BorderSize * Config.CellSize; bbMax[2] += Config.BorderSize * Config.CellSize; Heightfield hf; int width = Config.TileWidth + (Config.BorderSize * 2); if (!Context.CreateHeightfield(out hf, width, width, bbMin, bbMax, Config.CellSize, Config.CellHeight)) { throw new OutOfMemoryException("CreateHeightfield ran out of memory"); } Context.ClearUnwalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles, areas); Context.RasterizeTriangles(ref vertices, ref triangles, ref areas, hf, Config.WalkableClimb); // Once all geometry is rasterized, we do initial pass of filtering to // remove unwanted overhangs caused by the conservative rasterization // as well as filter spans where the character cannot possibly stand. Context.FilterLowHangingWalkableObstacles(Config.WalkableClimb, hf); Context.FilterLedgeSpans(Config.WalkableHeight, Config.WalkableClimb, hf); Context.FilterWalkableLowHeightSpans(Config.WalkableHeight, hf); // Compact the heightfield so that it is faster to handle from now on. // This will result in more cache coherent data as well as the neighbours // between walkable cells will be calculated. CompactHeightfield chf; if (!Context.BuildCompactHeightfield(Config.WalkableHeight, Config.WalkableClimb, hf, out chf)) { throw new OutOfMemoryException("BuildCompactHeightfield ran out of memory"); } hf.Delete(); // Erode the walkable area by agent radius. if (!Context.ErodeWalkableArea(Config.WalkableRadius, chf)) { throw new OutOfMemoryException("ErodeWalkableArea ran out of memory"); } // Prepare for region partitioning, by calculating distance field along the walkable surface. if (!Context.BuildDistanceField(chf)) { throw new OutOfMemoryException("BuildDistanceField ran out of memory"); } // Partition the walkable surface into simple regions without holes. if (!Context.BuildRegions(chf, Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea)) { throw new OutOfMemoryException("BuildRegionsMonotone ran out of memory"); } // Create contours. ContourSet cset; if (!Context.BuildContours(chf, Config.MaxSimplificationError, Config.MaxEdgeLength, out cset)) { throw new OutOfMemoryException("BuildContours ran out of memory"); } // Build polygon navmesh from the contours. PolyMesh pmesh; if (!Context.BuildPolyMesh(cset, Config.MaxVertsPerPoly, out pmesh)) { throw new OutOfMemoryException("BuildPolyMesh ran out of memory"); } // Build detail mesh. PolyMeshDetail dmesh; if ( !Context.BuildPolyMeshDetail(pmesh, chf, Config.DetailSampleDistance, Config.DetailSampleMaxError, out dmesh)) { throw new OutOfMemoryException("BuildPolyMeshDetail ran out of memory"); } chf.Delete(); cset.Delete(); // Remove padding from the polymesh data. (Remove this odditity) pmesh.RemovePadding(Config.BorderSize); // Set flags according to area types (e.g. Swim for Water) pmesh.MarkAll(); // get original bounds float[] tilebMin, tilebMax; CalculateTileBounds(out tilebMin, out tilebMax); tilebMin[1] = bbMin[1]; tilebMax[1] = bbMax[1]; // build off mesh connections for flightmasters // bMax and bMin are switched here because of the coordinate system transformation /// This is not needed for our particular use. var connections = new List <OffMeshConnection>(); /*var taxis = TaxiHelper.GetNodesInBBox(MapId, tilebMax.ToWoW(), tilebMin.ToWoW()); * foreach (var taxi in taxis) * { * Log.Log(LogCategory.Warning, * "Flightmaster \"" + taxi.Name + "\", Id: " + taxi.Id + " Horde: " + taxi.IsHorde + " Alliance: " + * taxi.IsAlliance); * * var data = TaxiHelper.GetTaxiData(taxi); * var from = taxi.Location.ToRecast().ToFloatArray(); * connections.AddRange(data.To.Select(to => new OffMeshConnection * { * AreaId = PolyArea.Road, * Flags = PolyFlag.FlightMaster, * From = from, * To = to.Value.Location.ToRecast().ToFloatArray(), * Radius = Config.WorldWalkableRadius, * Type = ConnectionType.OneWay, * UserID = (uint) to.Key * })); * * foreach (var target in data.To) * Log.Log(LogCategory.Warning, * "\tPath to: \"" + target.Value.Name + "\" Id: " + target.Value.Id + " Path Id: " + * target.Key); * }*/ byte[] tileData; if (!Detour.CreateNavMeshData(out tileData, pmesh, dmesh, X, Y, tilebMin, tilebMax, Config.WorldWalkableHeight, Config.WorldWalkableRadius, Config.WorldWalkableClimb, Config.CellSize, Config.CellHeight, Config.TileWidth, connections.ToArray())) { pmesh.Delete(); dmesh.Delete(); return(null); } pmesh.Delete(); dmesh.Delete(); Cache.Clear(); GC.Collect(); return(tileData); }
public byte[] Build(BaseLog log) { var wdt = new WDT("World\\maps\\" + Dungeon + "\\" + Dungeon + ".wdt"); if (!wdt.IsGlobalModel || !wdt.IsValid) return null; InitializeProgress(12); Geometry = new Geometry {Transform = true}; var model = new WorldModelRoot(wdt.ModelFile); Geometry.AddDungeon(model, wdt.ModelDefinition); CompleteWorkUnit(); if (Geometry.Vertices.Count == 0 && Geometry.Triangles.Count == 0) throw new InvalidOperationException("Can't build mesh with empty geometry"); Log = log; Context = new RecastContext(); Context.SetContextHandler(Log); // get raw geometry - lots of slowness here float[] vertices; int[] triangles; byte[] areas; Geometry.GetRawData(out vertices, out triangles, out areas); Geometry.Triangles.Clear(); float[] bmin, bmax; Geometry.CalculateBoundingBox(out bmin, out bmax); Geometry.Vertices.Clear(); // Allocate voxel heightfield where we rasterize our input data to. Heightfield hf; int width, height; Recast.CalcGridSize(bmin, bmax, Config.CellSize, out width, out height); if (!Context.CreateHeightfield(out hf, width, height, bmin, bmax, Config.CellSize, Config.CellHeight)) throw new OutOfMemoryException("CreateHeightfield ran out of memory"); CompleteWorkUnit(); // Find triangles which are walkable based on their slope and rasterize them. Context.ClearUnwalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles, areas); Context.RasterizeTriangles(ref vertices, ref triangles, ref areas, hf, Config.WalkableClimb); CompleteWorkUnit(); // Once all geometry is rasterized, we do initial pass of filtering to // remove unwanted overhangs caused by the conservative rasterization // as well as filter spans where the character cannot possibly stand. Context.FilterLowHangingWalkableObstacles(Config.WalkableClimb, hf); Context.FilterLedgeSpans(Config.WalkableHeight, Config.WalkableClimb, hf); Context.FilterWalkableLowHeightSpans(Config.WalkableHeight, hf); CompleteWorkUnit(); // Compact the heightfield so that it is faster to handle from now on. // This will result in more cache coherent data as well as the neighbours // between walkable cells will be calculated. CompactHeightfield chf; if (!Context.BuildCompactHeightfield(Config.WalkableHeight, Config.WalkableClimb, hf, out chf)) throw new OutOfMemoryException("BuildCompactHeightfield ran out of memory"); CompleteWorkUnit(); hf.Delete(); // Erode the walkable area by agent radius. if (!Context.ErodeWalkableArea(Config.WalkableRadius, chf)) throw new OutOfMemoryException("ErodeWalkableArea ran out of memory"); CompleteWorkUnit(); // Prepare for region partitioning, by calculating distance field along the walkable surface. if (!Context.BuildDistanceField(chf)) throw new OutOfMemoryException("BuildDistanceField ran out of memory"); CompleteWorkUnit(); // Partition the walkable surface into simple regions without holes. if (!Context.BuildRegions(chf, Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea)) throw new OutOfMemoryException("BuildRegions ran out of memory"); CompleteWorkUnit(); // Create contours. ContourSet cset; if (!Context.BuildContours(chf, Config.MaxSimplificationError, Config.MaxEdgeLength, out cset)) throw new OutOfMemoryException("BuildContours ran out of memory"); CompleteWorkUnit(); // Build polygon navmesh from the contours. PolyMesh pmesh; if (!Context.BuildPolyMesh(cset, Config.MaxVertsPerPoly, out pmesh)) throw new OutOfMemoryException("BuildPolyMesh ran out of memory"); CompleteWorkUnit(); // Build detail mesh. PolyMeshDetail dmesh; if (!Context.BuildPolyMeshDetail(pmesh, chf, Config.DetailSampleDistance, Config.DetailSampleMaxError, out dmesh)) throw new OutOfMemoryException("BuildPolyMeshDetail ran out of memory"); CompleteWorkUnit(); chf.Delete(); cset.Delete(); // Set flags according to area types (e.g. Swim for Water) pmesh.MarkAll(); byte[] meshData; if (!Detour.CreateNavMeshData(out meshData, pmesh, dmesh, 0, 0, bmin, bmax, Config.WorldWalkableHeight, Config.WorldWalkableRadius, Config.WorldWalkableClimb, Config.CellSize, Config.CellHeight, Config.TileWidth, null)) { pmesh.Delete(); dmesh.Delete(); return null; } CompleteWorkUnit(); pmesh.Delete(); dmesh.Delete(); return meshData; }
public byte[] Build(BaseLog log) { Log = log; Geometry = new Geometry {Transform = true}; { var main = new ADT(GetAdtPath(World, X, Y)); main.Read(); Geometry.AddAdt(main); } if (Geometry.Vertices.Count == 0 && Geometry.Triangles.Count == 0) throw new InvalidOperationException("Can't build tile with empty geometry"); float[] bbMin, bbMax; CalculateTileBounds(out bbMin, out bbMax); Geometry.CalculateMinMaxHeight(out bbMin[1], out bbMax[1]); // again, we load everything - wasteful but who cares for (int ty = Y - 1; ty <= Y + 1; ty++) { for (int tx = X - 1; tx <= X + 1; tx++) { try { // don't load main tile again if (tx == X && ty == Y) continue; var adt = new ADT(GetAdtPath(World, tx, ty)); adt.Read(); Geometry.AddAdt(adt); } catch (FileNotFoundException) { // don't care - no file means no geometry } } } Context = new RecastContext(); Context.SetContextHandler(Log); // get raw geometry - lots of slowness here float[] vertices; int[] triangles; byte[] areas; Geometry.GetRawData(out vertices, out triangles, out areas); Geometry.Triangles.Clear(); Geometry.Vertices.Clear(); // add border bbMin[0] -= Config.BorderSize*Config.CellSize; bbMin[2] -= Config.BorderSize*Config.CellSize; bbMax[0] += Config.BorderSize*Config.CellSize; bbMax[2] += Config.BorderSize*Config.CellSize; Heightfield hf; int width = Config.TileWidth + (Config.BorderSize*2); if (!Context.CreateHeightfield(out hf, width, width, bbMin, bbMax, Config.CellSize, Config.CellHeight)) throw new OutOfMemoryException("CreateHeightfield ran out of memory"); Context.ClearUnwalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles, areas); Context.RasterizeTriangles(ref vertices, ref triangles, ref areas, hf, Config.WalkableClimb); // Once all geometry is rasterized, we do initial pass of filtering to // remove unwanted overhangs caused by the conservative rasterization // as well as filter spans where the character cannot possibly stand. Context.FilterLowHangingWalkableObstacles(Config.WalkableClimb, hf); Context.FilterLedgeSpans(Config.WalkableHeight, Config.WalkableClimb, hf); Context.FilterWalkableLowHeightSpans(Config.WalkableHeight, hf); // Compact the heightfield so that it is faster to handle from now on. // This will result in more cache coherent data as well as the neighbours // between walkable cells will be calculated. CompactHeightfield chf; if (!Context.BuildCompactHeightfield(Config.WalkableHeight, Config.WalkableClimb, hf, out chf)) throw new OutOfMemoryException("BuildCompactHeightfield ran out of memory"); hf.Delete(); // Erode the walkable area by agent radius. if (!Context.ErodeWalkableArea(Config.WalkableRadius, chf)) throw new OutOfMemoryException("ErodeWalkableArea ran out of memory"); // Prepare for region partitioning, by calculating distance field along the walkable surface. if (!Context.BuildDistanceField(chf)) throw new OutOfMemoryException("BuildDistanceField ran out of memory"); // Partition the walkable surface into simple regions without holes. if (!Context.BuildRegions(chf, Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea)) throw new OutOfMemoryException("BuildRegionsMonotone ran out of memory"); // Create contours. ContourSet cset; if (!Context.BuildContours(chf, Config.MaxSimplificationError, Config.MaxEdgeLength, out cset)) throw new OutOfMemoryException("BuildContours ran out of memory"); // Build polygon navmesh from the contours. PolyMesh pmesh; if (!Context.BuildPolyMesh(cset, Config.MaxVertsPerPoly, out pmesh)) throw new OutOfMemoryException("BuildPolyMesh ran out of memory"); // Build detail mesh. PolyMeshDetail dmesh; if ( !Context.BuildPolyMeshDetail(pmesh, chf, Config.DetailSampleDistance, Config.DetailSampleMaxError, out dmesh)) throw new OutOfMemoryException("BuildPolyMeshDetail ran out of memory"); chf.Delete(); cset.Delete(); // Remove padding from the polymesh data. (Remove this odditity) pmesh.RemovePadding(Config.BorderSize); // Set flags according to area types (e.g. Swim for Water) pmesh.MarkAll(); // get original bounds float[] tilebMin, tilebMax; CalculateTileBounds(out tilebMin, out tilebMax); tilebMin[1] = bbMin[1]; tilebMax[1] = bbMax[1]; // build off mesh connections for flightmasters // bMax and bMin are switched here because of the coordinate system transformation var taxis = TaxiHelper.GetNodesInBBox(MapId, tilebMax.ToWoW(), tilebMin.ToWoW()); var connections = new List<OffMeshConnection>(); foreach (var taxi in taxis) { Log.Log(LogCategory.Warning, "Flightmaster \"" + taxi.Name + "\", Id: " + taxi.Id + " Horde: " + taxi.IsHorde + " Alliance: " + taxi.IsAlliance); var data = TaxiHelper.GetTaxiData(taxi); var from = taxi.Location.ToRecast().ToFloatArray(); connections.AddRange(data.To.Select(to => new OffMeshConnection { AreaId = PolyArea.Road, Flags = PolyFlag.FlightMaster, From = from, To = to.Value.Location.ToRecast().ToFloatArray(), Radius = Config.WorldWalkableRadius, Type = ConnectionType.OneWay, UserID = (uint) to.Key })); foreach (var target in data.To) Log.Log(LogCategory.Warning, "\tPath to: \"" + target.Value.Name + "\" Id: " + target.Value.Id + " Path Id: " + target.Key); } byte[] tileData; if (!Detour.CreateNavMeshData(out tileData, pmesh, dmesh, X, Y, tilebMin, tilebMax, Config.WorldWalkableHeight, Config.WorldWalkableRadius, Config.WorldWalkableClimb, Config.CellSize, Config.CellHeight, Config.TileWidth, connections.ToArray())) { pmesh.Delete(); dmesh.Delete(); return null; } pmesh.Delete(); dmesh.Delete(); Cache.Clear(); GC.Collect(); return tileData; }
public byte[] Build(BaseLog log) { var wdt = new WDT("World\\maps\\" + Dungeon + "\\" + Dungeon + ".wdt"); if (!wdt.IsGlobalModel || !wdt.IsValid) { return(null); } InitializeProgress(12); Geometry = new Geometry { Transform = true }; var model = new WorldModelRoot(wdt.ModelFile); Geometry.AddDungeon(model, wdt.ModelDefinition); CompleteWorkUnit(); if (Geometry.Vertices.Count == 0 && Geometry.Triangles.Count == 0) { throw new InvalidOperationException("Can't build mesh with empty geometry"); } Log = log; Context = new RecastContext(); Context.SetContextHandler(Log); // get raw geometry - lots of slowness here float[] vertices; int[] triangles; byte[] areas; Geometry.GetRawData(out vertices, out triangles, out areas); Geometry.Triangles.Clear(); float[] bmin, bmax; Geometry.CalculateBoundingBox(out bmin, out bmax); Geometry.Vertices.Clear(); // Allocate voxel heightfield where we rasterize our input data to. Heightfield hf; int width, height; Recast.CalcGridSize(bmin, bmax, Config.CellSize, out width, out height); if (!Context.CreateHeightfield(out hf, width, height, bmin, bmax, Config.CellSize, Config.CellHeight)) { throw new OutOfMemoryException("CreateHeightfield ran out of memory"); } CompleteWorkUnit(); // Find triangles which are walkable based on their slope and rasterize them. Context.ClearUnwalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles, areas); Context.RasterizeTriangles(ref vertices, ref triangles, ref areas, hf, Config.WalkableClimb); CompleteWorkUnit(); // Once all geometry is rasterized, we do initial pass of filtering to // remove unwanted overhangs caused by the conservative rasterization // as well as filter spans where the character cannot possibly stand. Context.FilterLowHangingWalkableObstacles(Config.WalkableClimb, hf); Context.FilterLedgeSpans(Config.WalkableHeight, Config.WalkableClimb, hf); Context.FilterWalkableLowHeightSpans(Config.WalkableHeight, hf); CompleteWorkUnit(); // Compact the heightfield so that it is faster to handle from now on. // This will result in more cache coherent data as well as the neighbours // between walkable cells will be calculated. CompactHeightfield chf; if (!Context.BuildCompactHeightfield(Config.WalkableHeight, Config.WalkableClimb, hf, out chf)) { throw new OutOfMemoryException("BuildCompactHeightfield ran out of memory"); } CompleteWorkUnit(); hf.Delete(); // Erode the walkable area by agent radius. if (!Context.ErodeWalkableArea(Config.WalkableRadius, chf)) { throw new OutOfMemoryException("ErodeWalkableArea ran out of memory"); } CompleteWorkUnit(); // Prepare for region partitioning, by calculating distance field along the walkable surface. if (!Context.BuildDistanceField(chf)) { throw new OutOfMemoryException("BuildDistanceField ran out of memory"); } CompleteWorkUnit(); // Partition the walkable surface into simple regions without holes. if (!Context.BuildRegions(chf, Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea)) { throw new OutOfMemoryException("BuildRegions ran out of memory"); } CompleteWorkUnit(); // Create contours. ContourSet cset; if (!Context.BuildContours(chf, Config.MaxSimplificationError, Config.MaxEdgeLength, out cset)) { throw new OutOfMemoryException("BuildContours ran out of memory"); } CompleteWorkUnit(); // Build polygon navmesh from the contours. PolyMesh pmesh; if (!Context.BuildPolyMesh(cset, Config.MaxVertsPerPoly, out pmesh)) { throw new OutOfMemoryException("BuildPolyMesh ran out of memory"); } CompleteWorkUnit(); // Build detail mesh. PolyMeshDetail dmesh; if (!Context.BuildPolyMeshDetail(pmesh, chf, Config.DetailSampleDistance, Config.DetailSampleMaxError, out dmesh)) { throw new OutOfMemoryException("BuildPolyMeshDetail ran out of memory"); } CompleteWorkUnit(); chf.Delete(); cset.Delete(); // Set flags according to area types (e.g. Swim for Water) pmesh.MarkAll(); byte[] meshData; if (!Detour.CreateNavMeshData(out meshData, pmesh, dmesh, 0, 0, bmin, bmax, Config.WorldWalkableHeight, Config.WorldWalkableRadius, Config.WorldWalkableClimb, Config.CellSize, Config.CellHeight, Config.TileWidth, null)) { pmesh.Delete(); dmesh.Delete(); return(null); } CompleteWorkUnit(); pmesh.Delete(); dmesh.Delete(); return(meshData); }
public void use_64bit_polyref() { Assert.IsTrue(RecastContext.IsUsing64BitPolyRefs()); }