| | | 1 | | //======================================================================= |
| | | 2 | | // NavigationSurfaceComponentKeySet.cs |
| | | 3 | | //======================================================================= |
| | | 4 | | // MIT License, Copyright (c) 2024-present David Oravsky (mrdav30) |
| | | 5 | | // See LICENSE file in the project root for full license information. |
| | | 6 | | //======================================================================= |
| | | 7 | | |
| | | 8 | | namespace Trailblazer.Pathing; |
| | | 9 | | |
| | | 10 | | /// <summary>Stores a persistent canonical set of exact address-medium keys.</summary> |
| | | 11 | | internal sealed class NavigationSurfaceComponentKeySet |
| | | 12 | | { |
| | | 13 | | private readonly PersistentStringMap<PersistentVoxelIndexMap<byte>> _maps; |
| | | 14 | | private readonly long _innerBytes; |
| | | 15 | | private readonly int _innerPages; |
| | | 16 | | |
| | 2567 | 17 | | private NavigationSurfaceComponentKeySet( |
| | 2567 | 18 | | PersistentStringMap<PersistentVoxelIndexMap<byte>> maps, |
| | 2567 | 19 | | int count, |
| | 2567 | 20 | | long innerBytes, |
| | 2567 | 21 | | int innerPages) |
| | | 22 | | { |
| | 2567 | 23 | | _maps = maps; |
| | 2567 | 24 | | Count = count; |
| | 2567 | 25 | | _innerBytes = innerBytes; |
| | 2567 | 26 | | _innerPages = innerPages; |
| | 2567 | 27 | | } |
| | | 28 | | |
| | | 29 | | internal static NavigationSurfaceComponentKeySet Empty { get; } = new( |
| | | 30 | | PersistentStringMap<PersistentVoxelIndexMap<byte>>.Empty, |
| | | 31 | | 0, |
| | | 32 | | 0, |
| | | 33 | | 0); |
| | | 34 | | |
| | | 35 | | internal int Count { get; } |
| | | 36 | | |
| | 302950 | 37 | | internal long RetainedBytes => checked(40L + _maps.RetainedBytes + _innerBytes); |
| | | 38 | | |
| | 303567 | 39 | | internal int PersistentPageCount => checked( |
| | 303567 | 40 | | 1 + _maps.PersistentNodeCount + _innerPages); |
| | | 41 | | |
| | | 42 | | internal bool Contains(NavigationSurfaceComponentKey key) => |
| | 2031494 | 43 | | _maps.TryGetValue( |
| | 2031494 | 44 | | key.Representative.MapId, |
| | 2031494 | 45 | | out PersistentVoxelIndexMap<byte> values) |
| | 2031494 | 46 | | && values.TryGetValue(key.Representative.Index, out byte mask) |
| | 2031494 | 47 | | && (mask & NavigationMediumSlots<byte>.GetBit(key.Medium)) != 0; |
| | | 48 | | |
| | | 49 | | internal NavigationSurfaceComponentKeySet Add(NavigationSurfaceComponentKey key) |
| | | 50 | | { |
| | 2516 | 51 | | string mapId = key.Representative.MapId; |
| | 2516 | 52 | | bool hadMap = _maps.TryGetValue( |
| | 2516 | 53 | | mapId, |
| | 2516 | 54 | | out PersistentVoxelIndexMap<byte> values); |
| | 2516 | 55 | | values ??= PersistentVoxelIndexMap<byte>.Empty; |
| | 2516 | 56 | | byte bit = NavigationMediumSlots<byte>.GetBit(key.Medium); |
| | 2516 | 57 | | values.TryGetValue(key.Representative.Index, out byte mask); |
| | 2516 | 58 | | if ((mask & bit) != 0) |
| | 3 | 59 | | return this; |
| | 2513 | 60 | | long innerBytes = _innerBytes - (hadMap ? values.RetainedBytes : 0L); |
| | 2513 | 61 | | int innerPages = _innerPages - (hadMap ? values.PersistentNodeCount : 0); |
| | 2513 | 62 | | values = values.Set(key.Representative.Index, (byte)(mask | bit)); |
| | 2513 | 63 | | return new NavigationSurfaceComponentKeySet( |
| | 2513 | 64 | | _maps.Set(mapId, values), |
| | 2513 | 65 | | checked(Count + 1), |
| | 2513 | 66 | | checked(innerBytes + values.RetainedBytes), |
| | 2513 | 67 | | checked(innerPages + values.PersistentNodeCount)); |
| | | 68 | | } |
| | | 69 | | |
| | | 70 | | internal NavigationSurfaceComponentKeySet Remove(NavigationSurfaceComponentKey key) |
| | | 71 | | { |
| | 55 | 72 | | string mapId = key.Representative.MapId; |
| | 55 | 73 | | if (!_maps.TryGetValue(mapId, out PersistentVoxelIndexMap<byte> values) |
| | 55 | 74 | | || !values.TryGetValue(key.Representative.Index, out byte mask)) |
| | | 75 | | { |
| | 1 | 76 | | return this; |
| | | 77 | | } |
| | 54 | 78 | | byte bit = NavigationMediumSlots<byte>.GetBit(key.Medium); |
| | 54 | 79 | | if ((mask & bit) == 0) |
| | 1 | 80 | | return this; |
| | 53 | 81 | | long innerBytes = _innerBytes - values.RetainedBytes; |
| | 53 | 82 | | int innerPages = _innerPages - values.PersistentNodeCount; |
| | 53 | 83 | | byte nextMask = (byte)(mask & ~bit); |
| | 53 | 84 | | values = nextMask == 0 |
| | 53 | 85 | | ? values.Remove(key.Representative.Index, out _) |
| | 53 | 86 | | : values.Set(key.Representative.Index, nextMask); |
| | 53 | 87 | | PersistentStringMap<PersistentVoxelIndexMap<byte>> maps = values.Count == 0 |
| | 53 | 88 | | ? _maps.Remove(mapId, out _) |
| | 53 | 89 | | : _maps.Set(mapId, values); |
| | 53 | 90 | | return new NavigationSurfaceComponentKeySet( |
| | 53 | 91 | | maps, |
| | 53 | 92 | | Count - 1, |
| | 53 | 93 | | checked(innerBytes + (values.Count == 0 ? 0L : values.RetainedBytes)), |
| | 53 | 94 | | checked(innerPages + (values.Count == 0 ? 0 : values.PersistentNodeCount))); |
| | | 95 | | } |
| | | 96 | | |
| | 2797 | 97 | | internal Enumerator GetEnumerator() => new(this); |
| | | 98 | | |
| | | 99 | | internal struct Enumerator |
| | | 100 | | { |
| | | 101 | | private readonly NavigationSurfaceComponentKeySet _set; |
| | | 102 | | private int _map; |
| | | 103 | | private int _address; |
| | | 104 | | private TraversalMedium _medium; |
| | | 105 | | private TraversalMedium _currentMedium; |
| | | 106 | | |
| | | 107 | | internal Enumerator(NavigationSurfaceComponentKeySet set) |
| | | 108 | | { |
| | 2797 | 109 | | _set = set; |
| | 2797 | 110 | | _map = 0; |
| | 2797 | 111 | | _address = 0; |
| | 2797 | 112 | | _medium = TraversalMedium.Solid; |
| | 2797 | 113 | | _currentMedium = TraversalMedium.Unknown; |
| | 2797 | 114 | | } |
| | | 115 | | |
| | | 116 | | internal NavigationSurfaceComponentKey Current |
| | | 117 | | { |
| | | 118 | | get |
| | | 119 | | { |
| | 2349 | 120 | | PersistentVoxelIndexMap<byte> values = _set._maps.GetValueAt(_map); |
| | 2349 | 121 | | return new NavigationSurfaceComponentKey( |
| | 2349 | 122 | | new NavigationCellAddress( |
| | 2349 | 123 | | _set._maps.GetKeyAt(_map), |
| | 2349 | 124 | | values.GetKeyAt(_address)), |
| | 2349 | 125 | | _currentMedium); |
| | | 126 | | } |
| | | 127 | | } |
| | | 128 | | |
| | | 129 | | internal bool MoveNext() |
| | | 130 | | { |
| | 2396 | 131 | | while (_map < _set._maps.Count) |
| | | 132 | | { |
| | 2394 | 133 | | PersistentVoxelIndexMap<byte> values = _set._maps.GetValueAt(_map); |
| | 4263 | 134 | | while (_address < values.Count) |
| | | 135 | | { |
| | 4218 | 136 | | byte mask = values.GetValueAt(_address); |
| | 8181 | 137 | | while (_medium <= TraversalMedium.Liquid) |
| | | 138 | | { |
| | 6312 | 139 | | TraversalMedium medium = _medium++; |
| | 6312 | 140 | | if ((mask & NavigationMediumSlots<byte>.GetBit(medium)) == 0) |
| | | 141 | | continue; |
| | 2349 | 142 | | _currentMedium = medium; |
| | 2349 | 143 | | return true; |
| | | 144 | | } |
| | 1869 | 145 | | _address++; |
| | 1869 | 146 | | _medium = TraversalMedium.Solid; |
| | | 147 | | } |
| | 45 | 148 | | _map++; |
| | 45 | 149 | | _address = 0; |
| | | 150 | | } |
| | 2 | 151 | | return false; |
| | | 152 | | } |
| | | 153 | | } |
| | | 154 | | } |