diff --git a/calefaction/eve/universe.py b/calefaction/eve/universe.py index 3f38bcb..6c14060 100644 --- a/calefaction/eve/universe.py +++ b/calefaction/eve/universe.py @@ -7,6 +7,18 @@ import yaml __all__ = ["Universe"] +def _cache(func): + """Wrap a no-argument method to cache its return value in the object.""" + def inner(self): + key = func.__name__ + if key in self._cache: + return self._cache[key] + value = func(self) + self._cache[key] = value + return value + return inner + + class _UniqueObject: """Base class for uniquely ID'd objects in the universe.""" @@ -14,6 +26,7 @@ class _UniqueObject: self._universe = universe self._id = id_ self._data = data + self._cache = {} @property def id(self): @@ -30,11 +43,13 @@ class _SolarSystem(_UniqueObject): return self._data["name"] @property + @_cache def constellation(self): """The solar system's constellation, as a _Constellation object.""" return self._universe.constellation(self._data["constellation"]) @property + @_cache def region(self): """The solar system's region, as a _Region object.""" return self._universe.region(self._data["region"]) @@ -50,6 +65,16 @@ class _SolarSystem(_UniqueObject): return tuple(self._data["coords"]) @property + @_cache + def gates(self): + """The solar system's adjacent systems, via stargate. + + A list of _SolarSystem objects. + """ + return [self._universe.system(sid) for sid in self._data["gates"]] + + @property + @_cache def faction(self): """The solar system's faction, as a _Faction object, or None.""" if "faction" in self._data: @@ -86,11 +111,13 @@ class _Constellation(_UniqueObject): return self._data["name"] @property + @_cache def region(self): """The constellation's region, as a _Region object.""" return self._universe.region(self._data["region"]) @property + @_cache def faction(self): """The constellation's faction, as a _Faction object, or None.""" if "faction" in self._data: @@ -112,6 +139,7 @@ class _Region(_UniqueObject): return self._data["name"] @property + @_cache def faction(self): """The region's faction, as a _Faction object, or None.""" if "faction" in self._data: @@ -132,6 +160,16 @@ class _Faction(_UniqueObject): """The faction's name, as a string.""" return self._data["name"] + @property + @_cache + def territory(self): + """The faction's controlled territory. + + A list of _SolarSystems. + """ + return [system for system in self._universe.systems() + if system.faction and system.faction.id == self.id] + class _Type(_UniqueObject): """Represents any type, including ships and materials.""" @@ -194,7 +232,8 @@ class _DummySolarSystem(_SolarSystem): "constellation": -1, "region": -1, "security": 0.0, - "coords": (0, 0, 0) + "coords": (0.0, 0.0, 0.0), + "gates": [] }) @@ -325,6 +364,12 @@ class Universe: return _DummyConstellation(self) return _Constellation(self, cid, self._constellations[cid]) + def constellations(self): + """Return an iterator over all _Constellations.""" + self._load() + for cid in self._constellations: + yield self.constellation(cid) + def region(self, rid): """Return a _Region with the given ID. @@ -335,6 +380,12 @@ class Universe: return _DummyRegion(self) return _Region(self, rid, self._regions[rid]) + def regions(self): + """Return an iterator over all _Regions.""" + self._load() + for rid in self._regions: + yield self.region(rid) + def faction(self, fid): """Return a _Faction with the given ID. @@ -345,6 +396,12 @@ class Universe: return _DummyFaction(self) return _Faction(self, fid, self._factions[fid]) + def factions(self): + """Return an iterator over all _Factions.""" + self._load() + for fid in self._factions: + yield self.faction(fid) + def type(self, tid): """Return a _Type with the given ID. diff --git a/calefaction/modules/map.py b/calefaction/modules/map.py index dc20547..4b6e343 100644 --- a/calefaction/modules/map.py +++ b/calefaction/modules/map.py @@ -25,10 +25,18 @@ def mapdata(): "galaxy": { system.id: { "name": system.name, + "security": system.security, "coords": system.coords, - "security": system.security + "gates": [dest.id for dest in system.gates], + "faction": system.faction.id if system.faction else -1 } for system in g.eve.universe.systems() if not system.is_whspace + }, + "factions": { + faction.id: { + "name": faction.name + } + for faction in g.eve.universe.factions() if faction.territory } } resp = app.response_class(response=json.dumps(payload), status=200, diff --git a/scripts/import_sde.py b/scripts/import_sde.py index 8253004..276161a 100755 --- a/scripts/import_sde.py +++ b/scripts/import_sde.py @@ -152,7 +152,9 @@ def _build_galaxy_skeleton(ids, names): "name": names[sid], "constellation": -1, "region": -1, - "security": 0.0 + "security": 0.0, + "coords": [0.0, 0.0, 0.0], + "gates": [] } print("done.") @@ -181,6 +183,16 @@ def _load_assoc_for_system(galaxy, system, rid, cid): assert facid >= 0 galaxy["systems"][sid]["faction"] = facid + galaxy["systems->stargates"][sid] = [] + for sgid, gate in data["stargates"].items(): + dest = gate["destination"] + assert isinstance(sgid, int) + assert isinstance(dest, int) + assert sgid >= 0 + assert dest >= 0 + galaxy["systems->stargates"][sid].append(dest) + galaxy["stargates->systems"][sgid] = sid + def _load_assoc_for_constellation(galaxy, constellation, rid): data = _load_yaml(constellation / "constellation.staticdata") cid = data["constellationID"] @@ -221,9 +233,19 @@ def _load_assoc_for_region(galaxy, region): _load_assoc_for_constellation(galaxy, constellation, rid) +def _load_gate_info(galaxy): + sys2gate = galaxy["systems->stargates"] + gate2sys = galaxy["stargates->systems"] + + for sid, gates in sys2gate.items(): + galaxy["systems"][sid]["gates"] = [gate2sys[gate] for gate in gates] + def _load_galaxy_associations(sde_dir, galaxy): print("Loading galaxy staticdata... ", end="", flush=True) + galaxy["systems->stargates"] = {} + galaxy["stargates->systems"] = {} + univdir = sde_dir / "fsd" / "universe" for base in univdir.iterdir(): if not base.is_dir(): @@ -235,7 +257,9 @@ def _load_galaxy_associations(sde_dir, galaxy): _load_assoc_for_region(galaxy, region) - print("done.") + _load_gate_info(galaxy) + del galaxy["systems->stargates"] + del galaxy["stargates->systems"] for cid, constellation in galaxy["constellations"].items(): if constellation["region"] < 0: @@ -246,6 +270,8 @@ def _load_galaxy_associations(sde_dir, galaxy): if system["region"] < 0 or system["constellation"] < 0: print("[WARNING] Orphaned system: %d=%s" % (sid, system["name"])) + print("done.") + def _load_factions(sde_dir): print("Loading factions... ", end="", flush=True)