from nullptr.store import Store from nullptr.models.ship import Ship from nullptr.missions import create_mission, get_mission_class from random import choice from time import sleep from threading import Thread from nullptr.atlas_builder import AtlasBuilder class CentralCommandError(Exception): pass class CentralCommand: def __init__(self, store, api): self.missions = {} self.stopping = False self.store = store self.api = api self.atlas_builder = AtlasBuilder(store, api) self.update_missions() def get_ready_missions(self): result = [] for ship, mission in self.missions.items(): if mission.is_ready(): result.append(ship) return result def tick(self): missions = self.get_ready_missions() if len(missions) == 0: return False ship = choice(missions) mission = self.missions[ship] mission.step() return True def run_interactive(self): print('auto mode. hit enter to stop') t = Thread(target=self.wait_for_stop) t.daemon = True t.start() self.run() print('manual mode') def wait_for_stop(self): try: input() except EOFError: pass self.stopping = True print('stopping...') def run(self): self.update_missions() while not self.stopping: did_step = True request_counter = self.api.requests_sent while request_counter == self.api.requests_sent and did_step: did_step = self.tick() if request_counter == self.api.requests_sent: self.atlas_builder.do_work() else: pass # print('nowork') self.store.flush() sleep(0.5) self.stopping = False def stop(self): self.stopping = True def set_mission_param(self, ship, nm, val): if ship not in self.missions: print('set a mission for this ship first') return mission = self.missions[ship] params = mission.params() if not nm in params: print(f'{nm} is not a valid param') return param = params[nm] try: parsed_val = param.parse(val, self.store) except ValueError as e: raise MissionError(e) return ship.set_mission_state(nm, parsed_val) def update_missions(self): for s in self.store.all(Ship): if s.mission is None: if s in self.missions: self.stop_mission(s) elif s not in self.missions: self.start_mission(s) if s in self.missions: m = self.missions[s] m.next_step = max(s.cooldown, s.arrival) def init_mission(self, s, mtyp): if mtyp == 'none': s.mission_state = {} s.mission_status = None s.mission = None return try: mclass = get_mission_class(mtyp) except ValueError: raise CentralCommandError('no such mission') s.mission = mtyp s.mission_status = 'init' s.mission_state = {k: v.default for k,v in mclass.params().items()} self.start_mission(s) def start_mission(self, s): mtype = s.mission m = create_mission(mtype, s, self.store, self.api) self.missions[s] = m return m def stop_mission(self, s): if s in self.missions: del self.missions[s]