0ptr/nullptr/commander.py
2023-06-23 13:32:08 +02:00

386 lines
11 KiB
Python

from nullptr.command_line import CommandLine
from nullptr.store import Store
from nullptr.analyzer import Analyzer
import argparse
from nullptr.models.agent import Agent
from nullptr.models.system import System
from nullptr.models.waypoint import Waypoint
from nullptr.models.marketplace import Marketplace
from nullptr.models.jumpgate import Jumpgate
from nullptr.api import Api
from .util import *
from time import sleep, time
from threading import Thread
from nullptr.atlas_builder import AtlasBuilder
from nullptr.central_command import CentralCommand
class CommandError(Exception):
pass
class Commander(CommandLine):
def __init__(self, store_dir='data'):
self.store_dir = store_dir
self.store = Store(store_dir)
self.store.load()
self.agent = self.select_agent()
self.api = Api(self.store, self.agent)
self.atlas_builder = AtlasBuilder(self.store, self.api)
self.centcom = CentralCommand(self.store, self.api)
self.analyzer = Analyzer(self.store)
self.ship = None
self.stop_auto= False
super().__init__()
def prompt(self):
if self.ship:
return f'{self.ship.symbol}> '
else:
return '> '
def has_ship(self):
if self.ship is not None:
return True
else:
print('set a ship')
def ask_obj(self, typ, prompt):
obj = None
while obj is None:
symbol = input(prompt).strip()
obj = self.store.get(typ, symbol.upper())
if obj is None:
print('not found')
return obj
def select_agent(self):
agents = self.store.all(Agent)
agent = next(agents, None)
if agent is None:
symbol = input('agent name: ')
agent = self.store.get(Agent, symbol, create=True)
return agent
def resolve(self, typ, arg):
arg = arg.upper()
matches = [c for c in self.store.all(typ) if c.symbol.startswith(arg)]
if len(matches) == 1:
return matches[0]
elif len(matches) > 1:
raise CommandError('multiple matches')
else:
raise CommandError('not found')
def after_cmd(self):
self.store.flush()
def do_info(self, arg=''):
if arg.startswith('r'):
self.api.info()
pprint(self.agent, 100)
def do_auto(self):
self.centcom.run_interactive()
def set_mission(self, arg=''):
if arg == 'none':
arg = None
self.ship.mission = arg
self.ship.mission_status = 'init'
if 'traject' in self.ship.mission_state:
del self.ship.mission_state['traject']
self.centcom.start_mission(self.ship)
def print_mission(self):
print(f'mission: {self.ship.mission} ({self.ship.mission_status})')
pprint(self.ship.mission_state)
def do_mission(self, arg=''):
if not self.has_ship(): return
if arg:
self.set_mission(arg)
self.print_mission()
def do_mreset(self):
if not self.has_ship(): return
self.ship.mission_state = {}
def do_mset(self, nm, val):
if not self.has_ship(): return
self.centcom.set_mission_param(self.ship, nm, val)
def active_contract(self):
for c in self.store.all('Contract'):
if c.accepted and not c.fulfilled: return c
raise CommandError('no active contract')
def do_cmine(self):
if not self.has_ship(): return
site = self.ship.location_str
contract = self.active_contract()
delivery = contract.unfinished_delivery()
if delivery is None:
raise CommandError('no delivery')
resource = delivery['trade_symbol']
destination = delivery['destination']
self.set_mission('mine')
self.centcom.set_mission_param(self.ship, 'site', site)
self.centcom.set_mission_param(self.ship, 'resource', resource)
self.centcom.set_mission_param(self.ship, 'dest', destination)
self.centcom.set_mission_param(self.ship, 'contract', contract.symbol)
self.print_mission()
def do_chaul(self):
if not self.has_ship(): return
contract = self.active_contract()
delivery = contract.unfinished_delivery()
if delivery is None:
raise CommandError('no delivery')
resource = delivery['trade_symbol']
destination = delivery['destination']
m = self.analyzer.find_closest_market(resource, 'buy', destination)
if m is None:
m = self.analyzer.find_closest_market(resource, 'exchange', destination)
if m is None:
print('no market found')
return
site = self.store.get(Waypoint, m.symbol)
self.set_mission('haul')
self.centcom.set_mission_param(self.ship, 'site', site.symbol)
self.centcom.set_mission_param(self.ship, 'resource', resource)
self.centcom.set_mission_param(self.ship, 'dest', destination)
self.centcom.set_mission_param(self.ship, 'contract', contract.symbol)
self.print_mission()
def do_travel(self, dest):
dest = self.resolve('Waypoint', dest)
self.set_mission('travel')
self.centcom.set_mission_param(self.ship, 'dest', dest.symbol)
self.print_mission()
def do_register(self, faction):
self.api.register(faction.upper())
site = self.ship.location_str
contract = self.active_contract()
self.do_mission('mine')
self.centcom.set_mission_param(self.ship, 'site', site)
self.centcom.set_mission_param(self.ship, 'contract', contract)
def do_universe(self, page=1):
self.atlas_builder.run(page)
def do_systems(self, page=1):
r = self.api.list_systems(int(page))
pprint(self.api.last_meta)
def do_stats(self):
total = 0
for t in self.store.data:
num = len(self.store.data[t])
nam = t.__name__
total += num
print(f'{num:5d} {nam}')
print(f'{total:5d} total')
def do_waypoints(self, system_str=''):
if system_str == '':
if not self.has_ship(): return
system = self.ship.location().system()
else:
system = self.store.get(System, system_str)
r = self.store.all_members(system, 'Waypoint')
for w in r:
traits = []
if 'MARKETPLACE' in w.traits:
traits.append('MARKET')
if 'SHIPYARD' in w.traits:
traits.append('SHIPYARD')
if w.type == 'JUMP_GATE':
traits.append('JUMP')
if w.type == 'ASTEROID_FIELD':
traits.append('ASTROIDS')
print(w.symbol.split('-')[2], ', '.join(traits))
def do_wp(self, s=''):
self.do_waypoints(s)
def do_marketplace(self, waypoint_str):
waypoint = self.store.get(Waypoint, waypoint_str.upper())
r = self.api.marketplace(waypoint)
def do_jumps(self, waypoint_str=None):
if waypoint_str is None:
if not self.has_ship(): return
waypoint = self.ship.location()
else:
waypoint = self.store.get(Waypoint, waypoint_str.upper())
r = self.api.jumps(waypoint)
pprint(r)
def do_query(self):
if not self.has_ship(): return
location = self.ship.location()
resource = input('what resource?').upper()
print('Found markets:')
for typ, m, plen in self.analyzer.find_closest_markets(resource, 'buy,exchange',location):
print(m, typ[0], f'{plen-1} hops')
def do_path(self):
orig = self.ask_obj(System, 'from: ')
dest = self.ask_obj(System, 'to: ')
# orig = self.store.get(System, 'X1-KS52')
# dest = self.store.get(System, 'X1-DA90')
path = self.analyzer.find_path(orig, dest)
pprint(path)
def do_ships(self, arg=''):
if arg.startswith('r'):
r = self.api.list_ships()
else:
r = list(self.store.all('Ship'))
pprint(r)
def do_contracts(self, arg=''):
if arg.startswith('r'):
r = self.api.list_contracts()
else:
r = list(self.store.all('Contract'))
pprint(r)
def do_deliver(self):
if not self.has_ship(): return
site = self.ship.location_str
contract = self.active_contract()
delivery = contract.unfinished_delivery()
if delivery is None:
raise CommandError('no delivery')
resource = delivery['trade_symbol']
self.api.deliver(self.ship, resource, contract)
pprint(contract)
def do_fulfill(self):
contract = self.active_contract()
self.api.fulfill(contract)
def do_ship(self, arg=''):
if arg != '':
symbol = f'{self.agent.symbol}-{arg}'
ship = self.store.get('Ship', symbol)
if ship is None:
print('not found')
return
else:
self.ship = ship
pprint(self.ship)
def do_pp(self):
pprint(self.api.last_result)
def do_go(self, arg):
if not self.has_ship(): return
system = self.ship.location().system()
symbol = f'{system}-{arg}'
dest = self.resolve('Waypoint', symbol)
self.api.navigate(self.ship, dest)
pprint(self.ship)
def do_dock(self):
if not self.has_ship(): return
self.api.dock(self.ship)
pprint(self.ship)
def do_orbit(self):
if not self.has_ship(): return
self.api.orbit(self.ship)
pprint(self.ship)
def do_negotiate(self):
if not self.has_ship(): return
r = self.api.negotiate(self.ship)
pprint(r)
def do_refuel(self):
if not self.has_ship(): return
r = self.api.refuel(self.ship)
pprint(self.ship)
def do_accept(self, c):
contract = self.resolve('Contract', c)
r = self.api.accept_contract(contract)
pprint(r)
def do_market(self, arg=''):
if arg == '':
if not self.has_ship(): return
waypoint = self.ship.location()
else:
waypoint = self.resolve('Waypoint', arg)
r = self.api.marketplace(waypoint)
pprint(r)
def do_cargo(self):
if not self.has_ship(): return
for c, units in self.ship.cargo.items():
print(f'{units:4d} {c}')
def do_buy(self, resource, amt=None):
if not self.has_ship(): return
if amt is None:
amt = self.ship.cargo_capacity - self.ship.cargo_units
self.api.buy(self.ship, resource.upper(), amt)
self.do_cargo()
def do_sell(self, resource):
if not self.has_ship(): return
self.api.sell(self.ship, resource.upper())
self.do_cargo()
def do_dump(self, resource):
if not self.has_ship(): return
self.api.jettison(self.ship, resource.upper())
self.do_cargo()
def do_shipyard(self):
if not self.has_ship(): return
location = self.ship.location()
data = self.api.shipyard(location)
for s in must_get(data, 'ships'):
print(s['type'], s['purchasePrice'])
def do_jump(self, system_str):
if not self.has_ship(): return
if '-' not in system_str:
sector = self.ship.location_str.split('-')[0]
system_str = f'{sector}-{system_str}'
system = self.resolve('System', system_str)
self.api.jump(self.ship, system)
pprint(self.ship)
def do_purchase(self, ship_type):
if not self.has_ship(): return
location = self.ship.location()
ship_type = ship_type.upper()
if not ship_type.startswith('SHIP'):
ship_type = 'SHIP_' + ship_type
s = self.api.purchase(ship_type, location)
pprint(s)
def do_survey(self):
if not self.has_ship(): return
r = self.api.survey(self.ship)
pprint(r)
def do_surveys(self):
pprint(list(self.store.all('Survey')))
def do_extract(self, survey_str=''):
if not self.has_ship(): return
survey = None
if survey_str != '':
survey = self.resolve('Survey', survey_str)
result = self.api.extract(self.ship, survey)
symbol = mg(result,'extraction.yield.symbol')
units = mg(result,'extraction.yield.units')
print(units, symbol)