diff --git a/ConfigService/Configurations/NavigationMonitorConfiguration.cs b/ConfigService/Configurations/NavigationMonitorConfiguration.cs index eed2694f0b..8003417518 100644 --- a/ConfigService/Configurations/NavigationMonitorConfiguration.cs +++ b/ConfigService/Configurations/NavigationMonitorConfiguration.cs @@ -36,11 +36,11 @@ public class NavigationMonitorConfiguration : Config public ObservableCollection bookmarks { get; set; } = new ObservableCollection(); // Current in-game route - public NavWaypointCollection navRouteList { get; set; } = new NavWaypointCollection(); + public NavWaypointCollection navRouteList { get; set; } = new NavWaypointCollection(null, true); // Plotted routes - public NavWaypointCollection plottedRouteList { get; set; } = new NavWaypointCollection(); + public NavWaypointCollection carrierPlottedRoute { get; set; } = new NavWaypointCollection(null, true); - public NavWaypointCollection carrierPlottedRoute { get; set; } = new NavWaypointCollection(); + public NavWaypointCollection plottedRouteList { get; set; } = new NavWaypointCollection(); } } diff --git a/DataDefinitions/NavWaypointCollection.cs b/DataDefinitions/NavWaypointCollection.cs index 7b81472510..1f01afa450 100644 --- a/DataDefinitions/NavWaypointCollection.cs +++ b/DataDefinitions/NavWaypointCollection.cs @@ -61,28 +61,27 @@ public int? RouteFuelTotal private decimal? currentZ; [JsonConstructor] - public NavWaypointCollection() + public NavWaypointCollection (IEnumerable items = null, bool fillVisitedGaps = false) { - Waypoints.CollectionChanged += NavWaypointList_CollectionChanged; - } + if ( items != null ) + { + foreach ( var item in items ) + { + Waypoints.Add( item ); + } + CalculateFuelUsed(); + CalculateRouteDistances(); + } - public NavWaypointCollection(bool fillVisitedGaps = false) - { FillVisitedGaps = fillVisitedGaps; Waypoints.CollectionChanged += NavWaypointList_CollectionChanged; } - public NavWaypointCollection(IEnumerable items, bool fillVisitedGaps = false) + public NavWaypointCollection ( decimal x, decimal y, decimal z ) { - foreach (var item in items) - { - Waypoints.Add(item); - } - - CalculateFuelUsed(); - CalculateRouteDistances(); - - FillVisitedGaps = fillVisitedGaps; + currentX = x; + currentY = y; + currentZ = z; Waypoints.CollectionChanged += NavWaypointList_CollectionChanged; } diff --git a/EDDI/ChangeLog.md b/EDDI/ChangeLog.md index f9dbc2dcc6..842dc99871 100644 --- a/EDDI/ChangeLog.md +++ b/EDDI/ChangeLog.md @@ -7,6 +7,7 @@ Full details of the variables available for each noted event, and VoiceAttack in * EDDI will no longer report your environment as "Supercruise" right after a Thargoid hyperdiction. (#2597) * Navigation Monitor * Improved route guidance updates. + * Fixed ship routes reporting wrong jump distances. (#2591) * Speech Responder * Functions * `Play()` now supports relative file system paths. (#2581) diff --git a/NavigationMonitor/NavigationMonitor.cs b/NavigationMonitor/NavigationMonitor.cs index 64131ad13c..18fa78523a 100644 --- a/NavigationMonitor/NavigationMonitor.cs +++ b/NavigationMonitor/NavigationMonitor.cs @@ -143,66 +143,62 @@ public void HandleProfile(JObject profile) public void PreHandle(Event @event) { - if (@event.timestamp >= updateDat) + // Handle the events that we care about + if (@event is CarrierJumpRequestEvent carrierJumpRequestEvent) { - // Handle the events that we care about - - if (@event is CarrierJumpRequestEvent carrierJumpRequestEvent) - { - handleCarrierJumpRequestEvent(carrierJumpRequestEvent); - } - else if (@event is CarrierJumpCancelledEvent carrierJumpCancelledEvent) - { - handleCarrierJumpCancelledEvent(carrierJumpCancelledEvent); - } - else if (@event is CarrierJumpedEvent carrierJumpedEvent) - { - handleCarrierJumpedEvent(carrierJumpedEvent); - } - else if (@event is CarrierJumpEngagedEvent carrierJumpEngagedEvent) - { - handleCarrierJumpEngagedEvent(carrierJumpEngagedEvent); - } - else if (@event is CarrierPurchasedEvent carrierPurchasedEvent) - { - handleCarrierPurchasedEvent(carrierPurchasedEvent); - } - else if (@event is CarrierStatsEvent carrierStatsEvent) - { - handleCarrierStatsEvent(carrierStatsEvent); - } - else if (@event is CommodityPurchasedEvent commodityPurchasedEvent) - { - handleCommodityPurchasedEvent(commodityPurchasedEvent); - } - else if (@event is CommoditySoldEvent commoditySoldEvent) - { - handleCommoditySoldEvent(commoditySoldEvent); - } - else if (@event is DockedEvent dockedEvent) - { - handleDockedEvent(dockedEvent); - } - else if (@event is JumpedEvent jumpedEvent) - { - handleJumpedEvent(jumpedEvent); - } - else if (@event is LocationEvent locationEvent) - { - handleLocationEvent(locationEvent); - } - else if (@event is NavRouteEvent navRouteEvent) - { - handleNavRouteEvent(navRouteEvent); - } - else if (@event is RouteDetailsEvent routeDetailsEvent) - { - handleRouteDetailsEvent(routeDetailsEvent); - } - else if (@event is FSDTargetEvent fsdTargetEvent) - { - handleFSDTargetEvent(fsdTargetEvent); - } + handleCarrierJumpRequestEvent(carrierJumpRequestEvent); + } + else if (@event is CarrierJumpCancelledEvent carrierJumpCancelledEvent) + { + handleCarrierJumpCancelledEvent(carrierJumpCancelledEvent); + } + else if (@event is CarrierJumpedEvent carrierJumpedEvent) + { + handleCarrierJumpedEvent(carrierJumpedEvent); + } + else if (@event is CarrierJumpEngagedEvent carrierJumpEngagedEvent) + { + handleCarrierJumpEngagedEvent(carrierJumpEngagedEvent); + } + else if (@event is CarrierPurchasedEvent carrierPurchasedEvent) + { + handleCarrierPurchasedEvent(carrierPurchasedEvent); + } + else if (@event is CarrierStatsEvent carrierStatsEvent) + { + handleCarrierStatsEvent(carrierStatsEvent); + } + else if (@event is CommodityPurchasedEvent commodityPurchasedEvent) + { + handleCommodityPurchasedEvent(commodityPurchasedEvent); + } + else if (@event is CommoditySoldEvent commoditySoldEvent) + { + handleCommoditySoldEvent(commoditySoldEvent); + } + else if (@event is DockedEvent dockedEvent) + { + handleDockedEvent(dockedEvent); + } + else if (@event is JumpedEvent jumpedEvent) + { + handleJumpedEvent(jumpedEvent); + } + else if (@event is LocationEvent locationEvent) + { + handleLocationEvent(locationEvent); + } + else if (@event is NavRouteEvent navRouteEvent) + { + handleNavRouteEvent(navRouteEvent); + } + else if (@event is RouteDetailsEvent routeDetailsEvent) + { + handleRouteDetailsEvent(routeDetailsEvent); + } + else if (@event is FSDTargetEvent fsdTargetEvent) + { + handleFSDTargetEvent(fsdTargetEvent); } } @@ -635,11 +631,11 @@ private void ReadNavConfig() GetBookmarkExtras(Bookmarks); // Restore our in-game routing - NavRoute = navConfig.navRouteList ?? new NavWaypointCollection(true); + NavRoute = navConfig.navRouteList ?? new NavWaypointCollection(null, true); // Restore our plotted routes + CarrierPlottedRoute = navConfig.carrierPlottedRoute ?? new NavWaypointCollection(null, true); PlottedRoute = navConfig.plottedRouteList ?? new NavWaypointCollection(); - CarrierPlottedRoute = navConfig.carrierPlottedRoute ?? new NavWaypointCollection(true); // Misc updateDat = navConfig.updatedat; diff --git a/NavigationService/IQueryResolver.cs b/NavigationService/IQueryResolver.cs index cd17f52af5..a499d48558 100644 --- a/NavigationService/IQueryResolver.cs +++ b/NavigationService/IQueryResolver.cs @@ -1,10 +1,12 @@ -using EddiEvents; +using EddiDataDefinitions; +using EddiEvents; +using JetBrains.Annotations; namespace EddiNavigationService { public interface IQueryResolver { QueryType Type { get; } - RouteDetailsEvent Resolve ( Query query ); + RouteDetailsEvent Resolve ( [NotNull] Query query, [NotNull] StarSystem startSystem ); } } diff --git a/NavigationService/NavigationService.cs b/NavigationService/NavigationService.cs index 9c6246ed80..5dc9d790a2 100644 --- a/NavigationService/NavigationService.cs +++ b/NavigationService/NavigationService.cs @@ -174,10 +174,38 @@ public RouteDetailsEvent NavQuery(QueryType queryType, string stringArg0 = null, // Resolve the current search query if ( queryResolvers.ContainsKey( queryType ) ) { + if ( EDDI.Instance.CurrentStarSystem == null ) + { + Logging.Debug( "Could not resolve navigation query: current star system is unknown." ); + return null; + } + foreach ( var resolver in queryResolvers .Where( resolver => resolver.Key == queryType ) ) { - result = resolver.Value.Resolve( query ); + if ( queryType == QueryType.carrier ) + { + var fleetCarrier = EDDI.Instance.FleetCarrier; + if ( fleetCarrier is null ) + { + Logging.Warn( "Invalid query: no fleet carrier found." ); + return null; + } + else + { + var carrierLocation = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem( fleetCarrier.currentStarSystem ); + if ( carrierLocation is null ) + { + Logging.Warn("Invalid query: unable to find fleet carrier location."); + return null; + } + result = resolver.Value.Resolve( query, carrierLocation ); + } + } + else + { + result = resolver.Value.Resolve( query, EDDI.Instance.CurrentStarSystem ); + } break; } } diff --git a/NavigationService/QueryResolvers/GalaxyQueryResolvers.cs b/NavigationService/QueryResolvers/GalaxyQueryResolvers.cs index 2dd308aa1e..14abbb2171 100644 --- a/NavigationService/QueryResolvers/GalaxyQueryResolvers.cs +++ b/NavigationService/QueryResolvers/GalaxyQueryResolvers.cs @@ -15,11 +15,11 @@ namespace EddiNavigationService.QueryResolvers internal class NearestScoopSystemResolver : IQueryResolver { public QueryType Type => QueryType.scoop; - public RouteDetailsEvent Resolve ( Query query ) => GetNearestScoopSystem(query.NumericArg); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => GetNearestScoopSystem(startSystem, query.NumericArg); /// Route to the nearest star system that is eligible for fuel scoop refueling /// The query result - private RouteDetailsEvent GetNearestScoopSystem ( decimal? searchRadius = null ) + private RouteDetailsEvent GetNearestScoopSystem ( [NotNull] StarSystem startSystem, decimal? searchRadius = null ) { if ( searchRadius is null ) { @@ -29,52 +29,50 @@ private RouteDetailsEvent GetNearestScoopSystem ( decimal? searchRadius = null ) // We'll search in progressive spherical shells out to a maximum radius of 100 ly // (the maximum from EDSM for a spherical system search) string searchSystem = null; - int searchCount = 0; - int searchIncrement = (int)Math.Ceiling(Math.Min((decimal)searchRadius, 100) / 4); - var navRouteList = new NavWaypointCollection(); + var searchCount = 0; + var searchIncrement = (int)Math.Ceiling(Math.Min((decimal)searchRadius, 100) / 4); + var navRouteList = new NavWaypointCollection(Convert.ToDecimal(startSystem.x), Convert.ToDecimal(startSystem.y), Convert.ToDecimal(startSystem.z)); - var currentSystem = EDDI.Instance?.CurrentStarSystem; - if ( currentSystem != null ) + if ( startSystem.scoopable ) { - if ( currentSystem.scoopable ) - { - searchSystem = currentSystem.systemname; - navRouteList.Waypoints.Add ( new NavWaypoint ( currentSystem ) { visited = true } ); - searchCount = 1; - } - else + searchSystem = startSystem.systemname; + navRouteList.Waypoints.Add ( new NavWaypoint ( startSystem ) { visited = true } ); + searchCount = 1; + } + else + { + for ( var i = 0; i < 4; i++ ) { - for ( int i = 0; i < 4; i++ ) + var startRadius = i * searchIncrement; + var endRadius = (i + 1) * searchIncrement; + var sphereSystems = + NavigationService.Instance.EdsmService.GetStarMapSystemsSphere( startSystem.systemname, startRadius, endRadius ) ?? + new List>(); + sphereSystems = sphereSystems.Where ( kvp => ( kvp[ "system" ] as StarSystem )?.scoopable ?? false ).ToList (); + searchCount = sphereSystems.Count; + if ( searchCount > 0 ) { - int startRadius = i * searchIncrement; - var endRadius = (i + 1) * searchIncrement; - var sphereSystems = NavigationService.Instance.EdsmService.GetStarMapSystemsSphere(currentSystem.systemname, startRadius, endRadius) ?? new List>(); - sphereSystems = sphereSystems.Where ( kvp => ( kvp[ "system" ] as StarSystem )?.scoopable ?? false ).ToList (); - searchCount = sphereSystems.Count; - if ( searchCount > 0 ) + var nearestList = new SortedList(); + foreach ( var system in sphereSystems ) { - var nearestList = new SortedList(); - foreach ( Dictionary system in sphereSystems ) + decimal distance = (decimal)system["distance"]; + if ( !nearestList.ContainsKey ( distance ) ) { - decimal distance = (decimal)system["distance"]; - if ( !nearestList.ContainsKey ( distance ) ) - { - nearestList.Add ( distance, system[ "system" ] as StarSystem ); - } + nearestList.Add ( distance, system[ "system" ] as StarSystem ); } + } - // Nearest 'scoopable' system - searchSystem = nearestList.Values.FirstOrDefault ()?.systemname; - - // Update the navRouteList - navRouteList.Waypoints.Add ( new NavWaypoint ( currentSystem ) { visited = true } ); - if ( currentSystem.systemname != nearestList.Values.FirstOrDefault ()?.systemname ) - { - navRouteList.Waypoints.Add ( new NavWaypoint ( nearestList.Values.FirstOrDefault () ) { visited = nearestList.Values.FirstOrDefault ()?.systemname == currentSystem.systemname } ); - } + // Nearest 'scoopable' system + searchSystem = nearestList.Values.FirstOrDefault ()?.systemname; - break; + // Update the navRouteList + navRouteList.Waypoints.Add ( new NavWaypoint ( startSystem ) { visited = true } ); + if ( startSystem.systemname != nearestList.Values.FirstOrDefault ()?.systemname ) + { + navRouteList.Waypoints.Add ( new NavWaypoint ( nearestList.Values.FirstOrDefault () ) { visited = nearestList.Values.FirstOrDefault ()?.systemname == startSystem.systemname } ); } + + break; } } } @@ -86,39 +84,31 @@ private RouteDetailsEvent GetNearestScoopSystem ( decimal? searchRadius = null ) internal class NeutronRouteResolver : IQueryResolver { public QueryType Type => QueryType.neutron; - public RouteDetailsEvent Resolve ( Query query ) => GetNeutronRoute(query.StringArg0); + + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => GetNeutronRoute( query.StringArg0, startSystem ); /// Obtains a neutron star route between the current star system and a named star system /// The query result - private RouteDetailsEvent GetNeutronRoute ( string targetSystemName, bool isSupercharged = false, bool useSupercharge = true, bool useInjections = false, bool excludeSecondary = false, bool fromUIquery = false ) + private RouteDetailsEvent GetNeutronRoute ( string targetSystemName, StarSystem startSystem, bool isSupercharged = false, bool useSupercharge = true, bool useInjections = false, bool excludeSecondary = false, bool fromUIquery = false ) { - var plottedRouteList = new NavWaypointCollection(); - var currentSystemName = EDDI.Instance.CurrentStarSystem?.systemname; - if ( EDDI.Instance.CurrentStarSystem == null ) - { - Logging.Debug ( "Neutron route plotting is not available, current star system is unknown." ); - } - else if ( string.IsNullOrEmpty ( targetSystemName ) ) + if ( string.IsNullOrEmpty( targetSystemName ) ) { - Logging.Debug ( "Neutron route plotting is not available, target star system is unknown." ); - } - else if ( targetSystemName == currentSystemName ) - { - Logging.Debug ( "Neutron route plotting is not available, the target star system name matches the current star system." ); + Logging.Warn( "Neutron route plotting is not available, target star system is unknown." ); + return null; } - else + else if ( targetSystemName == startSystem.systemname ) { - var cargoCarriedTons = ConfigService.Instance.cargoMonitorConfiguration.cargocarried; - var shipId = ConfigService.Instance.shipMonitorConfiguration.currentshipid; - var ship = ConfigService.Instance.shipMonitorConfiguration.shipyard.FirstOrDefault(s => - s.LocalId == shipId); - var spanshService = new SpanshService(); - plottedRouteList = spanshService.GetGalaxyRoute ( currentSystemName, targetSystemName, ship, cargoCarriedTons, - isSupercharged, useSupercharge, useInjections, excludeSecondary, fromUIquery ); + Logging.Warn( "Neutron route plotting is not available, the target star system name matches the current star system." ); + return null; } - if ( plottedRouteList == null || plottedRouteList.Waypoints.Count <= 1 ) - { return null; } + var cargoCarriedTons = ConfigService.Instance.cargoMonitorConfiguration.cargocarried; + var shipId = ConfigService.Instance.shipMonitorConfiguration.currentshipid; + var ship = ConfigService.Instance.shipMonitorConfiguration.shipyard.FirstOrDefault(s => s.LocalId == shipId); + var plottedRouteList = new SpanshService().GetGalaxyRoute ( startSystem.systemname, targetSystemName, ship, cargoCarriedTons, + isSupercharged, useSupercharge, useInjections, excludeSecondary, fromUIquery ); + if ( plottedRouteList == null || plottedRouteList.Waypoints.Count <= 1 ) { return null; } + plottedRouteList.UpdateLocationData( startSystem.systemAddress, startSystem.x, startSystem.y, startSystem.z ); // Sanity check - if we're already navigating to the plotted route destination then the number of jumps // must be equal or less then the already plotted route and the total route distance must be less also. @@ -142,31 +132,18 @@ private RouteDetailsEvent GetNeutronRoute ( string targetSystemName, bool isSupe internal class CarrierRouteResolver : IQueryResolver { public QueryType Type => QueryType.carrier; - public RouteDetailsEvent Resolve ( Query query ) => GetCarrierRoute( query.StringArg0, query.StringArg1, (long)Math.Round ( query.NumericArg ?? 0, 0 ) ); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => GetCarrierRoute( query.StringArg0, startSystem, (long)Math.Round ( query.NumericArg ?? 0, 0 ) ); /// Obtains a carrier route between the current carrier star system and a named star system /// The query result - private RouteDetailsEvent GetCarrierRoute ( string targetSystemName, string startingSystemName, long? usedCarrierCapacity = 0, string[] refuelDestinations = null, bool fromUIquery = false ) + private RouteDetailsEvent GetCarrierRoute ( [NotNull] string targetSystemName, [NotNull] StarSystem startSystem, long? usedCarrierCapacity = 0, string[] refuelDestinations = null, bool fromUIquery = false ) { - if ( string.IsNullOrEmpty ( startingSystemName ) ) - { - Logging.Warn ( "Invalid query: starting star system is not identified." ); - return null; - } - else if ( string.IsNullOrEmpty ( targetSystemName ) ) - { - Logging.Warn ( "Invalid query: target star system is not identified." ); - return null; - } - - var spanshService = new SpanshService(); usedCarrierCapacity = usedCarrierCapacity ?? EDDI.Instance.FleetCarrier?.usedCapacity; - if ( usedCarrierCapacity is null ) - { return null; } - var plottedRouteList = spanshService.GetCarrierRoute(startingSystemName, new[] { targetSystemName }, Convert.ToInt64(usedCarrierCapacity), false, refuelDestinations, fromUIquery); + if ( usedCarrierCapacity is null ) { return null; } - if ( plottedRouteList == null || plottedRouteList.Waypoints.Count <= 1 ) - { return null; } + var plottedRouteList = new SpanshService().GetCarrierRoute(startSystem.systemname, new[] { targetSystemName }, Convert.ToInt64(usedCarrierCapacity), false, refuelDestinations, fromUIquery); + if ( plottedRouteList == null || plottedRouteList.Waypoints.Count <= 1 ) { return null; } + plottedRouteList.UpdateLocationData( startSystem.systemAddress, startSystem.x, startSystem.y, startSystem.z ); // Sanity check - if we're already navigating to the plotted route destination then the number of jumps // must be equal or less then the already plotted route and the total route distance must be less also. @@ -180,7 +157,7 @@ private RouteDetailsEvent GetCarrierRoute ( string targetSystemName, string star plottedRouteList.Waypoints.First ().visited = true; var searchSystem = plottedRouteList.Waypoints[1].systemName; - + return new RouteDetailsEvent ( DateTime.UtcNow, QueryType.carrier.ToString (), searchSystem, null, plottedRouteList, plottedRouteList.Waypoints.Count, null ); } } diff --git a/NavigationService/QueryResolvers/MissionQueryResolvers.cs b/NavigationService/QueryResolvers/MissionQueryResolvers.cs index 4016393b3e..baab6dc7b4 100644 --- a/NavigationService/QueryResolvers/MissionQueryResolvers.cs +++ b/NavigationService/QueryResolvers/MissionQueryResolvers.cs @@ -1,5 +1,4 @@ using EddiConfigService; -using EddiCore; using EddiDataDefinitions; using EddiDataProviderService; using EddiEvents; @@ -15,66 +14,50 @@ namespace EddiNavigationService.QueryResolvers internal class CargoSourceMissionResolver : IQueryResolver { public QueryType Type => QueryType.source; - public RouteDetailsEvent Resolve ( Query query ) => GetMissionCargoSourceRoute ( query.StringArg0 ); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => GetMissionCargoSourceRoute ( startSystem, query.StringArg0 ); /// Route to the nearest star system that can be used to source active mission cargo - /// (Optional) If set, calculate relative to the named starting system rather than the current system + /// The current star system + /// (Optional) If set, calculate relative to the named starting system rather than the current system /// The query result - private RouteDetailsEvent GetMissionCargoSourceRoute ( string system = null ) + private RouteDetailsEvent GetMissionCargoSourceRoute ( [NotNull] StarSystem currentSystem, string fromSystemName = null ) { - var cargoConfig = ConfigService.Instance.cargoMonitorConfiguration; - var inventory = cargoConfig.cargo.ToList(); - var missionsCount = inventory.Sum(c => c.haulageData.Count); - StarSystem searchSystem = null; - int systemsCount = 0; - var missionids = new List(); // List of mission IDs for the next system - var sourceList = new SortedList(); - var navRouteList = new NavWaypointCollection(); - - if ( missionsCount > 0 ) - { - var curr = EDDI.Instance?.CurrentStarSystem; - var currentSystem = curr?.systemname; - var fromHere = system == currentSystem; + var cargo = ConfigService.Instance.cargoMonitorConfiguration.cargo.ToList(); + if ( cargo.Sum( c => c.haulageData.Count ) == 0 ) { return null; } - if ( curr != null ) - { - foreach ( Cargo cargo in inventory.Where ( c => c.haulageData.Any () ).ToList () ) - { - foreach ( Haulage haulage in cargo.haulageData - .Where ( h => - h.status == "Active" && - h.sourcesystem != null - ).ToList () ) - { - if ( fromHere && ( haulage.originsystem != currentSystem ) ) - { - break; - } + var haulageMissionIds = new HashSet(); // List of mission IDs for the next system + var sortedSourceSystems = new SortedList(); + var navRouteList = new NavWaypointCollection(Convert.ToDecimal(currentSystem.x), Convert.ToDecimal(currentSystem.y), Convert.ToDecimal(currentSystem.z)); - var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(haulage.sourcesystem, true, false, true, false, false); - long distance = (long)(Functions.StellarDistanceLy(curr.x, curr.y, curr.z, dest.x, dest.y, dest.z) ?? (0 * 100)); - if ( !sourceList.TryGetValue ( distance, out var _ ) ) - { - sourceList.Add ( distance, dest ); - } + foreach ( var haulage in cargo + .Where( c => c.haulageData.Any() ) + .SelectMany(c => c.haulageData ) + .Where( h => h.status == "Active" && h.sourcesystem != null ) ) + { + if ( fromSystemName == currentSystem.systemname && haulage.originsystem != currentSystem.systemname ) + { + // We are already at the named system and this is not the system where this haulage originates + break; + } - missionids.Add ( haulage.missionid ); - } - } + var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(haulage.sourcesystem, true, false, true, false, false); + var distance = (long)(Functions.StellarDistanceLy(currentSystem.x, currentSystem.y, currentSystem.z, dest.x, dest.y, dest.z) ?? (0 * 100)); + if ( !sortedSourceSystems.TryGetValue( distance, out _ ) ) + { + sortedSourceSystems.Add( distance, dest ); + } + haulageMissionIds.Add( haulage.missionid ); + } - searchSystem = sourceList.Values.FirstOrDefault (); - systemsCount = sourceList.Count; + var searchSystem = sortedSourceSystems.Values.FirstOrDefault (); - // Update the navRouteList - navRouteList.Waypoints.Add ( new NavWaypoint ( curr ) { visited = true } ); - if ( ( searchSystem != null ) && ( curr.systemname != searchSystem.systemname ) ) - { - navRouteList.Waypoints.Add ( new NavWaypoint ( searchSystem ) { visited = searchSystem.systemname == curr.systemname } ); - } - } + // Update the navRouteList + navRouteList.Waypoints.Add ( new NavWaypoint ( currentSystem ) { visited = true } ); + if ( ( searchSystem != null ) && ( currentSystem.systemname != searchSystem.systemname ) ) + { + navRouteList.Waypoints.Add ( new NavWaypoint ( searchSystem ) { visited = searchSystem.systemname == currentSystem.systemname } ); } - return new RouteDetailsEvent ( DateTime.UtcNow, QueryType.source.ToString (), searchSystem?.systemname, null, navRouteList, systemsCount, missionids ); + return new RouteDetailsEvent( DateTime.UtcNow, QueryType.source.ToString(), searchSystem?.systemname, null, navRouteList, sortedSourceSystems.Count, haulageMissionIds.ToList() ); } } @@ -82,49 +65,41 @@ private RouteDetailsEvent GetMissionCargoSourceRoute ( string system = null ) internal class ExpiringMissionResolver : IQueryResolver { public QueryType Type => QueryType.expiring; - public RouteDetailsEvent Resolve ( Query query ) => GetExpiringMissionRoute (); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => GetExpiringMissionRoute ( startSystem ); /// Route to the star system where missions shall expire first /// The query result - private RouteDetailsEvent GetExpiringMissionRoute () + private RouteDetailsEvent GetExpiringMissionRoute ( [NotNull] StarSystem startSystem ) { - var missionsConfig = ConfigService.Instance.missionMonitorConfiguration; - var missions = missionsConfig.missions.ToList(); - var missionids = new List(); // List of mission IDs for the next system + var missions = ConfigService.Instance.missionMonitorConfiguration.missions.ToList(); + if ( missions.Count == 0 ) { return null; } + var navRouteList = new NavWaypointCollection(Convert.ToDecimal(startSystem.x), Convert.ToDecimal(startSystem.y), Convert.ToDecimal(startSystem.z)); string searchSystem = null; long expiringSeconds = 0; - var navRouteList = new NavWaypointCollection(); - - if ( missions.Count > 0 ) + foreach ( var mission in missions + .Where ( m => m.statusEDName == "Active" + && m.expiry >= DateTime.UtcNow + && !string.IsNullOrEmpty ( m.destinationsystem ) ) ) { - foreach ( Mission mission in missions - .Where ( m => (m.statusEDName == "Active") - && (m.expiry >= DateTime.UtcNow) - && !string.IsNullOrEmpty ( m.destinationsystem ) ) - .ToList () ) + if ( expiringSeconds == 0 || mission.expiryseconds < expiringSeconds ) { - if ( (expiringSeconds == 0) || (mission.expiryseconds < expiringSeconds) ) - { - expiringSeconds = mission.expiryseconds ?? 0; - searchSystem = mission.destinationsystem; - } + expiringSeconds = mission.expiryseconds ?? 0; + searchSystem = mission.destinationsystem; } + } - if ( !string.IsNullOrEmpty ( searchSystem ) ) + if ( !string.IsNullOrEmpty ( searchSystem ) ) + { + var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(searchSystem, true, false, true, false, false); // Destination star system + navRouteList.Waypoints.Add ( new NavWaypoint ( startSystem ) { visited = true } ); + if ( startSystem.systemname != dest?.systemname ) { - var curr = EDDI.Instance?.CurrentStarSystem; - var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(searchSystem, true, false, true, false, false); // Destination star system - - navRouteList.Waypoints.Add ( new NavWaypoint ( curr ) { visited = true } ); - if ( curr?.systemname != dest?.systemname ) - { - navRouteList.Waypoints.Add ( new NavWaypoint ( dest ) { visited = dest?.systemname == curr?.systemname } ); - } + navRouteList.Waypoints.Add ( new NavWaypoint ( dest ) { visited = dest?.systemname == startSystem.systemname } ); } - - // Get mission IDs for 'expiring' system - missionids = NavigationService.GetSystemMissionIds ( searchSystem ); } + + // Get mission IDs for 'expiring' system + var missionids = NavigationService.GetSystemMissionIds ( searchSystem ); // List of mission IDs for the next system return new RouteDetailsEvent ( DateTime.UtcNow, QueryType.expiring.ToString (), searchSystem, null, navRouteList, expiringSeconds, missionids ); } } @@ -133,60 +108,55 @@ private RouteDetailsEvent GetExpiringMissionRoute () internal class FarthestMissionResolver : IQueryResolver { public QueryType Type => QueryType.farthest; - public RouteDetailsEvent Resolve ( Query query ) => GetFarthestMissionRoute (); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => GetFarthestMissionRoute ( startSystem ); /// Route to the star system furthest from the current star system with active missions /// The query result - private RouteDetailsEvent GetFarthestMissionRoute () + private RouteDetailsEvent GetFarthestMissionRoute ( [ NotNull ] StarSystem startSystem ) { - var missionsConfig = ConfigService.Instance.missionMonitorConfiguration; - var missions = missionsConfig.missions.ToList(); - var missionids = new List(); // List of mission IDs for the next system - string searchSystem = null; - var navRouteList = new NavWaypointCollection(); - - if ( missions.Count > 0 ) + var missions = ConfigService.Instance.missionMonitorConfiguration.missions.ToList(); + if ( missions.Count == 0 ) { return null; } + var navRouteList = new NavWaypointCollection(Convert.ToDecimal(startSystem.x), Convert.ToDecimal(startSystem.y), Convert.ToDecimal(startSystem.z)); + var farthestList = new SortedList(); + foreach ( var mission in missions.Where( m => m.statusDef == MissionStatus.Active ).ToList() ) { - var curr = EDDI.Instance?.CurrentStarSystem; - var farthestList = new SortedList(); - foreach ( Mission mission in missions.Where ( m => m.statusDef == MissionStatus.Active ).ToList () ) + if ( mission.destinationsystems != null && mission.destinationsystems.Any() ) { - if ( (mission.destinationsystems != null) && mission.destinationsystems.Any () ) + foreach ( var system in mission.destinationsystems ) { - foreach ( var system in mission.destinationsystems ) - { - var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(system.systemName, true, false, true, false, false); // Destination star system - decimal distance = NavigationService.CalculateDistance(curr, dest); - if ( !farthestList.ContainsKey ( distance ) ) - { - farthestList.Add ( distance, system ); - - } - } - } - else if ( !string.IsNullOrEmpty ( mission.destinationsystem ) ) - { - var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(mission.destinationsystem, true, false, true, false, false); // Destination star system - decimal distance = NavigationService.CalculateDistance(curr, dest); - if ( !farthestList.ContainsKey ( distance ) ) - { - farthestList.Add ( distance, new NavWaypoint ( dest ) { visited = dest.systemname == curr?.systemname } ); - } + var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem( system.systemName, true, false, true, false, false ); // Destination star system + SortSystemByDistance( dest, system ); } } - // Farthest system is last in the list - searchSystem = farthestList.Values.LastOrDefault ()?.systemName; + else if ( !string.IsNullOrEmpty( mission.destinationsystem ) ) + { + var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem( mission.destinationsystem, true, false, true, false, false ); // Destination star system + SortSystemByDistance( dest, new NavWaypoint( dest ) { visited = dest.systemname == startSystem.systemname } ); + } + continue; - navRouteList.Waypoints.Add ( new NavWaypoint ( curr ) { visited = true } ); - if ( curr?.systemname != farthestList.Values.LastOrDefault ()?.systemName ) + void SortSystemByDistance ( StarSystem dest, NavWaypoint system ) { - navRouteList.Waypoints.Add ( farthestList.Values.LastOrDefault () ); + var distance = NavigationService.CalculateDistance( startSystem, dest ); + if ( !farthestList.ContainsKey( distance ) ) + { + farthestList.Add( distance, system ); + } } + } + + // Farthest system is last in the list + var searchSystemName = farthestList.Values.LastOrDefault ()?.systemName; - // Get mission IDs for 'farthest' system - missionids = NavigationService.GetSystemMissionIds ( searchSystem ); + navRouteList.Waypoints.Add ( new NavWaypoint ( startSystem ) { visited = true } ); + if ( startSystem.systemname != farthestList.Values.LastOrDefault ()?.systemName ) + { + navRouteList.Waypoints.Add ( farthestList.Values.LastOrDefault () ); } - return new RouteDetailsEvent ( DateTime.UtcNow, QueryType.farthest.ToString (), searchSystem, null, navRouteList, missionids.Count, missionids ); + + // Get mission IDs for 'farthest' system + var missionids = NavigationService.GetSystemMissionIds ( searchSystemName ); // List of mission IDs for the next system + return new RouteDetailsEvent ( DateTime.UtcNow, QueryType.farthest.ToString (), searchSystemName, null, navRouteList, missionids.Count, missionids ); } } @@ -194,48 +164,30 @@ private RouteDetailsEvent GetFarthestMissionRoute () internal class MostMissionsResolver : IQueryResolver { public QueryType Type => QueryType.most; - public RouteDetailsEvent Resolve ( Query query ) => GetMostMissionRoute(query.StringArg0); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => GetMostMissionRoute( query.StringArg0, startSystem ); /// Route to the star system that provides the most active missions /// The query result - private RouteDetailsEvent GetMostMissionRoute ( string targetSystemName ) + private RouteDetailsEvent GetMostMissionRoute ( [ NotNull ] string targetSystemName, [ NotNull ] StarSystem startSystem ) { - var missionsConfig = ConfigService.Instance.missionMonitorConfiguration; - var missions = missionsConfig.missions.ToList(); - var missionids = new List(); // List of mission IDs for the next system - string searchSystem = null; - long mostCount = 0; - var navRouteList = new NavWaypointCollection(); - - if ( missions.Count > 0 ) + var missions = ConfigService.Instance.missionMonitorConfiguration.missions.ToList(); + if ( missions.Count == 0 ) { return null; } + var navRouteList = new NavWaypointCollection(Convert.ToDecimal(startSystem.x), Convert.ToDecimal(startSystem.y), Convert.ToDecimal(startSystem.z)); + + // Determine the number of missions per individual system + var systems = new List(); // Mission systems + var systemsCount = new List(); // Count of missions per system + + foreach ( var mission in missions.Where ( m => m.statusDef == MissionStatus.Active ) ) { - // Determine the number of missions per individual system - List systems = new List(); // Mission systems - List systemsCount = new List(); // Count of missions per system - foreach ( Mission mission in missions.Where ( m => m.statusDef == MissionStatus.Active ).ToList () ) + if ( mission.destinationsystems?.Any () ?? false ) { - if ( mission.destinationsystems?.Any () ?? false ) + foreach ( var system in mission.destinationsystems ) { - foreach ( var system in mission.destinationsystems ) - { - int index = systems.IndexOf(system.systemName); - if ( index == -1 ) - { - systems.Add ( system.systemName ); - systemsCount.Add ( 1 ); - } - else - { - systemsCount[ index ] += 1; - } - } - } - else if ( !string.IsNullOrEmpty ( mission.destinationsystem ) ) - { - int index = systems.IndexOf(mission.destinationsystem); + var index = systems.IndexOf(system.systemName); if ( index == -1 ) { - systems.Add ( mission.destinationsystem ); + systems.Add ( system.systemName ); systemsCount.Add ( 1 ); } else @@ -244,37 +196,50 @@ private RouteDetailsEvent GetMostMissionRoute ( string targetSystemName ) } } } - - // Sort the 'most' systems by distance - var mostList = new SortedList(); // List of 'most' systems, sorted by distance - mostCount = systemsCount.Max (); - var curr = !string.IsNullOrEmpty(targetSystemName) - ? StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(targetSystemName, true, false, true, false, false) - : EDDI.Instance?.CurrentStarSystem; - for ( int i = 0; i < systems.Count; i++ ) + else if ( !string.IsNullOrEmpty ( mission.destinationsystem ) ) { - if ( systemsCount[ i ] == mostCount ) + var index = systems.IndexOf(mission.destinationsystem); + if ( index == -1 ) { - var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(systems[i], true, false, true, false, false); // Destination star system - if ( dest?.x != null ) - { - mostList.Add ( NavigationService.CalculateDistance( curr, dest ), dest ); - } + systems.Add ( mission.destinationsystem ); + systemsCount.Add ( 1 ); + } + else + { + systemsCount[ index ] += 1; } } + } - // Nearest 'most' system is first in the list - searchSystem = mostList.Values.FirstOrDefault ()?.systemname; - - navRouteList.Waypoints.Add ( new NavWaypoint ( curr ) { visited = true } ); - if ( curr?.systemname != mostList.Values.FirstOrDefault ()?.systemname ) + // Sort the 'most' systems by distance + var mostList = new SortedList(); // List of 'most' systems, sorted by distance + long mostCount = systemsCount.Max (); + var curr = !string.IsNullOrEmpty(targetSystemName) + ? StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(targetSystemName, true, false, true, false, false) + : startSystem; + for ( var i = 0; i < systems.Count; i++ ) + { + if ( systemsCount[ i ] == mostCount ) { - navRouteList.Waypoints.Add ( new NavWaypoint ( mostList.Values.FirstOrDefault () ) { visited = mostList.Values.FirstOrDefault ()?.systemname == curr?.systemname } ); + var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(systems[i], true, false, true, false, false); // Destination star system + if ( dest?.x != null ) + { + mostList.Add ( NavigationService.CalculateDistance( curr, dest ), dest ); + } } + } + + // Nearest 'most' system is first in the list + var searchSystem = mostList.Values.FirstOrDefault ()?.systemname; - // Get mission IDs for 'most' system - missionids = NavigationService.GetSystemMissionIds ( searchSystem ); + navRouteList.Waypoints.Add ( new NavWaypoint ( curr ) { visited = true } ); + if ( curr?.systemname != mostList.Values.FirstOrDefault ()?.systemname ) + { + navRouteList.Waypoints.Add ( new NavWaypoint ( mostList.Values.FirstOrDefault () ) { visited = mostList.Values.FirstOrDefault ()?.systemname == curr?.systemname } ); } + + // Get mission IDs for 'most' system + var missionids = NavigationService.GetSystemMissionIds ( searchSystem ); // List of mission IDs for the next system return new RouteDetailsEvent ( DateTime.UtcNow, QueryType.most.ToString (), searchSystem, null, navRouteList, mostCount, missionids ); } } @@ -283,59 +248,53 @@ private RouteDetailsEvent GetMostMissionRoute ( string targetSystemName ) internal class NearestMissionResolver : IQueryResolver { public QueryType Type => QueryType.nearest; - public RouteDetailsEvent Resolve ( Query query ) => GetNearestMissionRoute (); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => GetNearestMissionRoute ( startSystem ); /// Route to the nearest star system with active missions /// The query result - private RouteDetailsEvent GetNearestMissionRoute () + private RouteDetailsEvent GetNearestMissionRoute ( [ NotNull ] StarSystem startSystem ) { - var missionsConfig = ConfigService.Instance.missionMonitorConfiguration; - var missions = missionsConfig.missions.ToList(); - var missionids = new List(); // List of mission IDs for the next system - string searchSystem = null; - var navRouteList = new NavWaypointCollection(); - - var curr = EDDI.Instance?.CurrentStarSystem; // Current star system - if ( missions.Count > 0 ) + var missions = ConfigService.Instance.missionMonitorConfiguration.missions.ToList(); + if ( missions.Count == 0 ) { return null; } + var navRouteList = new NavWaypointCollection(Convert.ToDecimal(startSystem.x), Convert.ToDecimal(startSystem.y), Convert.ToDecimal(startSystem.z)); + var nearestList = new SortedList(); + foreach ( var mission in missions.Where ( m => m.statusDef == MissionStatus.Active ) ) { - var nearestList = new SortedList(); - foreach ( Mission mission in missions.Where ( m => m.statusDef == MissionStatus.Active ).ToList () ) + if ( mission.destinationsystems != null && mission.destinationsystems.Any () ) { - if ( (mission.destinationsystems != null) && mission.destinationsystems.Any () ) + foreach ( var system in mission.destinationsystems ) { - foreach ( var system in mission.destinationsystems ) - { - var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(system.systemName, true, false, true, false, false); // Destination star system - decimal distance = NavigationService.CalculateDistance(curr, dest); - if ( !nearestList.ContainsKey ( distance ) ) - { - nearestList.Add ( distance, dest ); - - } - } - } - else if ( !string.IsNullOrEmpty ( mission.destinationsystem ) ) - { - var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(mission.destinationsystem, true, false, true, false, false); // Destination star system - decimal distance = NavigationService.CalculateDistance(curr, dest); + var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(system.systemName, true, false, true, false, false); // Destination star system + var distance = NavigationService.CalculateDistance(startSystem, dest); if ( !nearestList.ContainsKey ( distance ) ) { nearestList.Add ( distance, dest ); + } } } - // Nearest system is first in the list - searchSystem = nearestList.Values.FirstOrDefault ()?.systemname; - - navRouteList.Waypoints.Add ( new NavWaypoint ( curr ) { visited = true } ); - if ( curr?.systemname != nearestList.Values.FirstOrDefault ()?.systemname ) + else if ( !string.IsNullOrEmpty ( mission.destinationsystem ) ) { - navRouteList.Waypoints.Add ( new NavWaypoint ( nearestList.Values.FirstOrDefault () ) { visited = nearestList.Values.FirstOrDefault ()?.systemname == curr?.systemname } ); + var dest = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystem(mission.destinationsystem, true, false, true, false, false); // Destination star system + var distance = NavigationService.CalculateDistance(startSystem, dest); + if ( !nearestList.ContainsKey ( distance ) ) + { + nearestList.Add ( distance, dest ); + } } + } + + // Nearest system is first in the list + var searchSystem = nearestList.Values.FirstOrDefault ()?.systemname; - // Get mission IDs for 'farthest' system - missionids = NavigationService.GetSystemMissionIds ( searchSystem ); + navRouteList.Waypoints.Add ( new NavWaypoint ( startSystem ) { visited = true } ); + if ( startSystem.systemname != nearestList.Values.FirstOrDefault ()?.systemname ) + { + navRouteList.Waypoints.Add ( new NavWaypoint ( nearestList.Values.FirstOrDefault () ) { visited = nearestList.Values.FirstOrDefault ()?.systemname == startSystem?.systemname } ); } + + // Get mission IDs for 'farthest' system + var missionids = NavigationService.GetSystemMissionIds ( searchSystem ); // List of mission IDs for the next system return new RouteDetailsEvent ( DateTime.UtcNow, QueryType.nearest.ToString (), searchSystem, null, navRouteList, missionids.Count, missionids ); } } @@ -344,96 +303,83 @@ private RouteDetailsEvent GetNearestMissionRoute () internal class RepetiveNearestNeighborMissionResolver : IQueryResolver { public QueryType Type => QueryType.route; - public RouteDetailsEvent Resolve ( Query query ) => GetRepetiveNearestNeighborMissionRoute ( query.StringArg0 ); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => GetRepetiveNearestNeighborMissionRoute ( startSystem, query.StringArg0 ); /// Route that provides the shortest total travel path to complete all missions using the 'Repetitive Nearest Neighbor' Algorithm (RNNA) /// (Optional) If set, calculate relative to the named starting system rather than the current system /// The query result - private RouteDetailsEvent GetRepetiveNearestNeighborMissionRoute ( string homeSystem = null ) + private RouteDetailsEvent GetRepetiveNearestNeighborMissionRoute ( [ NotNull ] StarSystem currentSystem, string homeSystem = null ) { - var missionsConfig = ConfigService.Instance.missionMonitorConfiguration; - var missions = missionsConfig.missions.ToList(); - var navRouteList = new NavWaypointCollection(); - string searchSystem = null; - int routeCount = 0; - - var systems = new List(); // List of eligible mission destination systems - var missionids = new List(); // List of mission IDs for the next system - - var homeStarSystem = NavigationService.Instance.DataProviderService.GetSystemData(homeSystem, showCoordinates: false, showBodies: false, showStations: false, showFactions: false); - NavWaypoint homeSystemWaypoint = null; - if ( homeStarSystem != null ) - { - homeSystemWaypoint = new NavWaypoint ( homeStarSystem ); - } + var missions = ConfigService.Instance.missionMonitorConfiguration.missions.ToList(); + if ( missions.Count == 0 ) { return null; } - if ( missions.Count > 0 ) + // List of eligible mission destination systems + var systems = new List { // Add current star system first - var curr = EDDI.Instance?.CurrentStarSystem; - systems.Add ( curr?.systemname ); + currentSystem.systemname + }; - // Add origin systems for 'return to origin' missions to the 'systems' list - foreach ( Mission mission in missions.Where ( m => m.statusDef != MissionStatus.Failed ).ToList () ) + // Add origin systems for 'return to origin' missions to the 'systems' list + foreach ( var mission in missions.Where ( m => m.statusDef != MissionStatus.Failed ) ) + { + if ( mission.originreturn && !systems.Contains ( mission.originsystem ) ) { - if ( mission.originreturn && !systems.Contains ( mission.originsystem ) ) - { - systems.Add ( mission.originsystem ); - } + systems.Add ( mission.originsystem ); } + } - // Add destination systems for applicable mission types to the 'systems' list - foreach ( Mission mission in missions.Where ( m => m.statusDef == MissionStatus.Active ).ToList () ) + // Add destination systems for applicable mission types to the 'systems' list + foreach ( var mission in missions.Where ( m => m.statusDef == MissionStatus.Active ) ) + { + if ( mission.tagsList.Any ( t => t.IncludeInMissionRouting ) ) { - if ( mission.tagsList.Any ( t => t.IncludeInMissionRouting ) ) + if ( !( mission.destinationsystems?.Any () ?? false ) ) { - if ( !( mission.destinationsystems?.Any () ?? false ) ) + if ( !string.IsNullOrEmpty ( mission.destinationsystem ) && !systems.Contains ( mission.destinationsystem ) ) { - if ( !string.IsNullOrEmpty ( mission.destinationsystem ) && !systems.Contains ( mission.destinationsystem ) ) - { - systems.Add ( mission.destinationsystem ); - } + systems.Add ( mission.destinationsystem ); } - else + } + else + { + foreach ( var system in mission.destinationsystems ) { - foreach ( var system in mission.destinationsystems ) + if ( !systems.Contains ( system.systemName ) ) { - if ( !systems.Contains ( system.systemName ) ) - { - systems.Add ( system.systemName ); - } + systems.Add ( system.systemName ); } } } } + } - // Calculate the missions route using the 'Repetitive Nearest Neighbor' Algorithm (RNNA) - var navWaypoints = NavigationService.Instance.DataProviderService.GetSystemsData(systems.ToArray(), true, false, false, false).Select(s => new NavWaypoint(s)).ToList(); - if ( CalculateRepetiveNearestNeighbor ( navWaypoints, missions, out var sortedRoute, homeSystemWaypoint ) ) + // Calculate the missions route using the 'Repetitive Nearest Neighbor' Algorithm (RNNA) + var navWaypoints = NavigationService.Instance.DataProviderService.GetSystemsData(systems.ToArray(), true, false, false, false).Select(s => new NavWaypoint(s)).ToList(); + var homeStarSystem = NavigationService.Instance.DataProviderService.GetSystemData( homeSystem, showCoordinates: false, showBodies: false, showStations: false, showFactions: false ); + var homeSystemWaypoint = homeStarSystem is null ? null : new NavWaypoint( homeStarSystem ); + if ( CalculateRepetiveNearestNeighbor ( navWaypoints, missions, out var sortedRoute, homeSystemWaypoint ) ) + { + // Prepend our current system to the route if it is not already present + if ( sortedRoute.FirstOrDefault ()?.systemAddress != currentSystem.systemAddress ) { - // Prepend our current system to the route if it is not already present - if ( EDDI.Instance?.CurrentStarSystem != null && - sortedRoute.FirstOrDefault ()?.systemAddress != EDDI.Instance.CurrentStarSystem.systemAddress ) - { - sortedRoute = sortedRoute.Prepend ( new NavWaypoint ( EDDI.Instance.CurrentStarSystem ) ).ToList (); - sortedRoute[ 0 ].visited = true; - } + sortedRoute = sortedRoute.Prepend ( new NavWaypoint ( currentSystem ) { visited = true } ).ToList (); + } - navRouteList = new NavWaypointCollection ( sortedRoute ); - searchSystem = navRouteList.Waypoints.FirstOrDefault ( w => !w.visited )?.systemName; - routeCount = navRouteList.Waypoints.Count; + var navRouteList = new NavWaypointCollection ( sortedRoute ); + navRouteList.UpdateLocationData( currentSystem.systemAddress, currentSystem.x, currentSystem.y, currentSystem.z ); + var searchSystem = navRouteList.Waypoints.FirstOrDefault ( w => !w.visited )?.systemName; + var routeCount = navRouteList.Waypoints.Count; - Logging.Debug ( "Calculated Route Selected = " + string.Join ( ", ", sortedRoute.Select ( w => w.systemName ) ) + ", Total Distance = " + navRouteList.RouteDistance ); + Logging.Debug ( "Calculated Route Selected = " + string.Join ( ", ", sortedRoute.Select ( w => w.systemName ) ) + ", Total Distance = " + navRouteList.RouteDistance ); - // Get mission IDs for 'search' system - missionids = NavigationService.GetSystemMissionIds ( searchSystem ); - } - else - { - Logging.Debug ( "Unable to meet missions route calculation criteria" ); - } + // Get mission IDs for 'search' system + var missionids = NavigationService.GetSystemMissionIds ( searchSystem ); // List of mission IDs for the next system + return new RouteDetailsEvent( DateTime.UtcNow, QueryType.route.ToString(), searchSystem, null, navRouteList, routeCount, missionids ); } - return new RouteDetailsEvent ( DateTime.UtcNow, QueryType.route.ToString (), searchSystem, null, navRouteList, routeCount, missionids ); + + Logging.Debug ( "Unable to meet missions route calculation criteria" ); + return null; } private bool CalculateRepetiveNearestNeighbor ( List inputSystems, List missions, out List outputRoute, NavWaypoint homeSystem = null ) diff --git a/NavigationService/QueryResolvers/RouteQueryResolvers.cs b/NavigationService/QueryResolvers/RouteQueryResolvers.cs index 168282e756..f253195501 100644 --- a/NavigationService/QueryResolvers/RouteQueryResolvers.cs +++ b/NavigationService/QueryResolvers/RouteQueryResolvers.cs @@ -13,40 +13,39 @@ namespace EddiNavigationService.QueryResolvers internal class SetQueryResolver : IQueryResolver { public QueryType Type => QueryType.set; - public RouteDetailsEvent Resolve ( Query query ) => SetRoute ( query.StringArg0, query.StringArg1 ); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => SetRoute ( startSystem, query.StringArg0, query.StringArg1 ); - private static RouteDetailsEvent SetRoute ( string system, string station = null ) + private static RouteDetailsEvent SetRoute ( StarSystem startSystem, string system, string station = null ) { - NavWaypointCollection navRouteList; - NavWaypoint firstUnvisitedWaypoint; - // Use our saved route if a named system is not provided + // Disregard commands to set a route to the current star system. + if ( startSystem.systemname == system ) { return null; } + if ( string.IsNullOrEmpty ( system ) ) { - navRouteList = ConfigService.Instance.navigationMonitorConfiguration.plottedRouteList ?? new NavWaypointCollection (); - firstUnvisitedWaypoint = navRouteList.Waypoints.FirstOrDefault ( w => !w.visited ); + // Use our saved route if a named system is not provided + var navRouteList = ConfigService.Instance.navigationMonitorConfiguration.plottedRouteList ?? new NavWaypointCollection (); + navRouteList.UpdateLocationData( startSystem.systemAddress, startSystem.x, startSystem.y, startSystem.z ); + var firstUnvisitedWaypoint = navRouteList.Waypoints.FirstOrDefault ( w => !w.visited ); if ( firstUnvisitedWaypoint != null ) { return new RouteDetailsEvent ( DateTime.UtcNow, QueryType.set.ToString (), firstUnvisitedWaypoint.systemName, firstUnvisitedWaypoint.stationName, navRouteList, navRouteList.Waypoints.Count, firstUnvisitedWaypoint.missionids ); } } - - // Disregard commands to set a route to the current star system. - var curr = EDDI.Instance?.CurrentStarSystem; - if ( curr?.systemname == system ) - { return null; } - - // Set a course to a named system (and optionally station) - var neutronRoute = NavigationService.Instance.NavQuery(QueryType.neutron, system); - if ( neutronRoute == null || neutronRoute.Route.Waypoints.Count <= 1 ) - { return null; } - - navRouteList = neutronRoute.Route; - foreach ( var wp in navRouteList.Waypoints ) + else { - wp.missionids = NavigationService.GetSystemMissionIds ( wp.systemName ); + // Set a course to a named system (and optionally station) + var neutronRoute = NavigationService.Instance.NavQuery(QueryType.neutron, system); + if ( neutronRoute == null || neutronRoute.Route.Waypoints.Count == 1 ) { return null; } + var navRouteList = neutronRoute.Route; + navRouteList.UpdateLocationData( startSystem.systemAddress, startSystem.x, startSystem.y, startSystem.z ); + foreach ( var wp in navRouteList.Waypoints ) + { + wp.missionids = NavigationService.GetSystemMissionIds( wp.systemName ); + } + var firstUnvisitedWaypoint = navRouteList.Waypoints.FirstOrDefault( w => !w.visited ); + return new RouteDetailsEvent( DateTime.UtcNow, QueryType.set.ToString(), firstUnvisitedWaypoint?.systemName, firstUnvisitedWaypoint?.systemName == system ? station : null, navRouteList, navRouteList.Waypoints.Count, firstUnvisitedWaypoint?.missionids ?? new List() ); } - firstUnvisitedWaypoint = navRouteList.Waypoints.FirstOrDefault ( w => !w.visited ); - return new RouteDetailsEvent ( DateTime.UtcNow, QueryType.set.ToString (), firstUnvisitedWaypoint?.systemName, firstUnvisitedWaypoint?.systemName == system ? station : null, navRouteList, navRouteList.Waypoints.Count, firstUnvisitedWaypoint?.missionids ?? new List () ); + return null; } } @@ -54,7 +53,7 @@ private static RouteDetailsEvent SetRoute ( string system, string station = null internal class CancelQueryResolver : IQueryResolver { public QueryType Type => QueryType.cancel; - public RouteDetailsEvent Resolve ( Query query ) => CancelRoute (); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => CancelRoute (); private static RouteDetailsEvent CancelRoute () { @@ -77,11 +76,11 @@ private static RouteDetailsEvent CancelRoute () public class UpdateQueryResolver : IQueryResolver { public QueryType Type => QueryType.update; - public RouteDetailsEvent Resolve ( Query query ) => RefreshLastNavigationQuery (); + public RouteDetailsEvent Resolve ( Query query, StarSystem currentSystem ) => RefreshLastNavigationQuery ( currentSystem ); /// Repeat the last mission query and return an updated result if different from the prior result, either relative to your current location or to a named system /// The star system result from the repeated query - private static RouteDetailsEvent RefreshLastNavigationQuery () + private static RouteDetailsEvent RefreshLastNavigationQuery ( [ NotNull ] StarSystem currentSystem ) { var config = ConfigService.Instance.navigationMonitorConfiguration; if ( !( config?.plottedRouteList?.GuidanceEnabled ?? false ) ) @@ -92,7 +91,7 @@ private static RouteDetailsEvent RefreshLastNavigationQuery () var missionsList = ConfigService.Instance.missionMonitorConfiguration?.missions?.ToList() ?? new List(); if ( missionsList .Where ( m => m != null && m.statusDef == MissionStatus.Active ) - .Any ( m => m.destinationsystem == EDDI.Instance.CurrentStarSystem?.systemname ) ) + .Any ( m => m.destinationsystem == currentSystem.systemname ) ) { // We still have active missions at the current location return null; @@ -107,7 +106,7 @@ private static RouteDetailsEvent RefreshLastNavigationQuery () } var currentWaypoint = currentPlottedRoute?.Waypoints.FirstOrDefault( w => - w.systemAddress == EDDI.Instance.CurrentStarSystem?.systemAddress ); + w.systemAddress == currentSystem.systemAddress ); if ( currentWaypoint != null ) { // We're visiting a waypoint on the plotted route and need to update using the next unvisited waypoint diff --git a/NavigationService/QueryResolvers/ServiceQueryResolvers.cs b/NavigationService/QueryResolvers/ServiceQueryResolvers.cs index 205399c15e..413f7d66aa 100644 --- a/NavigationService/QueryResolvers/ServiceQueryResolvers.cs +++ b/NavigationService/QueryResolvers/ServiceQueryResolvers.cs @@ -15,49 +15,49 @@ namespace EddiNavigationService.QueryResolvers public class EncodedMaterialsTrader : IQueryResolver { public QueryType Type => QueryType.encoded; - public RouteDetailsEvent Resolve ( Query query ) => new ServiceQueryResolver ().Resolve( Type, query ); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => new ServiceQueryResolver ().Resolve( Type, query, startSystem ); } [UsedImplicitly] public class GuardianTechBroker : IQueryResolver { public QueryType Type => QueryType.guardian; - public RouteDetailsEvent Resolve ( Query query ) => new ServiceQueryResolver ().Resolve ( Type, query ); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => new ServiceQueryResolver ().Resolve ( Type, query, startSystem ); } [UsedImplicitly] public class HumanTechBroker : IQueryResolver { public QueryType Type => QueryType.human; - public RouteDetailsEvent Resolve ( Query query ) => new ServiceQueryResolver ().Resolve ( Type, query ); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => new ServiceQueryResolver ().Resolve ( Type, query, startSystem ); } [UsedImplicitly] public class InterstellarFactors : IQueryResolver { public QueryType Type => QueryType.facilitator; - public RouteDetailsEvent Resolve ( Query query ) => new ServiceQueryResolver ().Resolve ( Type, query ); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => new ServiceQueryResolver ().Resolve ( Type, query, startSystem ); } [UsedImplicitly] public class ManufacturedMaterialsTrader : IQueryResolver { public QueryType Type => QueryType.manufactured; - public RouteDetailsEvent Resolve ( Query query ) => new ServiceQueryResolver ().Resolve ( Type, query ); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => new ServiceQueryResolver ().Resolve ( Type, query, startSystem ); } [UsedImplicitly] public class RawMaterialsTrader : IQueryResolver { public QueryType Type => QueryType.raw; - public RouteDetailsEvent Resolve ( Query query ) => new ServiceQueryResolver ().Resolve ( Type, query ); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => new ServiceQueryResolver ().Resolve ( Type, query, startSystem ); } [UsedImplicitly] public class ScorpionSrvVendor : IQueryResolver { public QueryType Type => QueryType.scorpion; - public RouteDetailsEvent Resolve ( Query query ) => new ServiceQueryResolver ().Resolve ( Type, query ); + public RouteDetailsEvent Resolve ( Query query, StarSystem startSystem ) => new ServiceQueryResolver ().Resolve ( Type, query, startSystem ); } #region ServiceQueryResolver @@ -159,152 +159,130 @@ internal class ServiceQueryResolver } }; - public RouteDetailsEvent Resolve ( QueryType queryType, Query query ) => GetServiceSystem ( + public RouteDetailsEvent Resolve ( QueryType queryType, [NotNull] Query query, [NotNull] StarSystem startSystem ) => GetServiceSystem ( queryType, + startSystem, query.NumericArg is null ? (int?)null : Convert.ToInt32 ( Math.Round ( (decimal)query.NumericArg ) ), query.BooleanArg ); /// Route to the nearest star system that offers a specific service /// The query result - private static RouteDetailsEvent GetServiceSystem ( QueryType serviceQuery, int? maxDistanceOverride = null, bool? prioritizeOrbitalStationsOverride = null ) + private static RouteDetailsEvent GetServiceSystem ( QueryType serviceQuery, [NotNull] StarSystem startSystem, int? maxDistanceOverride = null, bool? prioritizeOrbitalStationsOverride = null ) { // Get up-to-date configuration data var navConfig = ConfigService.Instance.navigationMonitorConfiguration; - int maxStationDistance = maxDistanceOverride ?? navConfig.maxSearchDistanceFromStarLs ?? 10000; - bool prioritizeOrbitalStations = prioritizeOrbitalStationsOverride ?? navConfig.prioritizeOrbitalStations; + var maxStationDistance = maxDistanceOverride ?? navConfig.maxSearchDistanceFromStarLs ?? 10000; + var prioritizeOrbitalStations = prioritizeOrbitalStationsOverride ?? navConfig.prioritizeOrbitalStations; - var currentSystem = EDDI.Instance.CurrentStarSystem; - if ( currentSystem != null ) + if ( ServiceFilters.TryGetValue( serviceQuery, out var filter ) ) { - var shipSize = EDDI.Instance.CurrentShip?.Size ?? LandingPadSize.Large; - if ( ServiceFilters.TryGetValue ( serviceQuery, out var filter ) ) - { - // Scorpions are only found at Surface Ports - if ( serviceQuery is QueryType.scorpion ) - { prioritizeOrbitalStations = false; } - - var serviceStarSystem = GetServiceSystem(serviceQuery, maxStationDistance, prioritizeOrbitalStations); - - if ( serviceStarSystem is null && prioritizeOrbitalStations ) - { - serviceStarSystem = GetServiceSystem ( serviceQuery, maxStationDistance, false ); - } + // Scorpions are only found at Surface Ports + if ( serviceQuery is QueryType.scorpion ) { prioritizeOrbitalStations = false; } - if ( serviceStarSystem != null ) - { - var searchSystem = serviceStarSystem; - - // Find stations which meet the search preference and filter requirements - var serviceStations = FilterSystemStations(serviceQuery, prioritizeOrbitalStations, serviceStarSystem, maxStationDistance, filter, shipSize); - - // Build list to find the station nearest to the main star - var nearestList = new SortedList (); - foreach ( var station in serviceStations ) - { - if ( !nearestList.ContainsKey ( station.distancefromstar ?? 0 ) ) - { - nearestList.Add ( station.distancefromstar ?? 0, station.name ); - } - } + var serviceStarSystem = GetServiceSystem( serviceQuery, startSystem, maxStationDistance, prioritizeOrbitalStations ); + if ( serviceStarSystem is null && prioritizeOrbitalStations ) + { + serviceStarSystem = GetServiceSystem( serviceQuery, startSystem, maxStationDistance, false ); + } + if ( serviceStarSystem == null ) { return null; } - // Station is nearest to the main star which meets the service query - var searchStation = nearestList.Values.FirstOrDefault(); + // Find stations which meet the search preference and filter requirements + var serviceStations = FilterSystemStations( serviceQuery, prioritizeOrbitalStations, serviceStarSystem, maxStationDistance, filter, EDDI.Instance.CurrentShip?.Size ?? LandingPadSize.Large ); - // Update the navRouteList - var navRouteList = new NavWaypointCollection(); - navRouteList.Waypoints.Add ( new NavWaypoint ( currentSystem ) { visited = true } ); - if ( currentSystem.systemname != searchSystem.systemname ) - { - navRouteList.Waypoints.Add ( new NavWaypoint ( searchSystem ) - { - visited = searchSystem.systemname == currentSystem.systemname, - stationName = searchStation - } ); - } + // Build list to find the station nearest to the main star + var nearestList = new SortedList(); + foreach (var station in serviceStations.Where(station => !nearestList.ContainsKey( station.distancefromstar ?? 0 ))) + { + nearestList.Add( station.distancefromstar ?? 0, station.name ); + } - // Get mission IDs for 'service' system - var missionids = NavigationService.GetSystemMissionIds(searchSystem.systemname); + // Station is nearest to the main star which meets the service query + var searchStation = nearestList.Values.FirstOrDefault(); - return new RouteDetailsEvent ( DateTime.UtcNow, serviceQuery.ToString (), searchSystem.systemname, searchStation, navRouteList, missionids.Count, missionids ); - } - } - else + // Update the navRouteList + var navRouteList = new NavWaypointCollection(Convert.ToDecimal(startSystem.x), Convert.ToDecimal(startSystem.y), Convert.ToDecimal(startSystem.z)); + navRouteList.Waypoints.Add( new NavWaypoint( startSystem ) { visited = true } ); + if ( startSystem.systemname != serviceStarSystem.systemname ) { - Logging.Error ( $"No navigation query filter found for query type {serviceQuery}." ); + navRouteList.Waypoints.Add( new NavWaypoint( serviceStarSystem ) + { + visited = serviceStarSystem.systemname == startSystem.systemname, + stationName = searchStation + } ); } + + // Get mission IDs for 'service' system + var missionids = NavigationService.GetSystemMissionIds( serviceStarSystem.systemname ); + + return new RouteDetailsEvent( DateTime.UtcNow, serviceQuery.ToString(), serviceStarSystem.systemname, searchStation, navRouteList, missionids.Count, missionids ); } else { - Logging.Warn ( "Unable to obtain navigation service result - current star system is not known." ); + Logging.Error( $"No navigation query filter found for query type {serviceQuery}." ); } + return null; } - private static StarSystem GetServiceSystem ( QueryType serviceQuery, int maxStationDistance, bool prioritizeOrbitalStations ) + private static StarSystem GetServiceSystem ( QueryType serviceQuery, [NotNull] StarSystem startSystem, int maxStationDistance, bool prioritizeOrbitalStations ) { - var currentSystem = EDDI.Instance?.CurrentStarSystem; - if ( currentSystem != null ) + // Get the filter parameters + var shipSize = EDDI.Instance.CurrentShip?.Size ?? LandingPadSize.Large; + if ( ServiceFilters.TryGetValue ( serviceQuery, out var filter ) ) { - // Get the filter parameters - var shipSize = EDDI.Instance.CurrentShip?.Size ?? LandingPadSize.Large; - if ( ServiceFilters.TryGetValue ( serviceQuery, out ServiceFilter filter ) ) - { - int cubeLy = filter.cubeLy; - var checkedSystems = new List (); - var maxTries = 5; + var cubeLy = filter.cubeLy; + var checkedSystems = new List (); + var maxTries = 5; - while ( maxTries > 0 ) + while ( maxTries > 0 ) + { + var cubeSystems = NavigationService.Instance.EdsmService.GetStarMapSystemsCube(startSystem.systemname, cubeLy); + if ( cubeSystems?.Any () ?? false ) { - var cubeSystems = NavigationService.Instance.EdsmService.GetStarMapSystemsCube(currentSystem.systemname, cubeLy); - if ( cubeSystems?.Any () ?? false ) + // Filter systems using search parameters + cubeSystems = cubeSystems.Where ( s => s.population >= filter.minPopulation ).ToList (); + cubeSystems = cubeSystems + .Where ( s => filter.security?.Any ( filterSecurity => s.securityLevel == filterSecurity ) ?? true ).ToList (); + cubeSystems = cubeSystems + .Where ( s => filter.systemEconomies?.Any ( filterEconomy => s.Economies.Any ( stationEconomy => filterEconomy == stationEconomy ) ) ?? true ) + .ToList (); + + // Retrieve systems in current shell which have not been previously checked + var systemNames = + cubeSystems.Select(s => s.systemname).Except(checkedSystems).ToList(); + if ( systemNames.Count > 0 ) { - // Filter systems using search parameters - cubeSystems = cubeSystems.Where ( s => s.population >= filter.minPopulation ).ToList (); - cubeSystems = cubeSystems - .Where ( s => filter.security?.Any ( filterSecurity => s.securityLevel == filterSecurity ) ?? true ).ToList (); - cubeSystems = cubeSystems - .Where ( s => filter.systemEconomies?.Any ( filterEconomy => s.Economies.Any ( stationEconomy => filterEconomy == stationEconomy ) ) ?? true ) - .ToList (); - - // Retrieve systems in current shell which have not been previously checked - var systemNames = - cubeSystems.Select(s => s.systemname).Except(checkedSystems).ToList(); - if ( systemNames.Count > 0 ) + var starSystems = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystems(systemNames.ToArray(), true, true, false, true, false); + checkedSystems.AddRange ( systemNames ); + + var nearestList = new SortedList (); + foreach ( var starsystem in starSystems ) { - var starSystems = StarSystemSqLiteRepository.Instance.GetOrFetchStarSystems(systemNames.ToArray(), true, true, false, true, false); - checkedSystems.AddRange ( systemNames ); + // Find stations which meet the search preference and filter requirements + var stations = FilterSystemStations(serviceQuery, prioritizeOrbitalStations, starsystem, maxStationDistance, filter, shipSize); - var nearestList = new SortedList (); - foreach ( var starsystem in starSystems ) + // Build list to find the 'service' system nearest to the current system, meeting station requirements + if ( stations.Count <= 0 ) { continue; } + var distance = NavigationService.CalculateDistance(startSystem, starsystem); + if ( !nearestList.ContainsKey ( distance ) ) { - // Find stations which meet the search preference and filter requirements - var stations = FilterSystemStations(serviceQuery, prioritizeOrbitalStations, starsystem, maxStationDistance, filter, shipSize); - - // Build list to find the 'service' system nearest to the current system, meeting station requirements - if ( stations.Count > 0 ) - { - decimal distance = NavigationService.CalculateDistance(currentSystem, starsystem); - if ( !nearestList.ContainsKey ( distance ) ) - { - nearestList.Add ( distance, starsystem.systemname ); - } - } + nearestList.Add ( distance, starsystem.systemname ); } + } - // Nearest 'service' system - var serviceSystem = nearestList.Values.FirstOrDefault(); - if ( serviceSystem != null ) - { - return starSystems.FirstOrDefault ( s => s.systemname == serviceSystem ); - } + // Nearest 'service' system + var serviceSystem = nearestList.Values.FirstOrDefault(); + if ( serviceSystem != null ) + { + return starSystems.FirstOrDefault ( s => s.systemname == serviceSystem ); } } - - // Increase search radius in 10 Ly increments (up from the starting shell size) until the required 'service' is found - cubeLy += 10; - maxTries--; } + + // Increase search radius in 10 Ly increments (up from the starting shell size) until the required 'service' is found + cubeLy += 10; + maxTries--; } } return null;