Exemple #1
0
        // Only grid cells connected vis cells with Walk movement flags will be treated as neighbours
        public void AddNeighbour(GridCell grid_cell)
        {
            if (AABB.Intersect(grid_cell.AABB, true) == null)
                return;

            if (Neighbours.Exists(x => x.cell.Equals(grid_cell)))
                return;

            bool any_cells_connected = false;
            MovementFlag connection_flags = MovementFlag.None;

            foreach (Cell our_cell in Cells)
            {
                foreach (Cell other_cell in grid_cell.Cells)
                {
                    bool cells_connected = our_cell.AddNeighbour(other_cell);

                    if (cells_connected)
                    {
                        any_cells_connected = true;
                        MovementFlag flags = our_cell.Flags & other_cell.Flags;

                        if (flags > connection_flags)
                            connection_flags = flags;
                    }
                }
            }

            if (any_cells_connected)
            {
                Neighbours.Add(new Neighbour(grid_cell, null, connection_flags));
                grid_cell.Neighbours.Add(new Neighbour(this, null, connection_flags));
            }
        }
Exemple #2
0
        public static void Render(Nav.GridCell cell, PointF trans, PaintEventArgs e, bool draw_connections, bool draw_id)
        {
            DrawRectangle(e.Graphics, Pens.Black, trans, cell.Min, cell.Max);

            if (draw_connections)
            {
                foreach (Nav.Cell.Neighbour neighbour in cell.Neighbours)
                {
                    DrawLine(e.Graphics, GRID_CELL_CONNECTION_PEN, trans, cell.Center, neighbour.cell.Center);
                }
            }

            if (draw_id)
            {
                DrawString(e.Graphics, Brushes.Black, trans, cell.Min, cell.GlobalId.ToString() + " (" + cell.Id.ToString() + ")", 15);
            }
        }
