0ptr/nullptr/central_command.py
2023-07-18 12:44:53 +02:00

125 lines
3.1 KiB
Python

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]