* @license MIT License * @version GIT: * @link https://git.keithsolomon.net/keith/Spacetraders */ require_once __DIR__ . '/lib/spacetraders-api.php'; require_once __DIR__ . '/lib/spacetraders-storage.php'; /** * Filter only mining ships. * * @param array> $ships * * @return array> */ function filterMiningShips( array $ships ): array { return array_values( array_filter( $ships, static function ( array $ship ): bool { $role = strtoupper( (string) ( $ship['registration']['role'] ?? '' ) ); return $role === 'EXCAVATOR'; } ) ); } $config = require __DIR__ . '/lib/project-config.php'; $storage = new SpacetradersStorage( $config['db_path'] ); $token = $storage->getAgentToken(); $statusMessage = ''; $errorMessage = ''; $actionResults = array(); $agent = array(); $ships = array(); $miningShips = array(); $activeContracts = array(); $marketWaypoints = array(); $selectedMarketWaypoint = ''; if (! is_string( $token ) || trim( $token ) === '' ) { $envToken = getenv( 'SPACETRADERS_TOKEN' ); if (is_string( $envToken ) && trim( $envToken ) !== '' ) { $token = trim( $envToken ); $storage->setAgentToken( $token ); } } if (! is_string( $token ) || trim( $token ) === '' ) { $tokenError = 'No token found. Set one in config.php or SPACETRADERS_TOKEN.'; } if (! isset( $tokenError ) ) { $client = new SpacetradersApi( trim( $token ), $config['api_base_url'], (int) $config['api_timeout'], $storage, (int) $config['cache_ttl'] ); } try { if (! isset( $tokenError ) ) { $agentResponse = $client->getMyAgent(); $shipsResponse = $client->listMyShips(); $contractsResponse = $client->listMyContracts(); $agent = $agentResponse['data'] ?? $agentResponse; $ships = $shipsResponse['data'] ?? $shipsResponse; $contracts = $contractsResponse['data'] ?? $contractsResponse; $miningShips = filterMiningShips( $ships ); $activeContracts = array_values( array_filter( (array) $contracts, static function ( array $contract ): bool { return (bool) ( $contract['accepted'] ?? false ) && ! (bool) ( $contract['fulfilled'] ?? false ); } ) ); $currentSystemSymbol = ''; if (! empty( $miningShips ) && isset( $miningShips[0]['nav']['systemSymbol'] ) ) { $currentSystemSymbol = (string) $miningShips[0]['nav']['systemSymbol']; } elseif (! empty( $ships ) && isset( $ships[0]['nav']['systemSymbol'] ) ) { $currentSystemSymbol = (string) $ships[0]['nav']['systemSymbol']; } elseif (isset( $agent['headquarters'] ) && is_string( $agent['headquarters'] ) ) { $hqParts = explode( '-', $agent['headquarters'] ); if (count( $hqParts ) >= 2 ) { $currentSystemSymbol = $hqParts[0] . '-' . $hqParts[1]; } } if ($currentSystemSymbol !== '' ) { $page = 1; $total = 0; $waypoints = array(); do { $waypointsResponse = $client->listWaypoints( $currentSystemSymbol, array( 'page' => $page, 'limit' => 20, ) ); $pageData = $waypointsResponse['data'] ?? array(); if (! is_array( $pageData ) || empty( $pageData ) ) { break; } $waypoints = array_merge( $waypoints, $pageData ); $total = (int) ( $waypointsResponse['meta']['total'] ?? count( $waypoints ) ); $page++; } while (count( $waypoints ) < $total); foreach ( $waypoints as $waypoint ) { foreach ( (array) ( $waypoint['traits'] ?? array() ) as $trait ) { if ((string) ( $trait['symbol'] ?? '' ) === 'MARKETPLACE' ) { $marketWaypoints[] = (string) ( $waypoint['symbol'] ?? '' ); break; } } } } $selectedMarketWaypoint = isset( $_POST['market_waypoint'] ) ? trim( (string) $_POST['market_waypoint'] ) : ( $marketWaypoints[0] ?? '' ); if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_POST['fleet_action'] ) ) { $fleetAction = (string) $_POST['fleet_action']; $successCount = 0; foreach ( $miningShips as $fleetShip ) { $shipSymbol = (string) ( $fleetShip['symbol'] ?? '' ); if ($shipSymbol === '' ) { continue; } try { $shipResponse = $client->getShip( $shipSymbol ); $shipData = $shipResponse['data'] ?? array(); $shipStatus = (string) ( $shipData['nav']['status'] ?? '' ); $waypointSymbol = (string) ( $shipData['nav']['waypointSymbol'] ?? '' ); if ($fleetAction === 'excavate_all' ) { if ($shipStatus === 'IN_TRANSIT' ) { $actionResults[] = $shipSymbol . ': skipped (in transit).'; continue; } if ($shipStatus === 'DOCKED' ) { $client->orbitShip( $shipSymbol ); } $client->extractResources( $shipSymbol ); $actionResults[] = $shipSymbol . ': extracting.'; $successCount++; } elseif ($fleetAction === 'dock_refuel_all' ) { if ($shipStatus === 'IN_TRANSIT' ) { $actionResults[] = $shipSymbol . ': skipped (in transit).'; continue; } if ($shipStatus !== 'DOCKED' ) { $client->dockShip( $shipSymbol ); } $client->refuelShip( $shipSymbol ); $actionResults[] = $shipSymbol . ': docked/refueled.'; $successCount++; } elseif ($fleetAction === 'move_and_sell_all' ) { if ($selectedMarketWaypoint === '' ) { $actionResults[] = $shipSymbol . ': no market waypoint selected.'; continue; } if ($shipStatus === 'IN_TRANSIT' ) { $actionResults[] = $shipSymbol . ': already in transit.'; continue; } if ($waypointSymbol !== $selectedMarketWaypoint ) { if ($shipStatus === 'DOCKED' ) { $client->orbitShip( $shipSymbol ); } $client->navigateShip( $shipSymbol, $selectedMarketWaypoint ); $actionResults[] = $shipSymbol . ': navigating to ' . $selectedMarketWaypoint . '.'; $successCount++; continue; } if ($shipStatus !== 'DOCKED' ) { $client->dockShip( $shipSymbol ); } $inventory = (array) ( $shipData['cargo']['inventory'] ?? array() ); $soldItems = 0; foreach ( $inventory as $item ) { $tradeSymbol = (string) ( $item['symbol'] ?? '' ); $units = (int) ( $item['units'] ?? 0 ); if ($tradeSymbol === '' || $units <= 0 ) { continue; } try { $client->sellCargo( $shipSymbol, $tradeSymbol, $units ); $soldItems++; } catch (SpacetradersApiException $e) { // Ignore individual sell failures and continue. } } $actionResults[] = $shipSymbol . ': sold ' . $soldItems . ' cargo item type(s).'; $successCount++; } elseif ($fleetAction === 'sell_cargo_here_all' ) { if ($shipStatus === 'IN_TRANSIT' ) { $actionResults[] = $shipSymbol . ': skipped (in transit).'; continue; } if ($shipStatus !== 'DOCKED' ) { $client->dockShip( $shipSymbol ); } $inventory = (array) ( $shipData['cargo']['inventory'] ?? array() ); $soldItems = 0; foreach ( $inventory as $item ) { $tradeSymbol = (string) ( $item['symbol'] ?? '' ); $units = (int) ( $item['units'] ?? 0 ); if ($tradeSymbol === '' || $units <= 0 ) { continue; } try { $client->sellCargo( $shipSymbol, $tradeSymbol, $units ); $soldItems++; } catch (SpacetradersApiException $e) { // Continue selling other items. } } $actionResults[] = $shipSymbol . ': sold ' . $soldItems . ' cargo item type(s) at current waypoint.'; $successCount++; } elseif ($fleetAction === 'jettison_cargo_all' ) { if ($shipStatus === 'IN_TRANSIT' ) { $actionResults[] = $shipSymbol . ': skipped (in transit).'; continue; } $inventory = (array) ( $shipData['cargo']['inventory'] ?? array() ); $jettisonedItems = 0; foreach ( $inventory as $item ) { $tradeSymbol = (string) ( $item['symbol'] ?? '' ); $units = (int) ( $item['units'] ?? 0 ); if ($tradeSymbol === '' || $units <= 0 ) { continue; } try { $client->jettisonCargo( $shipSymbol, $tradeSymbol, $units ); $jettisonedItems++; } catch (SpacetradersApiException $e) { // Continue jettisoning other items. } } $actionResults[] = $shipSymbol . ': jettisoned ' . $jettisonedItems . ' cargo item type(s).'; $successCount++; } } catch (SpacetradersApiException $e) { $actionResults[] = $shipSymbol . ': ' . $e->getMessage(); } } if ($successCount > 0 ) { $storage->clearAllCache(); } $statusMessage = 'Action complete for ' . $successCount . ' ship(s).'; $shipsResponse = $client->listMyShips(); $contractsResponse = $client->listMyContracts(); $ships = $shipsResponse['data'] ?? $shipsResponse; $contracts = $contractsResponse['data'] ?? $contractsResponse; $miningShips = filterMiningShips( $ships ); $activeContracts = array_values( array_filter( (array) $contracts, static function ( array $contract ): bool { return (bool) ( $contract['accepted'] ?? false ) && ! (bool) ( $contract['fulfilled'] ?? false ); } ) ); } if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_POST['ship_action'] ) && in_array( (string) $_POST['ship_action'], array( 'sell_ship_cargo', 'jettison_ship_cargo' ), true ) && isset( $_POST['ship_symbol'] )) { $shipAction = (string) $_POST['ship_action']; $sellShipSymbol = trim( (string) $_POST['ship_symbol'] ); if ($sellShipSymbol !== '' ) { try { $shipResponse = $client->getShip( $sellShipSymbol ); $shipData = $shipResponse['data'] ?? array(); $shipStatus = (string) ( $shipData['nav']['status'] ?? '' ); if ($shipStatus === 'IN_TRANSIT' ) { throw new SpacetradersApiException( 'Ship is in transit and cargo action is unavailable right now.' ); } if ($shipAction === 'sell_ship_cargo' && $shipStatus !== 'DOCKED' ) { $client->dockShip( $sellShipSymbol ); } $inventory = (array) ( $shipData['cargo']['inventory'] ?? array() ); $handledItems = 0; foreach ( $inventory as $item ) { $tradeSymbol = (string) ( $item['symbol'] ?? '' ); $units = (int) ( $item['units'] ?? 0 ); if ($tradeSymbol === '' || $units <= 0 ) { continue; } try { if ($shipAction === 'sell_ship_cargo' ) { $client->sellCargo( $sellShipSymbol, $tradeSymbol, $units ); } else { $client->jettisonCargo( $sellShipSymbol, $tradeSymbol, $units ); } $handledItems++; } catch (SpacetradersApiException $e) { // Continue processing other items. } } if ($shipAction === 'sell_ship_cargo' ) { $statusMessage = $sellShipSymbol . ': sold ' . $handledItems . ' cargo item type(s).'; } else { $statusMessage = $sellShipSymbol . ': jettisoned ' . $handledItems . ' cargo item type(s).'; } $storage->clearAllCache(); $shipsResponse = $client->listMyShips(); $ships = $shipsResponse['data'] ?? $shipsResponse; $miningShips = filterMiningShips( $ships ); } catch (SpacetradersApiException $e) { $errorMessage = $sellShipSymbol . ': ' . $e->getMessage(); } } } } } catch (SpacetradersApiException $e) { $errorMessage = $e->getMessage(); } ?> Spacetraders - Mining Fleet

Spacetraders - Mining Fleet

Global Controls

Action Results

Mining Ships:

Active Contracts

No active contracts.

Contract:

Type:

Deadline:

Payment: +

Deliveries:

  • : / to
No mining ships found (role: EXCAVATOR).

Name:

Status:

Waypoint:

Fuel: /

Cargo: /

Cargo Contents:

  • :