mission step priorities, fixed the store again

This commit is contained in:
Richard 2024-01-27 15:05:33 +01:00
parent f913d23c06
commit 5d47efdbda
10 changed files with 78 additions and 36 deletions

View File

@ -167,12 +167,17 @@ class Analyzer:
return prices return prices
def find_trade(self, system): def find_trade(self, system):
max_traders = 3
prices = self.prices(system) prices = self.prices(system)
occupied_routes = set() occupied_routes = dict()
for s in self.store.all('Ship'): for s in self.store.all('Ship'):
if s.mission != 'trade': if s.mission != 'trade':
continue continue
occupied_routes.add((s.mission_state['site'], s.mission_state['dest'])) k = (s.mission_state['site'], s.mission_state['dest'])
if k in occupied_routes:
occupied_routes[k] += 1
else:
occupied_routes[k] = 1
best = None best = None
for resource, markets in prices.items(): for resource, markets in prices.items():
source = sorted(markets, key=lambda x: x['buy'])[0] source = sorted(markets, key=lambda x: x['buy'])[0]
@ -180,7 +185,8 @@ class Analyzer:
swp = source['wp'] swp = source['wp']
dwp = dest['wp'] dwp = dest['wp']
margin = dest['sell'] -source['buy'] margin = dest['sell'] -source['buy']
if (swp.symbol,dwp.symbol) in occupied_routes: k = (swp.symbol,dwp.symbol)
if k in occupied_routes and occupied_routes[k] > max_traders:
continue continue
dist = swp.distance(dwp) dist = swp.distance(dwp)
dist = max(dist, 0.0001) dist = max(dist, 0.0001)

View File

@ -122,6 +122,9 @@ class Api:
######## Fleet ######### ######## Fleet #########
def list_ships(self): def list_ships(self):
data = self.request('get', 'my/ships') data = self.request('get', 'my/ships')
tp = total_pages(self.last_meta)
for p in range(1, tp):
data += self.request('get', 'my/ships', params={'page': p+1})
return self.store.update_list(Ship, data) return self.store.update_list(Ship, data)
def refuel(self, ship, from_cargo=False): def refuel(self, ship, from_cargo=False):
@ -244,8 +247,8 @@ class Api:
else: else:
raise e raise e
ship.update(data) ship.update(data)
amt = mg(data, 'extraction.yield.units') amt = sg(data, 'extraction.yield.units', 0)
rec = mg(data, 'extraction.yield.symbol') rec = sg(data, 'extraction.yield.symbol', 'nothing')
ship.log(f"extracted {amt} {rec}") ship.log(f"extracted {amt} {rec}")
ship.location.extracted += amt ship.location.extracted += amt
return data return data

View File

@ -23,9 +23,14 @@ class CentralCommand:
def get_ready_missions(self): def get_ready_missions(self):
result = [] result = []
prio = 1
for ship, mission in self.missions.items(): for ship, mission in self.missions.items():
if mission.is_ready(): p = mission.is_ready()
if p == prio:
result.append(ship) result.append(ship)
elif p > prio:
prio = p
result = [ship]
return result return result
def single_step(self, ship): def single_step(self, ship):

View File