Exemple #3
0
        public bool Load(string filename, bool clear = true, bool force_update_align_plane = false)
        {
            if (filename == null)
            {
                return(false);
            }

            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

            //using (new Profiler("[Nav] Loaded nav data [%t]"))
            {
                if (clear)
                {
                    Clear();
                }

                try
                {
                    StreamReader stream = new StreamReader(filename);

                    if (stream != null)
                    {
                        string   line;
                        GridCell g_cell                   = null;
                        Vec3     cell_shrink_size         = Vec3.Empty;
                        HashSet <region_data> avoid_areas = new HashSet <region_data>();

                        while ((line = stream.ReadLine()) != null)
                        {
                            string[] data = line.Split(' ');

                            if (data[0] == "g")
                            {
                                // add previous grid cell
                                Add(g_cell, false);

                                m_LastCellId = 0;

                                g_cell = new GridCell(float.Parse(data[1]), float.Parse(data[2]), float.Parse(data[3]), float.Parse(data[4]), float.Parse(data[5]), float.Parse(data[6]), (data.Length > 7 ? int.Parse(data[7]) : m_LastGridCellId++));
                            }
                            else if (data[0] == "n")
                            {
                                MovementFlag flags = MovementFlag.Walk | MovementFlag.Fly;

                                if (data.Length > 7)
                                {
                                    flags = (MovementFlag)int.Parse(data[7]);
                                }

                                Cell n_cell = new Cell(new Vec3(float.Parse(data[1]), float.Parse(data[2]), float.Parse(data[3])) - cell_shrink_size, new Vec3(float.Parse(data[4]), float.Parse(data[5]), float.Parse(data[6])) - cell_shrink_size, flags, m_LastCellId++);
                                g_cell.Add(n_cell);
                            }
                            else if (data[0] == "r")
                            {
                                avoid_areas.Add(new region_data(new AABB(float.Parse(data[1]), float.Parse(data[2]), float.Parse(data[3]), float.Parse(data[4]), float.Parse(data[5]), float.Parse(data[6])), float.Parse(data[7])));
                            }
                        }

                        // add last grid cell
                        Add(g_cell, false);

                        if (force_update_align_plane)
                        {
                            using (new ReadLock(DataLock))
                            {
                                foreach (Cell c in m_AllCells)
                                {
                                    c.UpdateAlignPlane();
                                }
                            }
                        }

                        Random   rng = new Random();
                        GridCell random_grid_cell = null;

                        random_grid_cell = m_GridCells.ElementAt(rng.Next(m_GridCells.Count));

                        NotifyOnNavDataChanged();

                        Regions = avoid_areas;

                        Log("[Nav] Navmesh loaded.");

                        stream.Close();

                        return(true);
                    }
                }
                catch (Exception)
                {
                }

                Log("[Nav] Navmesh load failed!");

                return(false);
            }
        }
        internal void OnGridCellAdded(GridCell grid_cell, bool trigger_nav_data_change = true)
        {
            //using (new Profiler("[Nav] Nav data updated [{t}]"))
            using (new ReadLock(DataLock, true))
            {
                // remove explore cells overlapping with grid cell
                List<ExploreCell> cells_to_validate = m_ExploreCells.FindAll(x => x.Overlaps2D(grid_cell));

                using (new WriteLock(DataLock))
                {
                    foreach (ExploreCell explore_cell in cells_to_validate)
                    {
                        explore_cell.Detach();
                        m_ExploreCells.RemoveAll(x => x.GlobalId == explore_cell.GlobalId);
                        m_ExploreCellsDistancer.Disconnect(explore_cell.GlobalId);
                    }
                }

                // check if new explore cells should be added
                int x_min = (int)Math.Floor(grid_cell.Min.X / EXPLORE_CELL_SIZE);
                int y_min = (int)Math.Floor(grid_cell.Min.Y / EXPLORE_CELL_SIZE);

                int x_max = (int)Math.Ceiling(grid_cell.Max.X / EXPLORE_CELL_SIZE);
                int y_max = (int)Math.Ceiling(grid_cell.Max.Y / EXPLORE_CELL_SIZE);

                int explore_cells_generated = 0;

                for (int y_index = y_min; y_index < y_max; ++y_index)
                {
                    for (int x_index = x_min; x_index < x_max; ++x_index)
                    {
                        AABB cell_aabb = new AABB(x_index * EXPLORE_CELL_SIZE, y_index * EXPLORE_CELL_SIZE, -10000,
                                                  (x_index + 1) * EXPLORE_CELL_SIZE, (y_index + 1) * EXPLORE_CELL_SIZE, 10000);

                        explore_cells_generated += GenerateExploreCells(cell_aabb);
                    }
                }

                if (explore_cells_generated > 0)
                    Navmesh.Log("[Nav] " + explore_cells_generated + " explore cell(s) generated");
            }

            //due to performance reasons OnNavDataChange is not automatically called after adding each grid cell
            if (trigger_nav_data_change)
                OnNavDataChange();
        }
