CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

OccupierSet.cs (9209B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // The Command & Conquer Map Editor and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // The Command & Conquer Map Editor and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 using MobiusEditor.Interface;
     16 using System;
     17 using System.Collections;
     18 using System.Collections.Generic;
     19 using System.Drawing;
     20 using System.Linq;
     21 
     22 namespace MobiusEditor.Model
     23 {
     24     public class OccupierAddedEventArgs<T> : EventArgs
     25     {
     26         public readonly int Cell;
     27 
     28         public readonly Point Location;
     29 
     30         public readonly T Occupier;
     31 
     32         public OccupierAddedEventArgs(CellMetrics metrics, int cell, T occupier)
     33         {
     34             Cell = cell;
     35             metrics.GetLocation(cell, out Location);
     36             Occupier = occupier;
     37         }
     38 
     39         public OccupierAddedEventArgs(CellMetrics metrics, Point location, T occupier)
     40         {
     41             Location = location;
     42             metrics.GetCell(location, out Cell);
     43             Occupier = occupier;
     44         }
     45     }
     46 
     47     public class OccupierRemovedEventArgs<T> : EventArgs
     48     {
     49         public readonly int Cell;
     50 
     51         public readonly Point Location;
     52 
     53         public readonly T Occupier;
     54 
     55         public OccupierRemovedEventArgs(CellMetrics metrics, int cell, T occupier)
     56         {
     57             Cell = cell;
     58             metrics.GetLocation(cell, out Location);
     59             Occupier = occupier;
     60         }
     61 
     62         public OccupierRemovedEventArgs(CellMetrics metrics, Point location, T occupier)
     63         {
     64             Location = location;
     65             metrics.GetCell(location, out Cell);
     66             Occupier = occupier;
     67         }
     68     }
     69 
     70     public class OccupierSet<T> : IEnumerable<(Point Location, T Occupier)>, IEnumerable where T : class, ICellOccupier
     71     {
     72         private readonly CellMetrics metrics;
     73         private readonly Dictionary<T, Point> occupiers = new Dictionary<T, Point>();
     74         private readonly T[,] occupierCells;
     75 
     76         public T this[Point location] => this[location.X, location.Y];
     77 
     78         public T this[int x, int y] => Contains(x, y) ? occupierCells[y, x] : null;
     79 
     80         public T this[int cell] => metrics.GetLocation(cell, out Point location) ? this[location] : null;
     81 
     82         public Point? this[T occupier] => occupiers.ContainsKey(occupier) ? occupiers[occupier] : default;
     83 
     84         public IEnumerable<T> Occupiers => occupiers.Keys;
     85 
     86         public event EventHandler<OccupierAddedEventArgs<T>> OccupierAdded;
     87         public event EventHandler<OccupierRemovedEventArgs<T>> OccupierRemoved;
     88         public event EventHandler<EventArgs> Cleared;
     89 
     90         public OccupierSet(CellMetrics metrics)
     91         {
     92             this.metrics = metrics;
     93             occupierCells = new T[metrics.Height, metrics.Width];
     94         }
     95 
     96         public bool CanAdd(Point location, T occupier, bool[,] occupyMask)
     97         {
     98             if ((occupier == null) || Contains(occupier))
     99             {
    100                 return false;
    101             }
    102 
    103             var occupyPoints = GetOccupyPoints(location, occupyMask).ToArray();
    104             return !occupyPoints.Any(p => !Contains(p) || (this[p] != null));
    105         }
    106 
    107         public bool CanAdd(int x, int y, T occupier, bool[,] occupyMask) => CanAdd(new Point(x, y), occupier, occupyMask);
    108 
    109         public bool CanAdd(int cell, T occupier, bool[,] occupyMask) => metrics.GetLocation(cell, out Point location) ? CanAdd(location, occupier, occupyMask) : false;
    110 
    111         public bool CanAdd(Point location, T occupier) => (occupier != null) ? CanAdd(location, occupier, occupier.OccupyMask) : false;
    112 
    113         public bool CanAdd(int x, int y, T occupier) => (occupier != null) ? CanAdd(x, y, occupier, occupier.OccupyMask) : false;
    114 
    115         public bool CanAdd(int cell, T occupier) => (occupier != null) ? CanAdd(cell, occupier, occupier.OccupyMask) : false;
    116 
    117         public bool Add(Point location, T occupier, bool[,] occupyMask)
    118         {
    119             if (!DoAdd(location, occupier, occupyMask))
    120             {
    121                 return false;
    122             }
    123 
    124             OnOccupierAdded(new OccupierAddedEventArgs<T>(metrics, location, occupier));
    125             return true;
    126         }
    127 
    128         public bool Add(int x, int y, T occupier, bool[,] occupyMask) => Add(new Point(x, y), occupier, occupyMask);
    129 
    130         public bool Add(int cell, T occupier, bool[,] occupyMask) => metrics.GetLocation(cell, out Point location) ? Add(location, occupier, occupyMask) : false;
    131 
    132         public bool Add(Point location, T occupier) => (occupier != null) ? Add(location, occupier, occupier.OccupyMask) : false;
    133 
    134         public bool Add(int x, int y, T occupier) => (occupier != null) ? Add(x, y, occupier, occupier.OccupyMask) : false;
    135 
    136         public bool Add(int cell, T occupier) => (occupier != null) ? Add(cell, occupier, occupier.OccupyMask) : false;
    137 
    138         public void Clear()
    139         {
    140             occupiers.Clear();
    141             Array.Clear(occupierCells, 0, occupierCells.Length);
    142             OnCleared();
    143         }
    144 
    145         public bool Contains(int x, int y) => ((x >= 0) && (x < occupierCells.GetLength(1)) && (y >= 0) && (y < occupierCells.GetLength(0)));
    146 
    147         public bool Contains(Point location) => Contains(location.X, location.Y);
    148 
    149         public bool Contains(int cell) => metrics.GetLocation(cell, out Point location) ? Contains(location) : false;
    150 
    151         public bool Contains(T occupier) => occupiers.ContainsKey(occupier);
    152 
    153         public IEnumerator<(Point Location, T Occupier)> GetEnumerator() => occupiers.Select(kv => (kv.Value, kv.Key)).GetEnumerator();
    154 
    155         public bool Remove(T occupier)
    156         {
    157             var oldLocation = this[occupier];
    158             if (!DoRemove(occupier))
    159             {
    160                 return false;
    161             }
    162 
    163             OnOccupierRemoved(new OccupierRemovedEventArgs<T>(metrics, oldLocation.Value, occupier));
    164             return true;
    165         }
    166 
    167         public bool Remove(Point location) => Remove(this[location]);
    168 
    169         public bool Remove(int x, int y) => Remove(new Point(x, y));
    170 
    171         public bool Remove(int cell) => metrics.GetLocation(cell, out Point location) ? Remove(location) : false;
    172 
    173         public IEnumerable<(Point Location, U Occupier)> OfType<U>() where U : T => this.Where(i => i.Occupier is U).Select(i => (i.Location, (U)i.Occupier));
    174 
    175         protected virtual void OnOccupierAdded(OccupierAddedEventArgs<T> e)
    176         {
    177             OccupierAdded?.Invoke(this, e);
    178         }
    179 
    180         protected virtual void OnOccupierRemoved(OccupierRemovedEventArgs<T> e)
    181         {
    182             OccupierRemoved?.Invoke(this, e);
    183         }
    184 
    185         protected virtual void OnCleared()
    186         {
    187             Cleared?.Invoke(this, new EventArgs());
    188         }
    189 
    190         IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    191 
    192         private bool DoAdd(Point location, T occupier, bool[,] occupyMask)
    193         {
    194             if ((occupier == null) || Contains(occupier))
    195             {
    196                 return false;
    197             }
    198 
    199             var occupyPoints = GetOccupyPoints(location, occupyMask).ToArray();
    200             if (occupyPoints.Any(p => !Contains(p) || (this[p] != null)))
    201             {
    202                 return false;
    203             }
    204 
    205             occupiers[occupier] = location;
    206             foreach (var p in occupyPoints)
    207             {
    208                 occupierCells[p.Y, p.X] = occupier;
    209             }
    210             return true;
    211         }
    212 
    213         private bool DoRemove(T occupier)
    214         {
    215             if ((occupier == null) || !occupiers.TryGetValue(occupier, out Point location))
    216             {
    217                 return false;
    218             }
    219 
    220             occupiers.Remove(occupier);
    221             for (var y = location.Y; y < metrics.Height; ++y)
    222             {
    223                 for (var x = location.X; x < metrics.Width; ++x)
    224                 {
    225                     if (occupierCells[y, x] == occupier)
    226                     {
    227                         occupierCells[y, x] = null;
    228                     }
    229                 }
    230             }
    231             return true;
    232         }
    233 
    234         private static IEnumerable<Point> GetOccupyPoints(Point location, bool[,] occupyMask)
    235         {
    236             for (var y = 0; y < occupyMask.GetLength(0); ++y)
    237             {
    238                 for (var x = 0; x < occupyMask.GetLength(1); ++x)
    239                 {
    240                     if (occupyMask[y, x])
    241                     {
    242                         yield return location + new Size(x, y);
    243                     }
    244                 }
    245             }
    246         }
    247 
    248         private static IEnumerable<Point> GetOccupyPoints(Point location, T occupier) => GetOccupyPoints(location, occupier.OccupyMask);
    249     }
    250 }