@ -24,7 +24,7 @@ class Commander(CommandLine):
self.hist_file = hist_file self.hist_file = hist_file
if os.path.isfile(hist_file): if os.path.isfile(hist_file):
readline.read_history_file(hist_file) readline.read_history_file(hist_file)
self.store = Store(store_file, False) self.store = Store(store_file, True)
self.agent = self.select_agent() self.agent = self.select_agent()
self.api = Api(self.store, self.agent) self.api = Api(self.store, self.agent)
self.centcom = CentralCommand(self.store, self.api) self.centcom = CentralCommand(self.store, self.api)
@ -141,6 +141,7 @@ class Commander(CommandLine):
print(agent) print(agent)
print('=== ships') print('=== ships')
self.do_ships('r') self.do_ships('r')
self.do_create_crews()
print('=== contracts') print('=== contracts')
self.do_contracts('r') self.do_contracts('r')
ship = self.store.get(Ship, symbol.upper() + '-2') ship = self.store.get(Ship, symbol.upper() + '-2')
@ -161,6 +162,14 @@ class Commander(CommandLine):
f.write(self.api.agent.token) f.write(self.api.agent.token)
pprint(self.api.agent) 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.centcom.init_mission(s, 'none')
######## Fleet ######### ######## Fleet #########
def do_info(self, arg=''): def do_info(self, arg=''):
if arg.startswith('r'): if arg.startswith('r'):
@ -288,10 +297,17 @@ class Commander(CommandLine):
ship = self.has_ship() ship = self.has_ship()
self.api.sell(ship, resource.upper(), amt) self.api.sell(ship, resource.upper(), amt)
self.do_cargo() 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): def do_dump(self, resource):
ship = self.has_ship() ship = self.has_ship()
self.api.jettison(ship, resource.upper()) self.dump(ship, resource)
self.do_cargo() self.do_cargo()
def do_transfer(self, resource, dship, amount=None): def do_transfer(self, resource, dship, amount=None):
@ -501,11 +517,11 @@ class Commander(CommandLine):
symbol, ext = oid.split('.') symbol, ext = oid.split('.')
symbol = symbol.upper() symbol = symbol.upper()
if not ext in self.store.extensions: if not ext in self.store.extensions:
print('unknown extension') raise CommandError('unknown extension')
typ = self.store.extensions[ext] typ = self.store.extensions[ext]
obj = self.store.get(typ, symbol) obj = self.store.get(typ, symbol)
if obj is None: if obj is None:
print('object not found') raise CommandError('object not found')
pprint(obj.__getstate__()) pprint(obj.__getstate__())
print('=== store ===') print('=== store ===')
h = self.store.get_header(obj) h = self.store.get_header(obj)

View File

@ -11,6 +11,7 @@ from functools import partial
import logging import logging
from nullptr.util import * from nullptr.util import *
class MissionError(Exception): class MissionError(Exception):
pass pass
@ -113,23 +114,24 @@ class Mission:
def step_done(self): def step_done(self):
self.ship.log(f'mission {type(self).__name__} finished with balance {self.balance()}', 3) self.ship.log(f'mission {type(self).__name__} finished with balance {self.balance()}', 3)
def is_waiting(self): def get_prio(self):
if self.next_step > time() or self.ship.cooldown > time() or self.ship.arrival > time(): if self.next_step > time() or self.ship.cooldown > time() or self.ship.arrival > time():
return True return 0
if self.wait_for is not None: if self.wait_for is not None:
if self.wait_for(): p = int(self.wait_for())
if p > 0:
self.wait_for = None self.wait_for = None
return False return p
else: return 3
return True
return False
def is_finished(self): def is_finished(self):
return self.status() in ['done','error'] return self.status() in ['done','error']
def is_ready(self): def is_ready(self):
return not self.is_waiting() and not self.is_finished() if self.is_finished():
return 0
return self.get_prio()
def step(self): def step(self):
steps = self.steps() steps = self.steps()
@ -147,7 +149,8 @@ class Mission:
try: try:
result = handler() result = handler()
except Exception as e: except Exception as e:
logging.error(e, exc_info=True) self.ship.log(fmtex(e))
self.ship.log(self.api.last_result)
self.status('error') self.status('error')
return return
if type(next_step) == str: if type(next_step) == str:

View File

@ -17,14 +17,16 @@ class HaulMission(BaseMission):
continue continue
if s.mission_status != 'load': if s.mission_status != 'load':
continue continue
return False return 0
return True return 5
def step_load(self): def step_load(self):
pass pass
def cargo_full(self): def cargo_full(self):
return self.ship.cargo_space() == 0 if self.ship.cargo_space() == 0:
return 5
return 0
@classmethod @classmethod
def params(cls): def params(cls):

View File

