From 5fb434a078fcc6ad3352f1b10cbabbd9e0e5478a Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Sun, 20 Aug 2023 23:33:27 +0000 Subject: [PATCH] refactor: Use local BehaviorState BehaviorState was originally introduced as side-loaded per-ship data but we added passing it to behavior functions a while back. This change makes us use the local version of state in almost all cases. Added BehaviorState.isComplete, but are not using it yet, it seemed the most risky of the possible changes. --- packages/cli/lib/behavior/advance.dart | 8 +++ packages/cli/lib/behavior/buy_ship.dart | 1 + .../cli/lib/behavior/central_command.dart | 72 ------------------- packages/cli/lib/behavior/change_mounts.dart | 5 +- packages/cli/lib/behavior/deliver.dart | 7 +- packages/cli/lib/behavior/explorer.dart | 4 ++ packages/cli/lib/behavior/miner.dart | 6 +- packages/cli/lib/behavior/surveyor.dart | 1 + packages/cli/lib/behavior/trader.dart | 19 +++++ packages/cli/lib/nav/navigation.dart | 13 ++-- .../test/behavior/central_command_test.dart | 20 ++---- packages/cli/test/nav/navigation_test.dart | 6 +- packages/types/lib/behavior.dart | 6 +- 13 files changed, 71 insertions(+), 97 deletions(-) diff --git a/packages/cli/lib/behavior/advance.dart b/packages/cli/lib/behavior/advance.dart index 2bf6125f..65197d09 100644 --- a/packages/cli/lib/behavior/advance.dart +++ b/packages/cli/lib/behavior/advance.dart @@ -73,6 +73,7 @@ Future advanceShipBehavior( final navResult = await continueNavigationIfNeeded( api, ship, + state, caches.ships, caches.systems, centralCommand, @@ -94,6 +95,13 @@ Future advanceShipBehavior( ship, getNow: getNow, ); + if (state.isComplete) { + // If the behavior is complete, clear it. + centralCommand.completeBehavior(ship.shipSymbol); + } else { + // Otherwise update the behavior state. + centralCommand.setBehavior(ship.shipSymbol, state); + } return waitUntil; } on JobException catch (error) { centralCommand.disableBehaviorForShip( diff --git a/packages/cli/lib/behavior/buy_ship.dart b/packages/cli/lib/behavior/buy_ship.dart index 164c0983..c9cb9edf 100644 --- a/packages/cli/lib/behavior/buy_ship.dart +++ b/packages/cli/lib/behavior/buy_ship.dart @@ -265,6 +265,7 @@ Future advanceBuyShip( return beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, diff --git a/packages/cli/lib/behavior/central_command.dart b/packages/cli/lib/behavior/central_command.dart index 2cad70b0..533b50f4 100644 --- a/packages/cli/lib/behavior/central_command.dart +++ b/packages/cli/lib/behavior/central_command.dart @@ -383,22 +383,6 @@ class CentralCommand { return _behaviorCache.deleteBehavior(shipSymbol); } - /// Returns any mount that's been queued for adding to this ship. - ShipMountSymbolEnum? getMountToAdd(ShipSymbol shipSymbol) { - final state = _behaviorCache.getBehavior(shipSymbol); - return state?.mountToAdd; - } - - /// Saves the given mount to be added to the ship. - void claimMount(ShipSymbol shipSymbol, ShipMountSymbolEnum mountSymbol) { - final state = _behaviorCache.getBehavior(shipSymbol); - if (state == null) { - logger.warn('No state for $shipSymbol'); - return; - } - state.mountToAdd = mountSymbol; - } - /// Returns the delivery ship bringing the mounts. Ship? getDeliveryShip(ShipSymbol shipSymbol, TradeSymbol item) { final deliveryShip = _shipCache.ships.first; @@ -455,62 +439,6 @@ class CentralCommand { return available.difference(claimed); } - /// Sets the deliver state for the given ship. - void setBuyJob(Ship ship, BuyJob buyJob) { - final shipSymbol = ship.shipSymbol; - final state = _behaviorCache.getBehavior(shipSymbol); - if (state == null) { - shipWarn(ship, 'No state for $shipSymbol'); - return; - } - state.buyJob = buyJob; - } - - /// Returns the DeliverState for the given ship. - BuyJob? getBuyJob(Ship ship) { - final shipSymbol = ship.shipSymbol; - final state = _behaviorCache.getBehavior(shipSymbol); - return state?.buyJob; - } - - /// Sets the deliver state for the given ship. - void setDeliverJob(Ship ship, DeliverJob deliverJob) { - final shipSymbol = ship.shipSymbol; - final state = _behaviorCache.getBehavior(shipSymbol); - if (state == null) { - shipWarn(ship, 'No state for $shipSymbol'); - return; - } - state.deliverJob = deliverJob; - } - - /// Returns the DeliverState for the given ship. - DeliverJob? getDeliverJob(Ship ship) { - final shipSymbol = ship.shipSymbol; - final state = _behaviorCache.getBehavior(shipSymbol); - return state?.deliverJob; - } - - /// Set the [RoutePlan] for the ship. - void setRoutePlan(Ship ship, RoutePlan routePlan) { - final state = _behaviorCache.getBehavior(ship.shipSymbol)! - ..routePlan = routePlan; - _behaviorCache.setBehavior(ship.shipSymbol, state); - } - - /// Get the current [RoutePlan] for the given ship. - RoutePlan? currentRoutePlan(Ship ship) { - final state = _behaviorCache.getBehavior(ship.shipSymbol); - return state?.routePlan; - } - - /// The [ship] has reached its destination. - void reachedEndOfRoutePlan(Ship ship) { - final state = _behaviorCache.getBehavior(ship.shipSymbol)! - ..routePlan = null; - _behaviorCache.setBehavior(ship.shipSymbol, state); - } - /// Record the given [transactions] for the current deal for [ship]. void recordDealTransactions( Ship ship, diff --git a/packages/cli/lib/behavior/change_mounts.dart b/packages/cli/lib/behavior/change_mounts.dart index c635cf50..6c34cc6d 100644 --- a/packages/cli/lib/behavior/change_mounts.dart +++ b/packages/cli/lib/behavior/change_mounts.dart @@ -38,7 +38,7 @@ Future advanceChangeMounts( Ship ship, { DateTime Function() getNow = defaultGetNow, }) async { - final toMount = centralCommand.getMountToAdd(ship.shipSymbol); + final toMount = state.mountToAdd; // Re-validate every loop in case resuming from error. final template = assertNotNull( @@ -170,12 +170,13 @@ Future advanceChangeMounts( const Duration(minutes: 10), ); shipInfo(ship, 'Claiming mount: $toClaim.'); - centralCommand.claimMount(ship.shipSymbol, toClaim); + state.mountToAdd = toClaim; // Go to the shipyard. final waitUntil = beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, diff --git a/packages/cli/lib/behavior/deliver.dart b/packages/cli/lib/behavior/deliver.dart index e3ee433b..d83cf1bf 100644 --- a/packages/cli/lib/behavior/deliver.dart +++ b/packages/cli/lib/behavior/deliver.dart @@ -187,6 +187,7 @@ Future doBuyJob( centralCommand, caches, ship, + state, maybeMarket, buyJob.tradeSymbol, ); @@ -199,6 +200,7 @@ Future doBuyJob( final waitUntil = await beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, @@ -309,6 +311,7 @@ Future doDeliverJob( final waitUntil = await beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, @@ -346,7 +349,7 @@ Future doInitJob( const Duration(minutes: 20), ); - centralCommand.setBuyJob(ship, buyJob); + state.buyJob = buyJob; final hqSystem = caches.agent.headquartersSymbol.systemSymbol; final hqWaypoints = await caches.waypoints.waypointsInSystem(hqSystem); @@ -356,7 +359,7 @@ Future doInitJob( tradeSymbol: buyJob.tradeSymbol, waypointSymbol: shipyard.waypointSymbol, ); - centralCommand.setDeliverJob(ship, deliverJob); + state.deliverJob = deliverJob; return JobResult.complete(); } diff --git a/packages/cli/lib/behavior/explorer.dart b/packages/cli/lib/behavior/explorer.dart index 213e5186..8eea79d6 100644 --- a/packages/cli/lib/behavior/explorer.dart +++ b/packages/cli/lib/behavior/explorer.dart @@ -222,6 +222,7 @@ Future routeForEmergencyFuelingIfNeeded( CentralCommand centralCommand, Waypoint waypoint, Ship ship, + BehaviorState state, ) async { if (ship.fuelPercentage > 0.4) { return null; @@ -250,6 +251,7 @@ Future routeForEmergencyFuelingIfNeeded( final waitUntil = await beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, @@ -314,6 +316,7 @@ Future advanceExplorer( centralCommand, waypoint, ship, + state, ); if (refuelWaitTime != null) { return refuelWaitTime; @@ -350,6 +353,7 @@ Future advanceExplorer( return beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, diff --git a/packages/cli/lib/behavior/miner.dart b/packages/cli/lib/behavior/miner.dart index 4919f6d8..a1d608cd 100644 --- a/packages/cli/lib/behavior/miner.dart +++ b/packages/cli/lib/behavior/miner.dart @@ -206,8 +206,8 @@ class MineJob { // - Navigate to mine // - Survey if needed // - Mine +// - Handle cargo (navigate to market, sell, jettison, etc) // - Navigate to market -// - Sell /// Apply the miner behavior to the ship. Future advanceMiner( @@ -272,6 +272,7 @@ Future advanceMiner( return beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, @@ -289,6 +290,7 @@ Future advanceMiner( return beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, @@ -324,6 +326,8 @@ Future advanceMiner( if (ship.isCommand) { centralCommand.completeBehavior(ship.shipSymbol); } + // We wait the full cooldown because our next action will be either + // surveying or mining, both of which require the reactor cooldown. return response.cooldown.expiration; } diff --git a/packages/cli/lib/behavior/surveyor.dart b/packages/cli/lib/behavior/surveyor.dart index ac283cf8..274fde22 100644 --- a/packages/cli/lib/behavior/surveyor.dart +++ b/packages/cli/lib/behavior/surveyor.dart @@ -25,6 +25,7 @@ Future advanceSurveyor( return beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, diff --git a/packages/cli/lib/behavior/trader.dart b/packages/cli/lib/behavior/trader.dart index 36758dc4..39a78a32 100644 --- a/packages/cli/lib/behavior/trader.dart +++ b/packages/cli/lib/behavior/trader.dart @@ -129,6 +129,7 @@ Future _handleAtSourceWithDeal( CentralCommand centralCommand, Caches caches, Ship ship, + BehaviorState state, Market currentMarket, CostedDeal costedDeal, ) async { @@ -192,6 +193,7 @@ Future _handleAtSourceWithDeal( return beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, @@ -344,6 +346,7 @@ Future _handleOffCourseWithDeal( CentralCommand centralCommand, Caches caches, Ship ship, + BehaviorState state, CostedDeal costedDeal, ) { final haveDealCargo = ship.cargo.countUnits(costedDeal.tradeSymbol) > 0; @@ -352,6 +355,7 @@ Future _handleOffCourseWithDeal( return beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, @@ -365,6 +369,7 @@ Future _handleOffCourseWithDeal( return beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, @@ -380,6 +385,7 @@ Future _handleAtDestinationWithDeal( CentralCommand centralCommand, Caches caches, Ship ship, + BehaviorState state, Market currentMarket, CostedDeal costedDeal, ) { @@ -390,6 +396,7 @@ Future _handleAtDestinationWithDeal( return beingNewRouteAndLog( api, ship, + state, caches.ships, caches.systems, caches.routePlanner, @@ -425,6 +432,7 @@ Future _handleDeal( Caches caches, CostedDeal costedDeal, Ship ship, + BehaviorState state, Market? currentMarket, ) async { // If we're at the source buy the cargo. @@ -440,6 +448,7 @@ Future _handleDeal( centralCommand, caches, ship, + state, currentMarket, costedDeal, ); @@ -457,6 +466,7 @@ Future _handleDeal( centralCommand, caches, ship, + state, currentMarket, costedDeal, ); @@ -466,6 +476,7 @@ Future _handleDeal( centralCommand, caches, ship, + state, costedDeal, ); } @@ -536,6 +547,7 @@ Future _navigateToBetterTradeLocation( MarketPrices marketPrices, ShipCache shipCache, Ship ship, + BehaviorState state, String why, ) async { shipWarn(ship, why); @@ -556,6 +568,7 @@ Future _navigateToBetterTradeLocation( final waitUntil = await beingNewRouteAndLog( api, ship, + state, shipCache, systemsCache, routePlanner, @@ -572,6 +585,7 @@ Future handleUnwantedCargoIfNeeded( CentralCommand centralCommand, Caches caches, Ship ship, + BehaviorState state, Market? currentMarket, TradeSymbol? wantedTradeSymbol, ) async { @@ -629,6 +643,7 @@ Future handleUnwantedCargoIfNeeded( final waitUntil = await beingRouteAndLog( api, ship, + state, caches.ships, caches.systems, centralCommand, @@ -693,6 +708,7 @@ Future advanceTrader( centralCommand, caches, ship, + state, currentMarket, pastDeal?.tradeSymbol, ); @@ -709,6 +725,7 @@ Future advanceTrader( caches, pastDeal, ship, + state, currentMarket, ); return waitUntil; @@ -739,6 +756,7 @@ Future advanceTrader( caches.marketPrices, caches.ships, ship, + state, why, ); return waitUntil; @@ -768,6 +786,7 @@ Future advanceTrader( caches, newDeal, ship, + state, currentMarket, ); return waitUntil; diff --git a/packages/cli/lib/nav/navigation.dart b/packages/cli/lib/nav/navigation.dart index 10b1b5dd..8bedd89d 100644 --- a/packages/cli/lib/nav/navigation.dart +++ b/packages/cli/lib/nav/navigation.dart @@ -14,6 +14,7 @@ import 'package:types/types.dart'; Future beingNewRouteAndLog( Api api, Ship ship, + BehaviorState state, ShipCache shipCache, SystemsCache systemsCache, RoutePlanner routePlanner, @@ -43,6 +44,7 @@ Future beingNewRouteAndLog( final waitTime = await beingRouteAndLog( api, ship, + state, shipCache, systemsCache, centralCommand, @@ -57,6 +59,7 @@ Future beingNewRouteAndLog( Future beingRouteAndLog( Api api, Ship ship, + BehaviorState state, ShipCache shipCache, SystemsCache systemsCache, CentralCommand centralCommand, @@ -67,12 +70,13 @@ Future beingRouteAndLog( return null; } - centralCommand.setRoutePlan(ship, routePlan); + state.routePlan = routePlan; // TODO(eseidel): Should this buy fuel first if we need it? shipInfo(ship, 'Beginning route to ${routePlan.endSymbol}'); final navResult = await continueNavigationIfNeeded( api, ship, + state, shipCache, systemsCache, centralCommand, @@ -150,6 +154,7 @@ void _verifyJumpTime( Future continueNavigationIfNeeded( Api api, Ship ship, + BehaviorState state, ShipCache shipCache, SystemsCache systemsCache, CentralCommand centralCommand, { @@ -173,21 +178,21 @@ Future continueNavigationIfNeeded( // has arrived before we got a chance to update it here. ship.nav.status = ShipNavStatus.IN_ORBIT; } - final routePlan = centralCommand.currentRoutePlan(ship); + final routePlan = state.routePlan; if (routePlan == null) { // We don't have a routePlan, so we can't navigate. return NavResult._continueAction(); } if (routePlan.actions.isEmpty) { shipWarn(ship, "Route plan is empty, assuming we're already there."); - centralCommand.reachedEndOfRoutePlan(ship); + state.routePlan = null; return NavResult._continueAction(); } // We've reached the routePlan, so we can stop navigating. if (ship.waypointSymbol == routePlan.endSymbol) { // Remove the destination from the ship's state or it will try to come back. - centralCommand.reachedEndOfRoutePlan(ship); + state.routePlan = null; return NavResult._continueAction(); } final action = routePlan.nextActionFrom(ship.waypointSymbol); diff --git a/packages/cli/test/behavior/central_command_test.dart b/packages/cli/test/behavior/central_command_test.dart index 24947ffe..c9ab4731 100644 --- a/packages/cli/test/behavior/central_command_test.dart +++ b/packages/cli/test/behavior/central_command_test.dart @@ -132,33 +132,27 @@ void main() { when(() => shipA.symbol).thenReturn(aSymbol.symbol); when(() => shipNavA.systemSymbol).thenReturn('S-A'); when(() => shipA.nav).thenReturn(shipNavA); - centralCommand.setBehavior( - aSymbol, - BehaviorState(aSymbol, Behavior.explorer), - ); + final stateA = BehaviorState(aSymbol, Behavior.explorer); + centralCommand.setBehavior(aSymbol, stateA); final saa = WaypointSymbol.fromString('S-A-A'); final saw = WaypointSymbol.fromString('S-A-W'); - centralCommand.setRoutePlan(shipA, fakeJump(saa, saw)); + stateA.routePlan = fakeJump(saa, saw); final shipB = _MockShip(); final shipBSymbol = ShipSymbol.fromString('X-B'); when(() => shipB.symbol).thenReturn(shipBSymbol.symbol); final shipNavB = _MockShipNav(); when(() => shipNavB.systemSymbol).thenReturn('S-C'); when(() => shipB.nav).thenReturn(shipNavB); - centralCommand.setBehavior( - shipBSymbol, - BehaviorState(shipBSymbol, Behavior.explorer), - ); + final stateB = BehaviorState(shipBSymbol, Behavior.explorer); + centralCommand.setBehavior(shipBSymbol, stateB); final sbw = WaypointSymbol.fromString('S-B-W'); - centralCommand.setRoutePlan(shipB, fakeJump(saa, sbw)); - expect(centralCommand.currentRoutePlan(shipB)!.endSymbol, sbw); + stateB.routePlan = fakeJump(saa, sbw); when(() => shipCache.ship(shipBSymbol)).thenReturn(shipB); final otherSystems = centralCommand.otherExplorerSystems(aSymbol).toList(); expect(otherSystems, [sbw.systemSymbol]); // From destination - centralCommand.reachedEndOfRoutePlan(shipB); - expect(centralCommand.currentRoutePlan(shipB), isNull); + stateB.routePlan = null; final otherSystems2 = centralCommand.otherExplorerSystems(aSymbol).toList(); expect( otherSystems2, diff --git a/packages/cli/test/nav/navigation_test.dart b/packages/cli/test/nav/navigation_test.dart index e7fc45fc..2e2d0737 100644 --- a/packages/cli/test/nav/navigation_test.dart +++ b/packages/cli/test/nav/navigation_test.dart @@ -38,8 +38,8 @@ void main() { final centralCommand = _MockCentralCommand(); /// The behavior doesn't matter, just needs to have a null destination. - when(() => centralCommand.getBehavior(shipSymbol)) - .thenAnswer((_) => BehaviorState(shipSymbol, Behavior.idle)); + final state = BehaviorState(shipSymbol, Behavior.idle); + when(() => centralCommand.getBehavior(shipSymbol)).thenAnswer((_) => state); final now = DateTime(2021); DateTime getNow() => now; @@ -56,6 +56,7 @@ void main() { () => continueNavigationIfNeeded( api, ship, + state, shipCache, systemsCache, centralCommand, @@ -79,6 +80,7 @@ void main() { () => continueNavigationIfNeeded( api, ship, + state, shipCache, systemsCache, centralCommand, diff --git a/packages/types/lib/behavior.dart b/packages/types/lib/behavior.dart index efde5ae6..747db20b 100644 --- a/packages/types/lib/behavior.dart +++ b/packages/types/lib/behavior.dart @@ -51,7 +51,7 @@ class BehaviorState { this.buyJob, this.deliverJob, this.jobIndex = 0, - }); + }) : isComplete = false; /// Create a new behavior state from JSON. factory BehaviorState.fromJson(Map json) { @@ -109,6 +109,10 @@ class BehaviorState { /// Mount to add. ShipMountSymbolEnum? mountToAdd; + /// This behavior is complete. + /// Never written to disk (instead the behavior state is deleted). + bool isComplete; + /// Convert this to JSON. Map toJson() { return {