From c9a7325f01d9a5344f35dbeb04e9181268999e2d Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sat, 31 Dec 2016 02:30:29 -0500 Subject: [PATCH] Add faction sovereignty information to universe data. --- calefaction/eve/universe.py | 126 ++++++++++++++++++++++++++++--------- scripts/import_sde.py | 150 ++++++++++++++++++++++++++++++++------------ 2 files changed, 207 insertions(+), 69 deletions(-) diff --git a/calefaction/eve/universe.py b/calefaction/eve/universe.py index 7b561a9..42178bb 100644 --- a/calefaction/eve/universe.py +++ b/calefaction/eve/universe.py @@ -7,19 +7,23 @@ import yaml __all__ = ["Universe"] -class _SolarSystem: - """Represents a solar system.""" +class _UniqueObject: + """Base class for uniquely ID'd objects in the universe.""" - def __init__(self, universe, sid, data): + def __init__(self, universe, id_, data): self._universe = universe - self._id = sid + self._id = id_ self._data = data @property def id(self): - """The solar system's ID, as an integer.""" + """The object's unique ID, as an integer.""" return self._id + +class _SolarSystem(_UniqueObject): + """Represents a solar system.""" + @property def name(self): """The solar system's name, as a string.""" @@ -40,19 +44,31 @@ class _SolarSystem: """The solar system's security status, as a float.""" return self._data["security"] + @property + def faction(self): + """The solar system's faction, as a _Faction object, or None.""" + if "faction" in self._data: + return self._universe.faction(self._data["faction"]) + return self.constellation.faction -class _Constellation: - """Represents a constellation.""" + @property + def is_nullsec(self): + """Whether the solar system is in nullsec.""" + return self.security < 0.05 - def __init__(self, universe, cid, data): - self._universe = universe - self._id = cid - self._data = data + @property + def is_lowsec(self): + """Whether the solar system is in nullsec.""" + return self.security >= 0.05 and self.security < 0.45 @property - def id(self): - """The constellation's ID, as an integer.""" - return self._id + def is_highsec(self): + """Whether the solar system is in nullsec.""" + return self.security >= 0.45 + + +class _Constellation(_UniqueObject): + """Represents a constellation.""" @property def name(self): @@ -64,23 +80,36 @@ class _Constellation: """The constellation's region, as a _Region object.""" return self._universe.region(self._data["region"]) + @property + def faction(self): + """The constellation's faction, as a _Faction object, or None.""" + if "faction" in self._data: + return self._universe.faction(self._data["faction"]) + return self.region.faction + -class _Region: +class _Region(_UniqueObject): """Represents a region.""" - def __init__(self, universe, rid, data): - self._universe = universe - self._id = rid - self._data = data + @property + def name(self): + """The region's name, as a string.""" + return self._data["name"] @property - def id(self): - """The region's ID, as an integer.""" - return self._id + def faction(self): + """The region's faction, as a _Faction object, or None.""" + if "faction" in self._data: + return self._universe.faction(self._data["faction"]) + return None + + +class _Faction(_UniqueObject): + """Represents a faction.""" @property def name(self): - """The region's name, as a string.""" + """The faction's name, as a string.""" return self._data["name"] @@ -115,16 +144,34 @@ class _DummyRegion(_Region): }) +class _DummyFaction(_Faction): + """Represents an unknown or invalid faction.""" + + def __init__(self, universe): + super().__init__(universe, -1, { + "name": "Unknown" + }) + + class Universe: """EVE API module for static universe data.""" def __init__(self, datadir): self._dir = datadir + self._lock = Lock() self._loaded = False + self._systems = {} self._constellations = {} self._regions = {} + self._factions = {} + + @staticmethod + def _load_yaml(path): + """Load in and return a YAML file with the given path.""" + with gzip.open(str(path), "rb") as fp: + return yaml.load(fp, Loader=yaml.CLoader) def _load(self): """Load in universe data. This can be called multiple times safely.""" @@ -135,13 +182,16 @@ class Universe: if self._loaded: return - filename = str(self._dir / "galaxy.yml.gz") - with gzip.open(filename, "rb") as fp: - data = yaml.load(fp, Loader=yaml.CLoader) + galaxy = self._load_yaml(self._dir / "galaxy.yml.gz") + self._systems = galaxy["systems"] + self._constellations = galaxy["constellations"] + self._regions = galaxy["regions"] + del galaxy + + entities = self._load_yaml(self._dir / "entities.yml.gz") + self._factions = entities["factions"] + del entities - self._systems = data["systems"] - self._constellations = data["constellations"] - self._regions = data["regions"] self._loaded = True def system(self, sid): @@ -173,3 +223,21 @@ class Universe: if rid not in self._regions: return _DummyRegion(self) return _Region(self, rid, self._regions[rid]) + + def faction(self, fid): + """Return a _Faction with the given ID. + + If the ID is invalid, return a dummy unknown object with ID -1. + """ + self._load() + if fid not in self._factions: + return _DummyFaction(self) + return _Faction(self, fid, self._factions[fid]) + + def ship(self, sid): + """Return a _Ship with the given ID. + + If the ID is invalid, return a dummy unknown object with ID -1. + """ + ... + raise NotImplementedError() diff --git a/scripts/import_sde.py b/scripts/import_sde.py index a1151fc..a33f3b2 100755 --- a/scripts/import_sde.py +++ b/scripts/import_sde.py @@ -90,6 +90,66 @@ def _build_galaxy_skeleton(ids, names): print("done.") return galaxy +def _load_assoc_for_system(galaxy, system, rid, cid): + data = _load_yaml(system / "solarsystem.staticdata") + sid = data["solarSystemID"] + sec = data["security"] + + assert isinstance(sid, int) + assert isinstance(sec, float) + assert sid >= 0 + assert sec >= -1.0 and sec <= 1.0 + + galaxy["systems"][sid]["constellation"] = cid + galaxy["systems"][sid]["region"] = rid + galaxy["systems"][sid]["security"] = sec + + if "factionID" in data: + facid = data["factionID"] + assert isinstance(facid, int) + assert facid >= 0 + galaxy["systems"][sid]["faction"] = facid + +def _load_assoc_for_constellation(galaxy, constellation, rid): + data = _load_yaml(constellation / "constellation.staticdata") + cid = data["constellationID"] + + assert isinstance(cid, int) + assert cid >= 0 + + galaxy["constellations"][cid]["region"] = rid + + if "factionID" in data: + facid = data["factionID"] + assert isinstance(facid, int) + assert facid >= 0 + galaxy["constellations"][cid]["faction"] = facid + + for system in constellation.iterdir(): + if not system.is_dir(): + continue + + _load_assoc_for_system(galaxy, system, rid, cid) + +def _load_assoc_for_region(galaxy, region): + data = _load_yaml(region / "region.staticdata") + rid = data["regionID"] + + assert isinstance(rid, int) + assert rid >= 0 + + if "factionID" in data: + facid = data["factionID"] + assert isinstance(facid, int) + assert facid >= 0 + galaxy["regions"][rid]["faction"] = facid + + for constellation in region.iterdir(): + if not constellation.is_dir(): + continue + + _load_assoc_for_constellation(galaxy, constellation, rid) + def _load_galaxy_associations(sde_dir, galaxy): print("Loading galaxy staticdata... ", end="", flush=True) @@ -101,38 +161,8 @@ def _load_galaxy_associations(sde_dir, galaxy): for region in base.iterdir(): if not region.is_dir(): continue - rdata = _load_yaml(region / "region.staticdata") - rid = rdata["regionID"] - - assert isinstance(rid, int) - assert rid >= 0 - - for constellation in region.iterdir(): - if not constellation.is_dir(): - continue - cdata = _load_yaml(constellation / "constellation.staticdata") - cid = cdata["constellationID"] - - assert isinstance(cid, int) - assert cid >= 0 - galaxy["constellations"][cid]["region"] = rid - - for system in constellation.iterdir(): - if not system.is_dir(): - continue - sdata = _load_yaml(system / "solarsystem.staticdata") - sid = sdata["solarSystemID"] - sec = sdata["security"] - - assert isinstance(sid, int) - assert isinstance(sec, float) - assert sid >= 0 - assert sec >= -1.0 and sec <= 1.0 - - galaxy["systems"][sid]["constellation"] = cid - galaxy["systems"][sid]["region"] = rid - galaxy["systems"][sid]["security"] = sec + _load_assoc_for_region(galaxy, region) print("done.") @@ -145,6 +175,25 @@ def _load_galaxy_associations(sde_dir, galaxy): if system["region"] < 0 or system["constellation"] < 0: print("[WARNING] Orphaned system: %d=%s" % (sid, system["name"])) +def _load_factions(sde_dir): + print("Loading factions... ", end="", flush=True) + + data = _load_yaml(sde_dir / "bsd" / "chrFactions.yaml") + + factions = {} + for entry in data: + fid = entry["factionID"] + name = entry["factionName"] + + assert isinstance(fid, int) + assert isinstance(name, str) + assert fid >= 0 + + factions[fid] = {"name": name} + + print("done.") + return factions + def _dump_galaxy(out_dir, galaxy): print("Dumping galaxy... ", end="", flush=True) @@ -154,22 +203,37 @@ def _dump_galaxy(out_dir, galaxy): print("done.") -def _compress_galaxy(out_dir): - print("Compressing galaxy... ", end="", flush=True) +def _dump_entities(out_dir, factions): + print("Dumping entities... ", end="", flush=True) - fn_src = out_dir / "galaxy.yml" - fn_dst = out_dir / "galaxy.yml.gz" + entities = {"factions": factions} - with fn_src.open("rb") as f_in: - with gzip.open(str(fn_dst), "wb") as f_out: - shutil.copyfileobj(f_in, f_out) + filename = out_dir / "entities.yml" + with filename.open("w") as fp: + fp.write(yaml.dump(entities, Dumper=yaml.CDumper)) print("done.") +def _compress(out_dir): + targets = ["galaxy", "entities"] + for basename in targets: + print("Compressing %s... " % basename, end="", flush=True) + + fn_src = out_dir / (basename + ".yml") + fn_dst = out_dir / (basename + ".yml.gz") + + with fn_src.open("rb") as f_in: + with gzip.open(str(fn_dst), "wb") as f_out: + shutil.copyfileobj(f_in, f_out) + + print("done.") + def _cleanup(out_dir): print("Cleaning up... ", end="", flush=True) - (out_dir / "galaxy.yml").unlink() + targets = ["galaxy", "entities"] + for basename in targets: + (out_dir / (basename + ".yml")).unlink() print("done.") @@ -184,13 +248,19 @@ def import_sde(sde_dir, out_dir): print("Counts: regions=%d, constellations=%d, systems=%d" % ( len(ids[_REGION]), len(ids[_CONSTELLATION]), len(ids[_SOLAR_SYSTEM]))) names = _load_names(sde_dir) + galaxy = _build_galaxy_skeleton(ids, names) del ids del names _load_galaxy_associations(sde_dir, galaxy) _dump_galaxy(out_dir, galaxy) del galaxy - _compress_galaxy(out_dir) + + factions = _load_factions(sde_dir) + _dump_entities(out_dir, factions) + del factions + + _compress(out_dir) _cleanup(out_dir) def main():