Exemple #5
0
        private void UpdateRegions()
        {
            // copy current regions to avoid acquiring lock later
            HashSet <region_data> regions_copy = Regions;

            using (new WriteLock(DataLock))
            //using (new Profiler($"Updatind {m_Regions.Count} regions took %t"))
            {
                foreach (var data in m_CellsOverlappedByRegions)
                {
                    data.Value.areas.Clear();
                }

                if (RegionsEnabled)
                {
                    // update cells overlapped by avoid areas
                    foreach (region_data region in regions_copy)
                    {
                        var         g_cells = m_GridCells.Where(x => x.AABB.Overlaps2D(region.area));
                        List <Cell> cells   = new List <Cell>();

                        // do not ignore disabled cells on purpose so we don't have to iterate separately over
                        foreach (GridCell g_cell in g_cells)
                        {
                            cells.AddRange(g_cell.Cells.FindAll(x => !x.Replacement && x.HasFlags(MovementFlag.Walk) && x.AABB.Overlaps2D(region.area)));
                        }

                        foreach (Cell cell in cells)
                        {
                            overlapped_cell_data data = null;
                            if (!m_CellsOverlappedByRegions.TryGetValue(cell.GlobalId, out data))
                            {
                                m_CellsOverlappedByRegions[cell.GlobalId] = data = new overlapped_cell_data(cell);
                            }

                            data.areas.Add(new region_data(region));
                        }
                    }
                }

                List <int> inactive_keys    = new List <int>();
                bool       anything_changed = false;

                // perform rectangulation
                foreach (var item in m_CellsOverlappedByRegions)
                {
                    // no longer overlapped
                    if (item.Value.areas.Count == 0)
                    {
                        inactive_keys.Add(item.Key);
                    }

                    overlapped_cell_data data = item.Value;

                    if (!data.areas.SetEquals(data.last_areas))
                    {
                        anything_changed = true;

                        GridCell parent_grid_cell = GetGridCell(data.replaced_cell.Center);

                        // grid cell containing this replacement has been removed
                        if (parent_grid_cell == null)
                        {
                            continue;
                        }

                        List <Cell> potential_neighbors = data.replaced_cell.Neighbours.Select(x => x.cell).ToList();

                        {
                            // disable original cell
                            if (data.last_areas.Count == 0)
                            {
                                data.replaced_cell.Disabled = true;
                            }

                            // remove previous replacement cells
                            foreach (Cell replacement_cell in data.replacement_cells)
                            {
                                parent_grid_cell.Remove(replacement_cell);
                                m_AllCells.Remove(replacement_cell);
                            }

                            data.replacement_cells.Clear();
                        }

                        if (data.areas.Count > 0)
                        {
                            // generate new replacement cells
                            data.replacement_cells.Add(data.replaced_cell);

                            foreach (region_data region in data.areas)
                            {
                                List <Cell> cells_to_check = new List <Cell>(data.replacement_cells);

                                foreach (Cell c in cells_to_check)
                                {
                                    AABB[] extracted = c.AABB.Extract2D(region.area);

                                    if (extracted != null)
                                    {
                                        data.replacement_cells.Remove(c);

                                        for (int k = 0; k < extracted.Length; ++k)
                                        {
                                            // in case of negative movement cost treat this region as dynamic obstacle
                                            if (region.move_cost_mult < 0 && k == 0)
                                            {
                                                continue;
                                            }

                                            float movement_cost_mult = c.MovementCostMult;

                                            // first cell is always the one overlapped by region
                                            if (k == 0)
                                            {
                                                if (RegionsMoveCostMode == RegionsMode.Mult)
                                                {
                                                    movement_cost_mult *= region.move_cost_mult;
                                                }
                                                else if (RegionsMoveCostMode == RegionsMode.Max)
                                                {
                                                    if (movement_cost_mult < 1 && region.move_cost_mult < 1)
                                                    {
                                                        movement_cost_mult = Math.Min(region.move_cost_mult, movement_cost_mult);
                                                    }
                                                    else
                                                    {
                                                        movement_cost_mult = Math.Max(region.move_cost_mult, movement_cost_mult);
                                                    }
                                                }
                                            }

                                            Cell r_cell = new Cell(extracted[k], data.replaced_cell.Flags, movement_cost_mult);
                                            r_cell.Replacement = true;
                                            data.replacement_cells.Add(r_cell);
                                        }
                                    }
                                }
                            }

                            // try to connect new replacement cells with potential neighbors
                            foreach (Cell replacement_cell in data.replacement_cells)
                            {
                                Vec3 border_point = null;

                                foreach (Cell potential_neighbor in potential_neighbors)
                                {
                                    replacement_cell.AddNeighbour(potential_neighbor, ref border_point);
                                }

                                parent_grid_cell.Cells.Add(replacement_cell);
                                m_AllCells.Add(replacement_cell);

                                // this cell is now potential neighbor as well, because can be interconnected with other replacement cells!
                                potential_neighbors.Add(replacement_cell);
                            }
                        }

                        item.Value.last_areas = new HashSet <region_data>(item.Value.areas);

                        // enable original cell when no longer overlapped
                        if (data.areas.Count == 0)
                        {
                            data.replaced_cell.Disabled = false;
                        }

                        m_CellsCache.Clear();
                    }
                }

                if (anything_changed)
                {
                    NotifyOnNavDataChanged();
                }

                // remove inactive data
                foreach (int key in inactive_keys)
                {
                    m_CellsOverlappedByRegions.Remove(key);
                }
            }
        }
