A corporation manager and dashboard for EVE Online
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 

298 lignes
8.0 KiB

  1. # -*- coding: utf-8 -*-
  2. import gzip
  3. from threading import Lock
  4. import yaml
  5. __all__ = ["Universe"]
  6. class _UniqueObject:
  7. """Base class for uniquely ID'd objects in the universe."""
  8. def __init__(self, universe, id_, data):
  9. self._universe = universe
  10. self._id = id_
  11. self._data = data
  12. @property
  13. def id(self):
  14. """The object's unique ID, as an integer."""
  15. return self._id
  16. class _SolarSystem(_UniqueObject):
  17. """Represents a solar system."""
  18. @property
  19. def name(self):
  20. """The solar system's name, as a string."""
  21. return self._data["name"]
  22. @property
  23. def constellation(self):
  24. """The solar system's constellation, as a _Constellation object."""
  25. return self._universe.constellation(self._data["constellation"])
  26. @property
  27. def region(self):
  28. """The solar system's region, as a _Region object."""
  29. return self._universe.region(self._data["region"])
  30. @property
  31. def security(self):
  32. """The solar system's security status, as a float."""
  33. return self._data["security"]
  34. @property
  35. def faction(self):
  36. """The solar system's faction, as a _Faction object, or None."""
  37. if "faction" in self._data:
  38. return self._universe.faction(self._data["faction"])
  39. return self.constellation.faction
  40. @property
  41. def is_nullsec(self):
  42. """Whether the solar system is in nullsec."""
  43. return self.security < 0.05
  44. @property
  45. def is_lowsec(self):
  46. """Whether the solar system is in nullsec."""
  47. return self.security >= 0.05 and self.security < 0.45
  48. @property
  49. def is_highsec(self):
  50. """Whether the solar system is in nullsec."""
  51. return self.security >= 0.45
  52. class _Constellation(_UniqueObject):
  53. """Represents a constellation."""
  54. @property
  55. def name(self):
  56. """The constellation's name, as a string."""
  57. return self._data["name"]
  58. @property
  59. def region(self):
  60. """The constellation's region, as a _Region object."""
  61. return self._universe.region(self._data["region"])
  62. @property
  63. def faction(self):
  64. """The constellation's faction, as a _Faction object, or None."""
  65. if "faction" in self._data:
  66. return self._universe.faction(self._data["faction"])
  67. return self.region.faction
  68. class _Region(_UniqueObject):
  69. """Represents a region."""
  70. @property
  71. def name(self):
  72. """The region's name, as a string."""
  73. return self._data["name"]
  74. @property
  75. def faction(self):
  76. """The region's faction, as a _Faction object, or None."""
  77. if "faction" in self._data:
  78. return self._universe.faction(self._data["faction"])
  79. return None
  80. class _Faction(_UniqueObject):
  81. """Represents a faction."""
  82. @property
  83. def name(self):
  84. """The faction's name, as a string."""
  85. return self._data["name"]
  86. class _Killable(_UniqueObject):
  87. """Represents a killable object, like a ship, structure, or fighter."""
  88. def __init__(self, universe, kid, cat, data):
  89. super().__init__(universe, kid, data)
  90. self._cat = cat
  91. @property
  92. def name(self):
  93. """The killable object's name, as a string."""
  94. return self._data["name"]
  95. @property
  96. def group(self):
  97. """The killable object's group, as a string."""
  98. return self._data["group"]
  99. @property
  100. def is_ship(self):
  101. """Whether the killable object is a ship."""
  102. return self._cat == "ships"
  103. @property
  104. def is_structure(self):
  105. """Whether the killable object is a structure."""
  106. return self._cat == "structures"
  107. @property
  108. def is_fighter(self):
  109. """Whether the killable object is a fighter."""
  110. return self._cat == "fighters"
  111. class _DummySolarSystem(_SolarSystem):
  112. """Represents an unknown or invalid solar system."""
  113. def __init__(self, universe):
  114. super().__init__(universe, -1, {
  115. "name": "Unknown",
  116. "constellation": -1,
  117. "region": -1,
  118. "security": 0.0
  119. })
  120. class _DummyConstellation(_Constellation):
  121. """Represents an unknown or invalid constellation."""
  122. def __init__(self, universe):
  123. super().__init__(universe, -1, {
  124. "name": "Unknown",
  125. "region": -1
  126. })
  127. class _DummyRegion(_Region):
  128. """Represents an unknown or invalid region."""
  129. def __init__(self, universe):
  130. super().__init__(universe, -1, {
  131. "name": "Unknown"
  132. })
  133. class _DummyFaction(_Faction):
  134. """Represents an unknown or invalid faction."""
  135. def __init__(self, universe):
  136. super().__init__(universe, -1, {
  137. "name": "Unknown"
  138. })
  139. class _DummyKillable(_Killable):
  140. """Represents an unknown or invalid killable object."""
  141. def __init__(self, universe):
  142. super().__init__(universe, -1, None, {
  143. "name": "Unknown",
  144. "group": "Unknown"
  145. })
  146. class Universe:
  147. """EVE API module for static universe data."""
  148. def __init__(self, datadir):
  149. self._dir = datadir
  150. self._lock = Lock()
  151. self._loaded = False
  152. self._systems = {}
  153. self._constellations = {}
  154. self._regions = {}
  155. self._factions = {}
  156. self._killable_idx = {}
  157. self._killable_tab = {}
  158. @staticmethod
  159. def _load_yaml(path):
  160. """Load in and return a YAML file with the given path."""
  161. with gzip.open(str(path), "rb") as fp:
  162. return yaml.load(fp, Loader=yaml.CLoader)
  163. def _load(self):
  164. """Load in universe data. This can be called multiple times safely."""
  165. if self._loaded:
  166. return
  167. with self._lock:
  168. if self._loaded:
  169. return
  170. galaxy = self._load_yaml(self._dir / "galaxy.yml.gz")
  171. self._systems = galaxy["systems"]
  172. self._constellations = galaxy["constellations"]
  173. self._regions = galaxy["regions"]
  174. del galaxy
  175. entities = self._load_yaml(self._dir / "entities.yml.gz")
  176. self._factions = entities["factions"]
  177. del entities
  178. types = self._load_yaml(self._dir / "types.yml.gz")
  179. self._killable_idx = {kid: cat for cat, kids in types.items()
  180. for kid in kids}
  181. self._killable_tab = types
  182. del types
  183. self._loaded = True
  184. def system(self, sid):
  185. """Return a _SolarSystem with the given ID.
  186. If the ID is invalid, return a dummy unknown object with ID -1.
  187. """
  188. self._load()
  189. if sid not in self._systems:
  190. return _DummySolarSystem(self)
  191. return _SolarSystem(self, sid, self._systems[sid])
  192. def constellation(self, cid):
  193. """Return a _Constellation with the given ID.
  194. If the ID is invalid, return a dummy unknown object with ID -1.
  195. """
  196. self._load()
  197. if cid not in self._constellations:
  198. return _DummyConstellation(self)
  199. return _Constellation(self, cid, self._constellations[cid])
  200. def region(self, rid):
  201. """Return a _Region with the given ID.
  202. If the ID is invalid, return a dummy unknown object with ID -1.
  203. """
  204. self._load()
  205. if rid not in self._regions:
  206. return _DummyRegion(self)
  207. return _Region(self, rid, self._regions[rid])
  208. def faction(self, fid):
  209. """Return a _Faction with the given ID.
  210. If the ID is invalid, return a dummy unknown object with ID -1.
  211. """
  212. self._load()
  213. if fid not in self._factions:
  214. return _DummyFaction(self)
  215. return _Faction(self, fid, self._factions[fid])
  216. def killable(self, kid):
  217. """Return a _Killable with the given ID.
  218. If the ID is invalid, return a dummy unknown object with ID -1.
  219. """
  220. self._load()
  221. if kid not in self._killable_idx:
  222. return _DummyKillable(self)
  223. cat = self._killable_idx[kid]
  224. return _Killable(self, kid, cat, self._killable_tab[cat][kid])