mission step priorities, fixed the store again
This commit is contained in:
parent
f913d23c06
commit
5d47efdbda
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
|
@ -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)
|
||||||
|
@ -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:
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
@ -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')
|
||||||
|
@ -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'
|
||||||
|
@ -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())
|
||||||
|
Loading…
Reference in New Issue
Block a user