Exemple #6
0
        protected virtual void OnDeserialize(BinaryReader r)
        {
            using (new WriteLock(DataLock))
                using (new WriteLock(InputLock))
                {
                    //using (new Profiler("Navmesh deserialization took %t"))
                    {
                        m_AllCells.Clear();
                        m_GridCells.Clear();
                        m_Regions.Clear();
                        m_CellsOverlappedByRegions.Clear();

                        Cell.CompareByGlobalId comp_by_global_id = new Cell.CompareByGlobalId();

                        int all_cells_count = r.ReadInt32();

                        // pre-allocate cells
                        for (int i = 0; i < all_cells_count; ++i)
                        {
                            Cell cell = new Cell(0, 0, 0, 0, 0, 0, MovementFlag.None);
                            cell.GlobalId = r.ReadInt32();
                            m_AllCells.Add(cell);
                        }

                        foreach (Cell cell in m_AllCells)
                        {
                            cell.Deserialize(m_AllCells, r);
                        }

                        Cell.LastCellGlobalId = r.ReadInt32();

                        int grid_cells_count = r.ReadInt32();

                        // pre-allocate grid cells
                        for (int i = 0; i < grid_cells_count; ++i)
                        {
                            GridCell grid_cell = new GridCell(0, 0, 0, 0, 0, 0);
                            grid_cell.GlobalId = r.ReadInt32();
                            m_GridCells.Add(grid_cell);
                        }

                        foreach (GridCell grid_cell in m_GridCells)
                        {
                            grid_cell.Deserialize(m_GridCells, m_AllCells, r);
                        }

                        GridCell.LastGridCellGlobalId = r.ReadInt32();

                        List <CellsPatch> patches = new List <CellsPatch>();
                        int patches_count         = r.ReadInt32();

                        // pre-allocate patches
                        for (int i = 0; i < patches_count; ++i)
                        {
                            CellsPatch patch = new CellsPatch(new HashSet <Cell>(), MovementFlag.None);
                            patch.GlobalId = r.ReadInt32();
                            patches.Add(patch);
                        }

                        foreach (CellsPatch patch in patches)
                        {
                            patch.Deserialize(m_AllCells, r);
                        }

                        m_CellsPatches = new HashSet <CellsPatch>(patches);

                        CellsPatch.LastCellsPatchGlobalId = r.ReadInt32();

                        int regions_count = r.ReadInt32();
                        for (int i = 0; i < regions_count; ++i)
                        {
                            m_Regions.Add(new region_data(r));
                        }

                        int cells_overlapped_by_regions_count = r.ReadInt32();
                        for (int i = 0; i < cells_overlapped_by_regions_count; ++i)
                        {
                            int key = r.ReadInt32();
                            m_CellsOverlappedByRegions.Add(key, new overlapped_cell_data(m_AllCells, r));
                        }
                    }
                }

            Log("[Nav] Navmesh deserialized.");
        }
Exemple #7
0
 public virtual void OnGridCellAdded(GridCell grid_cell)
 {
 }
