from nullptr.command_line import CommandLine from nullptr.store import Store from nullptr.analyzer import Analyzer import argparse from nullptr.models import * 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_file='data/store.npt'): self.store = Store(store_file) 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) api = Api(self.store, agent) faction = input('faction: ') api.register(faction.upper().strip()) self.store.flush() 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 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.centcom.init_mission(self.ship, 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 contract = self.active_contract() delivery = contract.unfinished_delivery() if delivery is None: raise CommandError('no delivery') resource = delivery['trade_symbol'] destination = delivery['destination'] self.centcom.init_mission(self.ship, '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) self.print_mission() def do_chaul(self): if not self.has_ship(): return if len(ship.cargo) > 0: raise CommandError('please dump cargo first') 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_markets(resource, 'buy', destination) if len(m) == 0: m = self.analyzer.find_closest_markets(resource, 'exchange', destination) if len(m) == 0: print('no market found') return _, m, _, _ = m[0] site = self.store.get(Waypoint, m.symbol) self.centcom.init_mission(self.ship, 'haul') 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) self.print_mission() def do_cprobe(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_markets(resource, 'buy,exchange', destination) if len(m) is None: print('no market found') return markets = [ mkt[1] for mkt in m] markets = self.analyzer.solve_tsp(markets) self.centcom.init_mission(self.ship, 'probe') self.centcom.set_mission_param(self.ship, 'hops', markets) self.print_mission() def do_travel(self, dest): dest = self.resolve('Waypoint', dest) self.centcom.init_mission(self.ship, 'travel') self.centcom.set_mission_param(self.ship, 'dest', dest) self.print_mission() def do_register(self, faction): self.api.register(faction.upper()) pprint(self.api.agent) 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, resource): if not self.has_ship(): return location = self.ship.location resource = resource.upper() print('Found markets:') for typ, m, d, plen in self.analyzer.find_closest_markets(resource, 'buy,exchange',location): price = '?' if resource in m.prices: price = m.prices[resource]['buy'] print(m, typ[0], f'{plen-1:3} hops {price}') 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 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.system.sector.symbol 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)