@ -16,6 +16,9 @@ class MarketEntry:
activity: int activity: int
history: List[Tuple[int, int, int, int, int, int]] = [] history: List[Tuple[int, int, int, int, int, int]] = []
def f(self, detail=1):
return f'b: {self.buy} s:{self.sell} hist: {len(self.history)}'
def add(self, buy, sell, volume, supply, activity): def add(self, buy, sell, volume, supply, activity):
self.buy = buy self.buy = buy
self.sell = sell self.sell = sell

View File

@ -26,6 +26,9 @@ class Ship(Base):
self._log_level = 5 self._log_level = 5
def log(self, m, l=3): def log(self, m, l=3):
if m is None: return
if type(m) != str:
m = pretty(m)
if self._log_file is None: if self._log_file is None:
fn = os.path.join(self.store.data_dir, f'{self.symbol}.{self.ext()}.log') fn = os.path.join(self.store.data_dir, f'{self.symbol}.{self.ext()}.log')
self._log_file = open(fn, 'a') self._log_file = open(fn, 'a')

View File

@ -131,7 +131,7 @@ class Store:
self.fil.seek(0) self.fil.seek(0)
offset = 0 offset = 0
while (hdr := ChunkHeader.parse(self.fil)): while (hdr := ChunkHeader.parse(self.fil)):
self.p(hdr) # self.p(hdr)
total += hdr.size total += hdr.size
if not hdr.in_use: if not hdr.in_use:
# print(f"skip {hdr.size} {self.fil.tell()}") # print(f"skip {hdr.size} {self.fil.tell()}")
@ -296,21 +296,18 @@ class Store:
self.system_members[system].remove(m) self.system_members[system].remove(m)
def cleanup(self): def cleanup(self):
if time() < self.last_cleanup + self.cleanup_interval:
return
self.last_cleanup = time() self.last_cleanup = time()
start_time = time() start_time = time()
expired = list() expired = list()
for t in self.data: for t in self.data:
for o in self.all(t): for o in self.data[t].values():
if o.is_expired(): if o.is_expired():
expired.append(o) expired.append(o)
for o in expired: for o in expired:
self.purge(obj) self.purge(o)
del self.data[type(o)][o.symbol]
dur = time() - start_time dur = time() - start_time
self.p(f'cleaned {len(expired)} in {dur:.03f} seconds') # self.p(f'cleaned {len(expired)} in {dur:.03f} seconds')
def flush(self): def flush(self):
self.cleanup() self.cleanup()
@ -318,16 +315,17 @@ class Store:
start_time = time() start_time = time()
for obj in copy(self.dirty_objects): for obj in copy(self.dirty_objects):
it += 1 it += 1
if obj.is_expired(): if obj.symbol not in self.data[type(obj)] or self.data[type(obj)][obj.symbol] != obj:
self.purge(obj) print(f"Dirty object not in data {type(obj)} {obj.symbol} {obj}")
else: continue
self.store(obj) self.store(obj)
self.fil.flush() self.fil.flush()
self.dirty_objects = set() self.dirty_objects = set()
dur = time() - start_time dur = time() - start_time
self.p(f'flush done {it} items {dur:.2f}') #self.p(f'flush done {it} items {dur:.2f}')
def defrag(self): def defrag(self):
self.flush()
nm = self.fil.name nm = self.fil.name
self.fil.close() self.fil.close()
bakfile = nm+'.bak' bakfile = nm+'.bak'

View File

@ -2,6 +2,7 @@ from datetime import datetime
from math import ceil from math import ceil
import os import os
from os.path import isfile, dirname from os.path import isfile, dirname
import traceback
def open_file(fn): def open_file(fn):
d = dirname(fn) d = dirname(fn)
@ -82,3 +83,5 @@ def parse_timestamp(ts):
def render_timestamp(ts): def render_timestamp(ts):
return datetime.utcfromtimestamp(ts).isoformat() return datetime.utcfromtimestamp(ts).isoformat()
def fmtex(e):
return ''.join(traceback.TracebackException.from_exception(e).format())