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.
 
 
 
 
 

368 lignes
9.9 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 coords(self):
  36. """The solar system's coordinates, as a 3-tuple of floats (x, y, z)."""
  37. return tuple(self._data["coords"])
  38. @property
  39. def faction(self):
  40. """The solar system's faction, as a _Faction object, or None."""
  41. if "faction" in self._data:
  42. return self._universe.faction(self._data["faction"])
  43. return self.constellation.faction
  44. @property
  45. def is_nullsec(self):
  46. """Whether the solar system is in nullsec."""
  47. return self.security < 0.05
  48. @property
  49. def is_lowsec(self):
  50. """Whether the solar system is in nullsec."""
  51. return self.security >= 0.05 and self.security < 0.45
  52. @property
  53. def is_highsec(self):
  54. """Whether the solar system is in nullsec."""
  55. return self.security >= 0.45
  56. @property
  57. def is_whspace(self):
  58. """Whether the solar system is in wormhole space."""
  59. return self.region.is_whspace
  60. class _Constellation(_UniqueObject):
  61. """Represents a constellation."""
  62. @property
  63. def name(self):
  64. """The constellation's name, as a string."""
  65. return self._data["name"]
  66. @property
  67. def region(self):
  68. """The constellation's region, as a _Region object."""
  69. return self._universe.region(self._data["region"])
  70. @property
  71. def faction(self):
  72. """The constellation's faction, as a _Faction object, or None."""
  73. if "faction" in self._data:
  74. return self._universe.faction(self._data["faction"])
  75. return self.region.faction
  76. @property
  77. def is_whspace(self):
  78. """Whether the constellation is in wormhole space."""
  79. return self.region.is_whspace
  80. class _Region(_UniqueObject):
  81. """Represents a region."""
  82. @property
  83. def name(self):
  84. """The region's name, as a string."""
  85. return self._data["name"]
  86. @property
  87. def faction(self):
  88. """The region's faction, as a _Faction object, or None."""
  89. if "faction" in self._data:
  90. return self._universe.faction(self._data["faction"])
  91. return None
  92. @property
  93. def is_whspace(self):
  94. """Whether the region is in wormhole space."""
  95. return self._id >= 11000000
  96. class _Faction(_UniqueObject):
  97. """Represents a faction."""
  98. @property
  99. def name(self):
  100. """The faction's name, as a string."""
  101. return self._data["name"]
  102. class _Type(_UniqueObject):
  103. """Represents any type, including ships and materials."""
  104. @property
  105. def name(self):
  106. """The item's name, as a string."""
  107. return self._data["name"]
  108. @property
  109. def group_id(self):
  110. """The item's group ID, as an integer."""
  111. return self._data["group_id"]
  112. @property
  113. def market_group_id(self):
  114. """The item's market group ID, as an integer, or None."""
  115. return self._data.get("market_group_id")
  116. class _Killable(_UniqueObject):
  117. """Represents a killable object, like a ship, structure, or fighter."""
  118. def __init__(self, universe, kid, cat, data):
  119. super().__init__(universe, kid, data)
  120. self._cat = cat
  121. @property
  122. def name(self):
  123. """The killable object's name, as a string."""
  124. return self._data["name"]
  125. @property
  126. def group(self):
  127. """The killable object's group, as a string."""
  128. return self._data["group"]
  129. @property
  130. def is_ship(self):
  131. """Whether the killable object is a ship."""
  132. return self._cat == "ships"
  133. @property
  134. def is_structure(self):
  135. """Whether the killable object is a structure."""
  136. return self._cat == "structures"
  137. @property
  138. def is_fighter(self):
  139. """Whether the killable object is a fighter."""
  140. return self._cat == "fighters"
  141. class _DummySolarSystem(_SolarSystem):
  142. """Represents an unknown or invalid solar system."""
  143. def __init__(self, universe):
  144. super().__init__(universe, -1, {
  145. "name": "Unknown",
  146. "constellation": -1,
  147. "region": -1,
  148. "security": 0.0,
  149. "coords": (0, 0, 0)
  150. })
  151. class _DummyConstellation(_Constellation):
  152. """Represents an unknown or invalid constellation."""
  153. def __init__(self, universe):
  154. super().__init__(universe, -1, {
  155. "name": "Unknown",
  156. "region": -1
  157. })
  158. class _DummyRegion(_Region):
  159. """Represents an unknown or invalid region."""
  160. def __init__(self, universe):
  161. super().__init__(universe, -1, {
  162. "name": "Unknown"
  163. })
  164. class _DummyFaction(_Faction):
  165. """Represents an unknown or invalid faction."""
  166. def __init__(self, universe):
  167. super().__init__(universe, -1, {
  168. "name": "Unknown"
  169. })
  170. class _DummyType(_Type):
  171. """Represents an unknown or invalid type."""
  172. def __init__(self, universe):
  173. super().__init__(universe, -1, {
  174. "name": "Unknown",
  175. "group_id": -1,
  176. "market_group_id": -1
  177. })
  178. class _DummyKillable(_Killable):
  179. """Represents an unknown or invalid killable object."""
  180. def __init__(self, universe):
  181. super().__init__(universe, -1, None, {
  182. "name": "Unknown",
  183. "group": "Unknown"
  184. })
  185. class Universe:
  186. """EVE API module for static universe data."""
  187. def __init__(self, datadir):
  188. self._dir = datadir
  189. self._lock = Lock()
  190. self._loaded = False
  191. self._systems = {}
  192. self._constellations = {}
  193. self._regions = {}
  194. self._factions = {}
  195. self._types = {}
  196. self._killable_idx = {}
  197. self._killable_tab = {}
  198. @staticmethod
  199. def _load_yaml(path):
  200. """Load in and return a YAML file with the given path."""
  201. with gzip.open(str(path), "rb") as fp:
  202. return yaml.load(fp, Loader=yaml.CLoader)
  203. def _load(self):
  204. """Load in universe data. This can be called multiple times safely."""
  205. if self._loaded:
  206. return
  207. with self._lock:
  208. if self._loaded:
  209. return
  210. galaxy = self._load_yaml(self._dir / "galaxy.yml.gz")
  211. self._systems = galaxy["systems"]
  212. self._constellations = galaxy["constellations"]
  213. self._regions = galaxy["regions"]
  214. del galaxy
  215. entities = self._load_yaml(self._dir / "entities.yml.gz")
  216. self._factions = entities["factions"]
  217. del entities
  218. self._types = self._load_yaml(self._dir / "types.yml.gz")
  219. killables = self._load_yaml(self._dir / "killables.yml.gz")
  220. self._killable_idx = {kid: cat for cat, kids in killables.items()
  221. for kid in kids}
  222. self._killable_tab = killables
  223. del killables
  224. self._loaded = True
  225. def system(self, sid):
  226. """Return a _SolarSystem with the given ID.
  227. If the ID is invalid, return a dummy unknown object with ID -1.
  228. """
  229. self._load()
  230. if sid not in self._systems:
  231. return _DummySolarSystem(self)
  232. return _SolarSystem(self, sid, self._systems[sid])
  233. def systems(self):
  234. """Return an iterator over all _SolarSystems."""
  235. self._load()
  236. for sid in self._systems:
  237. yield self.system(sid)
  238. def constellation(self, cid):
  239. """Return a _Constellation with the given ID.
  240. If the ID is invalid, return a dummy unknown object with ID -1.
  241. """
  242. self._load()
  243. if cid not in self._constellations:
  244. return _DummyConstellation(self)
  245. return _Constellation(self, cid, self._constellations[cid])
  246. def region(self, rid):
  247. """Return a _Region with the given ID.
  248. If the ID is invalid, return a dummy unknown object with ID -1.
  249. """
  250. self._load()
  251. if rid not in self._regions:
  252. return _DummyRegion(self)
  253. return _Region(self, rid, self._regions[rid])
  254. def faction(self, fid):
  255. """Return a _Faction with the given ID.
  256. If the ID is invalid, return a dummy unknown object with ID -1.
  257. """
  258. self._load()
  259. if fid not in self._factions:
  260. return _DummyFaction(self)
  261. return _Faction(self, fid, self._factions[fid])
  262. def type(self, tid):
  263. """Return a _Type with the given ID.
  264. If the ID is invalid, return a dummy unknown object with ID -1.
  265. """
  266. self._load()
  267. if tid not in self._types:
  268. return _DummyKillable(self)
  269. return _Type(self, tid, self._types[tid])
  270. def killable(self, kid):
  271. """Return a _Killable with the given ID.
  272. If the ID is invalid, return a dummy unknown object with ID -1.
  273. """
  274. self._load()
  275. if kid not in self._killable_idx:
  276. return _DummyKillable(self)
  277. cat = self._killable_idx[kid]
  278. return _Killable(self, kid, cat, self._killable_tab[cat][kid])