private void OnFloorWithDynamicObjectsChanged() { FloorWithDynamicObjects.CalculateConstrainedEdges(); NavigationMesh.Initialize(FloorWithDynamicObjects); Pathfinding = new AStar(NavigationMesh, FloorWithDynamicObjects); foreach (var unit in AllUnits) { unit.OnPathRecalculationNeeded(); } }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var intermediateDataId = ComputeAssetIntermediateDataId(); // Build cache items to build incrementally currentBuild = new NavigationMeshCachedBuild(); oldBuild = LoadIntermediateData(intermediateDataId); // The output object of the compilation NavigationMesh generatedNavigationMesh = new NavigationMesh(); // No scene specified, result in failure if (asset.Scene == null) { return(Task.FromResult(ResultStatus.Failed)); } if (asset.AutoGenerateBoundingBox) { generateBoundingBox = true; globalBoundingBox = BoundingBox.Empty; } else { generateBoundingBox = false; globalBoundingBox = asset.BoundingBox; } // Copy build settings so we can modify them buildSettings = asset.BuildSettings; // Check for tile size if (buildSettings.TileSize <= 0) { return(Task.FromResult(ResultStatus.Failed)); } // Clone scene, obtain hash and load collider shape assets EnsureClonedSceneAndHash(); if (clonedSceneAsset == null) { return(Task.FromResult(ResultStatus.Failed)); } // This collects all the input geometry, calculates the modified areas and calculates the scene bounds CollectInputGeometry(); List <BoundingBox> removedAreas = oldBuild?.GetRemovedAreas(sceneEntities); BoundingBox boundingBox = globalBoundingBox; // Can't generate when no bounding box or and invalid bounding box is specified // this means that either the user specified bounding box is wrong or the scene does not contain any colliders if (boundingBox.Extent.X > 0 && boundingBox.Extent.Y > 0 && boundingBox.Extent.Z > 0) { // Turn generated data into arrays Vector3[] meshVertices = sceneNavigationMeshInputBuilder.Points.ToArray(); int[] meshIndices = sceneNavigationMeshInputBuilder.Indices.ToArray(); // NOTE: Reversed winding order as input to recast int numSrcTriangles = meshIndices.Length / 3; for (int i = 0; i < numSrcTriangles; i++) { int j = meshIndices[i * 3 + 1]; meshIndices[i * 3 + 1] = meshIndices[i * 3 + 2]; meshIndices[i * 3 + 2] = j; } // Check if settings changed to trigger a full rebuild int currentSettingsHash = asset.GetHashCode(); currentBuild.SettingsHash = currentSettingsHash; if (oldBuild != null && oldBuild.SettingsHash != currentBuild.SettingsHash) { fullRebuild = true; } if (oldBuild != null && !fullRebuild) { // Perform incremental build on old navigation mesh generatedNavigationMesh = oldBuild.NavigationMesh; } // Initialize navigation mesh for building generatedNavigationMesh.Initialize(buildSettings, asset.NavigationMeshAgentSettings.ToArray()); // Set the new navigation mesh in the current build currentBuild.NavigationMesh = generatedNavigationMesh; // Generate all the layers corresponding to the various agent settings for (int layer = 0; layer < asset.NavigationMeshAgentSettings.Count; layer++) { Stopwatch layerBuildTimer = new Stopwatch(); layerBuildTimer.Start(); var agentSetting = asset.NavigationMeshAgentSettings[layer]; // Flag tiles to build for this specific layer HashSet <Point> tilesToBuild = new HashSet <Point>(); if (fullRebuild) { // For full rebuild just take the root bounding box for selecting tiles to build List <Point> newTileList = NavigationMeshBuildUtils.GetOverlappingTiles(buildSettings, boundingBox); foreach (Point p in newTileList) { tilesToBuild.Add(p); } } else { // Apply an offset so their neighbouring tiles which are affected by the agent radius also get rebuild Vector3 agentOffset = new Vector3(agentSetting.Radius, 0, agentSetting.Radius); if (removedAreas != null) { updatedAreas.AddRange(removedAreas); } foreach (var update in updatedAreas) { BoundingBox agentSpecificBoundingBox = new BoundingBox { Minimum = update.Minimum - agentOffset, Maximum = update.Maximum + agentOffset, }; List <Point> newTileList = NavigationMeshBuildUtils.GetOverlappingTiles(buildSettings, agentSpecificBoundingBox); foreach (Point p in newTileList) { tilesToBuild.Add(p); } } } // Build tiles foreach (var tileToBuild in tilesToBuild) { BoundingBox tileBoundingBox = NavigationMeshBuildUtils.ClampBoundingBoxToTile(buildSettings, boundingBox, tileToBuild); // Check if tile bounding box is contained withing the navigation mesh bounding box if (boundingBox.Contains(ref tileBoundingBox) == ContainmentType.Disjoint) { // Remove this tile generatedNavigationMesh.Layers[layer].RemoveLayerTile(tileToBuild); continue; } // Build the tile for the current layer being processed generatedNavigationMesh.Layers[layer].BuildTile(meshVertices.ToArray(), meshIndices.ToArray(), tileBoundingBox, tileToBuild); } } } // Store used bounding box in navigation mesh generatedNavigationMesh.BoundingBox = boundingBox; contentManager.Save(assetUrl, generatedNavigationMesh); SaveIntermediateData(intermediateDataId, currentBuild); return(Task.FromResult(ResultStatus.Successful)); }