| | | 1 | | //======================================================================= |
| | | 2 | | // NavigationEndpoint.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 | | using System; |
| | | 9 | | using FixedMathSharp; |
| | | 10 | | using SwiftCollections.Utility; |
| | | 11 | | |
| | | 12 | | namespace Trailblazer.Pathing; |
| | | 13 | | |
| | | 14 | | /// <summary> |
| | | 15 | | /// Describes one immutable world-space endpoint of a path query. |
| | | 16 | | /// </summary> |
| | | 17 | | public readonly struct NavigationEndpoint : IEquatable<NavigationEndpoint> |
| | | 18 | | { |
| | | 19 | | /// <summary> |
| | | 20 | | /// Gets the exact requested foot position in world space. |
| | | 21 | | /// </summary> |
| | | 22 | | public Vector3d Position { get; } |
| | | 23 | | |
| | | 24 | | /// <summary> |
| | | 25 | | /// Gets the optional stable map identifier used to filter endpoint candidates. |
| | | 26 | | /// </summary> |
| | | 27 | | public string? MapId { get; } |
| | | 28 | | |
| | | 29 | | /// <summary> |
| | | 30 | | /// Gets the endpoint resolution policy. |
| | | 31 | | /// </summary> |
| | | 32 | | public EndpointResolutionPolicy Resolution { get; } |
| | | 33 | | |
| | | 34 | | /// <summary> |
| | | 35 | | /// Gets the non-negative maximum resolution distance in world units. |
| | | 36 | | /// </summary> |
| | | 37 | | public Fixed64 MaxResolutionDistance { get; } |
| | | 38 | | |
| | | 39 | | /// <summary> |
| | | 40 | | /// Creates an immutable navigation endpoint. |
| | | 41 | | /// </summary> |
| | | 42 | | /// <exception cref="ArgumentException">Thrown when a supplied map identifier is empty or whitespace.</exception> |
| | | 43 | | /// <exception cref="ArgumentOutOfRangeException">Thrown when the policy is unknown or the distance is negative.</ex |
| | | 44 | | public NavigationEndpoint( |
| | | 45 | | Vector3d position, |
| | | 46 | | string? mapId = null, |
| | | 47 | | EndpointResolutionPolicy resolution = EndpointResolutionPolicy.Strict, |
| | | 48 | | Fixed64 maxResolutionDistance = default) |
| | | 49 | | { |
| | 2368 | 50 | | SwiftThrowHelper.ThrowIfArgument( |
| | 2368 | 51 | | mapId != null && string.IsNullOrWhiteSpace(mapId), |
| | 2368 | 52 | | nameof(mapId), |
| | 2368 | 53 | | "Map identifier cannot be empty or whitespace."); |
| | 2367 | 54 | | SwiftThrowHelper.ThrowIfArgumentOutOfRange( |
| | 2367 | 55 | | resolution is not EndpointResolutionPolicy.Strict and not EndpointResolutionPolicy.NearestNavigable, |
| | 2367 | 56 | | (int)resolution, |
| | 2367 | 57 | | nameof(resolution), |
| | 2367 | 58 | | "Endpoint resolution policy is unknown."); |
| | 2366 | 59 | | SwiftThrowHelper.ThrowIfArgumentOutOfRange( |
| | 2366 | 60 | | maxResolutionDistance < Fixed64.Zero, |
| | 2366 | 61 | | actualValue: null, |
| | 2366 | 62 | | nameof(maxResolutionDistance), |
| | 2366 | 63 | | "Maximum resolution distance cannot be negative."); |
| | | 64 | | |
| | 2365 | 65 | | Position = position; |
| | 2365 | 66 | | MapId = mapId; |
| | 2365 | 67 | | Resolution = resolution; |
| | 2365 | 68 | | MaxResolutionDistance = maxResolutionDistance; |
| | 2365 | 69 | | } |
| | | 70 | | |
| | | 71 | | /// <inheritdoc/> |
| | | 72 | | public bool Equals(NavigationEndpoint other) => |
| | 3785 | 73 | | Position == other.Position |
| | 3785 | 74 | | && string.Equals(MapId, other.MapId, StringComparison.Ordinal) |
| | 3785 | 75 | | && Resolution == other.Resolution |
| | 3785 | 76 | | && MaxResolutionDistance == other.MaxResolutionDistance; |
| | | 77 | | |
| | | 78 | | /// <inheritdoc/> |
| | 209 | 79 | | public override bool Equals(object? obj) => obj is NavigationEndpoint other && Equals(other); |
| | | 80 | | |
| | | 81 | | /// <inheritdoc/> |
| | | 82 | | public override int GetHashCode() |
| | | 83 | | { |
| | 4804 | 84 | | int mapIdHash = MapId == null |
| | 4804 | 85 | | ? 0 |
| | 4804 | 86 | | : SwiftHashTools.GetDeterministicStringEqualityComparer().GetHashCode(MapId); |
| | 4804 | 87 | | int hash = SwiftHashTools.CombineHashCodes(Position.X.GetHashCode(), Position.Y.GetHashCode()); |
| | 4804 | 88 | | hash = SwiftHashTools.CombineHashCodes(hash, Position.Z.GetHashCode()); |
| | 4804 | 89 | | hash = SwiftHashTools.CombineHashCodes(hash, mapIdHash); |
| | 4804 | 90 | | hash = SwiftHashTools.CombineHashCodes(hash, (int)Resolution); |
| | 4804 | 91 | | return SwiftHashTools.CombineHashCodes(hash, MaxResolutionDistance.GetHashCode()); |
| | | 92 | | } |
| | | 93 | | |
| | | 94 | | /// <summary> |
| | | 95 | | /// Returns whether two endpoints have exactly equal values. |
| | | 96 | | /// </summary> |
| | 3572 | 97 | | public static bool operator ==(NavigationEndpoint left, NavigationEndpoint right) => left.Equals(right); |
| | | 98 | | |
| | | 99 | | /// <summary> |
| | | 100 | | /// Returns whether two endpoints differ. |
| | | 101 | | /// </summary> |
| | 1 | 102 | | public static bool operator !=(NavigationEndpoint left, NavigationEndpoint right) => !left.Equals(right); |
| | | 103 | | |
| | | 104 | | } |