Exemple #8
0
        public bool Load(string filename, bool clear = true)
        {
            if (filename == null)
            {
                return(false);
            }

            //using (new Profiler("[Nav] Loaded nav data [{t}]"))
            {
                if (clear)
                {
                    Clear();
                }

                try
                {
                    StreamReader stream = new StreamReader(filename);

                    if (stream != null)
                    {
                        string   line;
                        GridCell g_cell                   = null;
                        Vec3     cell_shrink_size         = Vec3.Empty;
                        HashSet <region_data> avoid_areas = new HashSet <region_data>();

                        CultureInfo inv = (CultureInfo)CultureInfo.CurrentCulture.Clone();
                        inv.NumberFormat.CurrencyDecimalSeparator = ",";
                        inv.NumberFormat.NumberDecimalSeparator   = ",";

                        while ((line = stream.ReadLine()) != null)
                        {
                            string[] data = line.Split(' ');

                            if (data[0] == "g")
                            {
                                // add previous grid cell
                                Add(g_cell, false);

                                m_LastCellId = 0;

                                g_cell = new GridCell(float.Parse(data[1], inv), float.Parse(data[2], inv), float.Parse(data[3], inv), float.Parse(data[4], inv), float.Parse(data[5], inv), float.Parse(data[6], inv), (data.Length > 7 ? int.Parse(data[7]) : m_LastGridCellId++));
                            }
                            else if (data[0] == "n")
                            {
                                MovementFlag flags = MovementFlag.Walk | MovementFlag.Fly;

                                if (data.Length > 7)
                                {
                                    flags = (MovementFlag)int.Parse(data[7]);
                                }

                                Cell n_cell = new Cell(new Vec3(float.Parse(data[1], inv), float.Parse(data[2], inv), float.Parse(data[3], inv)) - cell_shrink_size, new Vec3(float.Parse(data[4], inv), float.Parse(data[5], inv), float.Parse(data[6], inv)) - cell_shrink_size, flags, m_LastCellId++);
                                g_cell.Add(n_cell);
                            }
                            else if (data[0] == "r")
                            {
                                avoid_areas.Add(new region_data(new AABB(float.Parse(data[1], inv), float.Parse(data[2], inv), float.Parse(data[3], inv), float.Parse(data[4], inv), float.Parse(data[5], inv), float.Parse(data[6], inv)), float.Parse(data[7], inv)));
                            }
                            else if (data[0] == "s")
                            {
                                Navigator.CurrentPos = new Vec3(float.Parse(data[1], inv), float.Parse(data[2], inv), float.Parse(data[3], inv));
                            }
                            else if (data[0] == "e")
                            {
                                Navigator.Destination = new Vec3(float.Parse(data[1], inv), float.Parse(data[2], inv), float.Parse(data[3], inv));
                            }
                        }

                        // add last grid cell
                        Add(g_cell, false);

                        Random   rng = new Random();
                        GridCell random_grid_cell = null;

                        random_grid_cell = m_GridCells[rng.Next(m_GridCells.Count)];

                        if (Explorator != null)
                        {
                            Explorator.OnNavDataChange();
                        }

                        Regions = avoid_areas;

                        Log("[Nav] Navmesh loaded.");

                        stream.Close();

                        return(true);
                    }
                }
                catch (Exception)
                {
                }

                Log("[Nav] Navmesh load failed!");

                return(false);
            }
        }
Exemple #9
0
        protected virtual void OnDeserialize(BinaryReader r)
        {
            using (new WriteLock(DataLock))
                using (new WriteLock(InputLock))
                {
                    //using (new Profiler("Navmesh deserialization took {t}"))
                    {
                        m_AllCells.Clear();
                        m_GridCells.Clear();
                        m_Regions.Clear();
                        m_CellsOverlappedByRegions.Clear();

                        Cell.CompareByGlobalId comp_by_global_id = new Cell.CompareByGlobalId();

                        int all_cells_count = r.ReadInt32();

                        // pre-allocate cells
                        for (int i = 0; i < all_cells_count; ++i)
                        {
                            Cell cell = new Cell(0, 0, 0, 0, 0, 0, MovementFlag.None);
                            cell.GlobalId = r.ReadInt32();
                            m_AllCells.Add(cell);
                        }

                        m_AllCells.Sort(comp_by_global_id);

                        foreach (Cell cell in m_AllCells)
                        {
                            cell.Deserialize(m_AllCells, r);
                        }

                        Cell.LastCellGlobalId = r.ReadInt32();

                        int grid_cells_count = r.ReadInt32();

                        // pre-allocate grid cells
                        for (int i = 0; i < grid_cells_count; ++i)
                        {
                            GridCell grid_cell = new GridCell(0, 0, 0, 0, 0, 0);
                            grid_cell.GlobalId = r.ReadInt32();
                            m_GridCells.Add(grid_cell);
                        }

                        m_GridCells.Sort(comp_by_global_id);

                        foreach (GridCell grid_cell in m_GridCells)
                        {
                            grid_cell.Deserialize(m_GridCells, m_AllCells, r);
                        }

                        GridCell.LastGridCellGlobalId = r.ReadInt32();

                        int regions_count = r.ReadInt32();
                        for (int i = 0; i < regions_count; ++i)
                        {
                            m_Regions.Add(new region_data(r));
                        }

                        int cells_overlapped_by_regions_count = r.ReadInt32();
                        for (int i = 0; i < cells_overlapped_by_regions_count; ++i)
                        {
                            int key = r.ReadInt32();
                            m_CellsOverlappedByRegions.Add(key, new overlapped_cell_data(m_AllCells, r));
                        }

                        Navigator.Deserialize(m_AllCells, r);

                        if (Explorator != null)
                        {
                            Explorator.Deserialize(m_AllCells, r);
                        }
                    }
                }

            Log("[Nav] Navmesh deserialized.");
        }