from nullptr.command_line import CommandLine from nullptr.store import Store from nullptr.analyzer import * from nullptr.context import Context 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.captain import Captain from nullptr.general import General import readline import os from copy import copy class CommandError(AppError): pass class Commander(CommandLine): def __init__(self, data_dir='data', auto=False): store_file = os.path.join(data_dir, 'store.npt') hist_file = os.path.join(data_dir, 'cmd.hst') self.cred_file = os.path.join(data_dir, 'creds.txt') self.hist_file = hist_file if os.path.isfile(hist_file): readline.read_history_file(hist_file) self.store = Store(store_file, True) self.c = Context(self.store) self.agent = self.select_agent() self.c.api = self.api = Api(self.c, self.agent) self.c.general = self.general = General(self.c) self.c.captain = self.captain = Captain(self.c) self.general.setup() self.captain.setup() self.api.info() self.ship = None self.stop_auto = False if auto: self.do_auto() super().__init__() ######## INFRA ######### def handle_eof(self): self.store.close() readline.write_history_file(self.hist_file) print("Goodbye!") def do_pp(self): pprint(self.api.last_result) def prompt(self): if self.ship: return f'{self.ship.symbol}> ' else: return '> ' def after_cmd(self): self.store.flush() def do_auto(self): self.captain.run_interactive() def do_log(self, level): ship = self.has_ship() ship._log_level = int(level) ######## Resolvers ######### 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 has_ship(self): if self.ship is not None: return self.ship else: raise CommandError('set a ship') def select_agent(self): agents = self.store.all(Agent) agent = next(agents, None) if agent is None: agent = self.agent_setup() 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(f'{arg} not found') def resolve_system(self, system_str): if type(system_str) == System: return system_str if system_str == '': ship = self.has_ship() system = ship.location.system else: system = self.store.get(System, system_str) return system def resolve_waypoint(self, w): if type(w) == Waypoint: return w if w == '': ship = self.has_ship() return ship.location p = w.split('-') if len(p) == 1: ship = self.has_ship() s = ship.location.system w = f'{s}-{w}' r = self.store.get(Waypoint, w) if r is None: raise CommandError(f'{w} not found') return r def resolve_ship(self, arg): symbol = f'{self.agent.symbol}-{arg}' ship = self.store.get('Ship', symbol) if ship is None: raise CommandError(f'ship {arg} not found') return ship ######## First run ######### def agent_setup(self): symbol = input('agent name: ') agent = self.store.get(Agent, symbol, create=True) self.agent = agent api = Api(self.c, agent) self.api = api faction = input('faction or token: ') if len(faction) > 50: self.agent.token = faction else: self.do_register(faction) print('=== agent:') print(agent) print('=== ships') self.do_ships('r') print('=== contracts') self.do_contracts('r') ship = self.store.get(Ship, symbol.upper() + '-2') print("=== catalog initial system") self.do_catalog(ship.location.system) self.do_stats() self.store.flush() return agent def do_token(self): print(self.agent.token) def do_register(self, faction): self.api.register(faction.upper()) with open(self.cred_file, 'w') as f: f.write(self.api.agent.symbol) f.write('\n') f.write(self.api.agent.token) pprint(self.api.agent) def do_reset(self, really): if really != 'yes': print('really? type: reset yes') self.api.list_ships() for s in self.store.all('Ship'): self.dump(s, 'all') self.captain.init_mission(s, 'none') ######## Fleet ######### def do_info(self, arg=''): if arg.startswith('r'): self.api.info() pprint(self.agent, 100) def do_ships(self, arg=''): if arg.startswith('r'): r = self.api.list_ships() else: r = sorted(list(self.store.all('Ship'))) pprint(r) def do_ship(self, arg=''): if arg != '': ship = self.resolve_ship(arg) self.ship = ship pprint(self.ship, 5) ######## Atlas ######### def do_systems(self, page=1): r = self.api.list_systems(int(page)) pprint(self.api.last_meta) def do_catalog(self, system_str=''): system = self.resolve_system(system_str) r = self.api.list_waypoints(system) for w in r: if 'MARKETPLACE' in w.traits: self.api.marketplace(w) if w.type == 'JUMP_GATE': self.api.jumps(w) if 'SHIPYARD' in w.traits: self.api.shipyard(w) def do_system(self, system_str): system = self.store.get(System, system_str) r = self.api.list_waypoints(system) pprint(r) def do_waypoints(self, grep=''): loc = None ship = self.has_ship() loc = ship.location system = loc.system print(f'=== waypoints in {system}') r = self.store.all_members(system, 'Waypoint') for w in r: wname = w.symbol.split('-')[2] traits = ", ".join(w.itraits()) typ = w.type[0] if typ not in ['F','J'] and len(traits) == 0: continue output = '' if loc: dist = loc.distance(w) output = f'{wname:4} {typ} {dist:6} {traits}' else: output = f'{wname:4} {typ} {traits}' if grep == '' or grep.lower() in output.lower(): print(output) def do_members(self): ship = self.has_ship() system = ship.location.system pprint(list(self.store.all_members(system))) def do_wp(self, grep=''): self.do_waypoints(grep) ######## Specials ######### def do_market(self, arg=''): waypoint = self.resolve_waypoint(arg) r = self.api.marketplace(waypoint) pprint(r, 3) def do_atlas(self, state=None): atlas = self.store.get(Atlas, 'ATLAS') if state is not None: atlas.enabled = True if state == 'on' else 'off' pprint(atlas, 5) def do_jumps(self, waypoint_str=None): if waypoint_str is None: ship = self.has_ship() waypoint = ship.location else: waypoint = self.store.get(Waypoint, waypoint_str.upper()) r = self.api.jumps(waypoint) pprint(r, 5) def do_shipyard(self, w=''): location = self.resolve_waypoint(w) if location is None: raise CommandError(f'waypoint {w} not found') sy = self.api.shipyard(location) pprint(sy, 5) ######## Commerce ######### def do_refuel(self, source='market'): ship = self.has_ship() from_cargo = source != 'market' r = self.api.refuel(ship, from_cargo=from_cargo) pprint(r) def do_cargo(self): ship = self.has_ship() print(f'== Cargo {ship.cargo_units}/{ship.cargo_capacity} ==') for c, units in ship.cargo.items(): print(f'{units:4d} {c}') def do_buy(self, resource, amt=None): ship = self.has_ship() if amt is None: amt = ship.cargo_capacity - ship.cargo_units self.api.buy(ship, resource.upper(), amt) self.do_cargo() def do_sell(self, resource, amt=None): ship = self.has_ship() self.api.sell(ship, resource.upper(), amt) self.do_cargo() def dump(self, ship, resource): if resource == 'all': for r in ship.cargo.keys(): self.api.jettison(ship, r) else: self.api.jettison(ship, resource.upper()) def do_dump(self, resource): ship = self.has_ship() self.dump(ship, resource) self.do_cargo() def do_transfer(self, resource, dship, amount=None): ship = self.has_ship() resource = resource.upper() avail = ship.get_cargo(resource) if amount is None: amount = avail amount = int(amount) if avail < amount: raise CommandError('resource not in cargo') dship = self.resolve_ship(dship) self.api.transfer(ship, dship, resource, amount) def do_purchase(self, ship_type): ship = self.has_ship() location = 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) ######## Mining ######### def do_siphon(self): ship = self.has_ship() data = self.api.siphon(ship) def do_survey(self): ship = self.has_ship() r = self.api.survey(ship) pprint(r) def do_surveys(self): pprint(list(self.store.all('Survey'))) def do_extract(self, survey_str=''): ship = self.has_ship() survey = None if survey_str != '': survey = self.resolve('Survey', survey_str) result = self.api.extract(ship, survey) symbol = mg(result,'extraction.yield.symbol') units = mg(result,'extraction.yield.units') print(units, symbol) ######## Missions ######### def print_mission(self): print(f'mission: {self.ship.mission} ({self.ship.mission_status})') pprint(self.ship.mission_state) def do_role(self, role): roles = [None, 'trader', 'probe', 'siphon', 'hauler', 'surveyor', 'miner'] ship = self.has_ship() if role == 'none': role = None if role not in roles: print(f'role {role} not found. Choose from {roles}') return ship.role = role def do_mission(self, arg=''): ship = self.has_ship() if arg: self.captain.init_mission(ship, arg) self.print_mission() def do_mrestart(self, status='init'): ship = self.has_ship() self.captain.restart_mission(ship, status) self.print_mission() def do_mstep(self): ship = self.has_ship() self.captain.single_step(ship) self.print_mission() def do_mreset(self): ship = self.has_ship() ship.mission_state = {} def do_mset(self, nm, val): ship = self.has_ship() self.captain.set_mission_param(ship, nm, val) def do_crew(self, arg): ship = self.has_ship() crew = self.resolve('Crew', arg) ship.crew = crew pprint(ship) def do_phase(self, phase): self.agent.phase = phase ######## Crews ######### def do_create_crews(self): crews = self.captain.create_default_crews() for c in crews: print(f'{c.symbol:15s} {c.site}') ######## Contracts ######### 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_contracts(self, arg=''): if arg.startswith('r'): r = self.api.list_contracts() else: r = list(self.store.all('Contract')) pprint(r) def do_negotiate(self): ship = self.has_ship() r = self.api.negotiate(ship) pprint(r) def do_accept(self, c): contract = self.resolve('Contract', c) r = self.api.accept_contract(contract) pprint(r) def do_deliver(self): ship = self.has_ship() site = 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(ship, resource, contract) pprint(contract) def do_fulfill(self): contract = self.active_contract() self.api.fulfill(contract) ######## Travel ######### def do_travel(self, dest): ship = self.has_ship() dest = self.resolve('Waypoint', dest) self.captain.init_mission(ship, 'travel') self.captain.set_mission_param(ship, 'dest', dest) self.print_mission() def do_go(self, arg): ship = self.has_ship() system = ship.location.system symbol = f'{system}-{arg}' dest = self.resolve('Waypoint', symbol) self.api.navigate(ship, dest) pprint(ship) def do_dock(self): ship = self.has_ship() self.api.dock(ship) pprint(ship) def do_orbit(self): ship = self.has_ship() self.api.orbit(ship) pprint(ship) def do_speed(self, speed): ship = self.has_ship() speed = speed.upper() speeds = ['DRIFT', 'STEALTH','CRUISE','BURN'] if speed not in speeds: print('please choose from:', speeds) self.api.flight_mode(ship, speed) def do_jump(self, waypoint_str): ship = self.has_ship() w = self.resolve('Waypoint', waypoint_str) self.api.jump(ship, w) pprint(ship) ######## Analysis ######### def do_server(self): data = self.api.status() pprint(data) def do_highscore(self): data = self.api.status() leaders = mg(data, 'leaderboards.mostCredits') for l in leaders: a = mg(l,'agentSymbol') c = mg(l, 'credits') print(f'{a:15s} {c}') 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_defrag(self): self.store.defrag() def do_obj(self, oid): if not '.' in oid: print('Usage: obj SYMBOL.ext') return symbol, ext = oid.split('.') symbol = symbol.upper() if not ext in self.store.extensions: raise CommandError('unknown extension') typ = self.store.extensions[ext] obj = self.store.get(typ, symbol) if obj is None: raise CommandError('object not found') pprint(obj.__getstate__()) print('=== store ===') h = self.store.get_header(obj) if h: pprint(h, 3) else: print('Not stored') print('Dirty: ', obj in self.store.dirty_objects) def do_query(self, resource): ship = self.has_ship() location = ship.location resource = resource.upper() print('Found markets:') for typ, m, d, plen in find_closest_markets(self.c, 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_findtrade(self): ship = self.has_ship() system = ship.location.system t = find_trade(self.c, system) pprint(t) def do_prices(self, resource=None): ship = self.has_ship() system = ship.location.system prices = prices(self.c, system) if resource is not None: prices = {resource: prices[resource.upper()]} for res, p in prices.items(): print('==' + res) for m in p: print(f"{m['wp'].symbol:12s} {m['category']} {m['volume']:5d} {m['buy']:5d} {m['sell']:5d}") def do_path(self, waypoint_str): ship = self.has_ship() w = self.resolve('Waypoint', waypoint_str) p = find_nav_path(self.c, ship.location, w, ship.fuel_capacity) pprint(p) def do_list(self, klass): ship = self.has_ship() for o in self.store.all_members(klass, ship.location.system): print(o)