A corporation manager and dashboard for EVE Online
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

331 lines
8.9 KiB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import gzip
  4. from pathlib import Path
  5. import shutil
  6. import sys
  7. import yaml
  8. _SHIP_CAT = 6
  9. _FIGHTER_CAT = 87
  10. _STRUCT_CATS = [22, 23, 40, 46, 65]
  11. _REGION = 3
  12. _CONSTELLATION = 4
  13. _SOLAR_SYSTEM = 5
  14. def _load_yaml(filename):
  15. with filename.open("rb") as fp:
  16. return yaml.load(fp, Loader=yaml.CLoader)
  17. def _save_yaml(filename, data):
  18. with filename.open("w") as fp:
  19. fp.write(yaml.dump(data, Dumper=yaml.CDumper))
  20. def _verify_categoryids(sde_dir):
  21. print("Verifying categoryIDs... ", end="", flush=True)
  22. data = _load_yaml(sde_dir / "fsd" / "categoryIDs.yaml")
  23. assert data[_SHIP_CAT]["name"]["en"] == "Ship"
  24. print("done.")
  25. def _load_groupids(sde_dir):
  26. print("Loading groupIDs... ", end="", flush=True)
  27. data = _load_yaml(sde_dir / "fsd" / "groupIDs.yaml")
  28. groups = {cid: {} for cid in [_SHIP_CAT, _FIGHTER_CAT] + _STRUCT_CATS}
  29. for gid, group in data.items():
  30. cat = group["categoryID"]
  31. if cat in groups:
  32. name = group["name"]["en"]
  33. assert isinstance(gid, int)
  34. assert isinstance(name, str)
  35. groups[cat][gid] = name
  36. print("done.")
  37. return groups
  38. def _load_typeids(sde_dir, groups):
  39. print("Loading typeIDs... ", end="", flush=True)
  40. data = _load_yaml(sde_dir / "fsd" / "typeIDs.yaml")
  41. assert data[_REGION]["groupID"] == _REGION
  42. assert data[_REGION]["name"]["en"] == "Region"
  43. assert data[_CONSTELLATION]["groupID"] == _CONSTELLATION
  44. assert data[_CONSTELLATION]["name"]["en"] == "Constellation"
  45. assert data[_SOLAR_SYSTEM]["groupID"] == _SOLAR_SYSTEM
  46. assert data[_SOLAR_SYSTEM]["name"]["en"] == "Solar System"
  47. types = {"ships": {}, "structures": {}, "fighters": {}}
  48. cat_conv = {_SHIP_CAT: "ships", _FIGHTER_CAT: "fighters"}
  49. cat_conv.update({cid: "structures" for cid in _STRUCT_CATS})
  50. group_conv = {gid: cid for cid, gids in groups.items() for gid in gids}
  51. for tid, type_ in data.items():
  52. gid = type_["groupID"]
  53. if gid in group_conv:
  54. cid = group_conv[gid]
  55. cname = cat_conv[cid]
  56. name = type_["name"]["en"]
  57. group = groups[cid][gid]
  58. assert isinstance(tid, int)
  59. types[cname][tid] = {"name": name, "group": group}
  60. print("done.")
  61. return types
  62. def _load_ids(sde_dir):
  63. print("Loading itemIDs... ", end="", flush=True)
  64. data = _load_yaml(sde_dir / "bsd" / "invItems.yaml")
  65. ids = {_REGION: [], _CONSTELLATION: [], _SOLAR_SYSTEM: []}
  66. for entry in data:
  67. if entry["typeID"] in ids:
  68. ids[entry["typeID"]].append(entry["itemID"])
  69. print("done.")
  70. return ids
  71. def _load_names(sde_dir):
  72. print("Loading itemNames... ", end="", flush=True)
  73. data = _load_yaml(sde_dir / "bsd" / "invNames.yaml")
  74. names = {}
  75. for entry in data:
  76. name = entry["itemName"]
  77. assert isinstance(name, str)
  78. names[entry["itemID"]] = name
  79. print("done.")
  80. return names
  81. def _build_galaxy_skeleton(ids, names):
  82. print("Building galaxy skeleton... ", end="", flush=True)
  83. galaxy = {"regions": {}, "constellations": {}, "systems": {}}
  84. d = galaxy["regions"]
  85. for rid in ids[_REGION]:
  86. assert isinstance(rid, int)
  87. d[rid] = {
  88. "name": names[rid]
  89. }
  90. d = galaxy["constellations"]
  91. for cid in ids[_CONSTELLATION]:
  92. assert isinstance(cid, int)
  93. d[cid] = {
  94. "name": names[cid],
  95. "region": -1
  96. }
  97. d = galaxy["systems"]
  98. for sid in ids[_SOLAR_SYSTEM]:
  99. assert isinstance(sid, int)
  100. d[sid] = {
  101. "name": names[sid],
  102. "constellation": -1, "region": -1, "security": 0.0
  103. }
  104. print("done.")
  105. return galaxy
  106. def _load_assoc_for_system(galaxy, system, rid, cid):
  107. data = _load_yaml(system / "solarsystem.staticdata")
  108. sid = data["solarSystemID"]
  109. sec = data["security"]
  110. assert isinstance(sid, int)
  111. assert isinstance(sec, float)
  112. assert sid >= 0
  113. assert sec >= -1.0 and sec <= 1.0
  114. galaxy["systems"][sid]["constellation"] = cid
  115. galaxy["systems"][sid]["region"] = rid
  116. galaxy["systems"][sid]["security"] = sec
  117. if "factionID" in data:
  118. facid = data["factionID"]
  119. assert isinstance(facid, int)
  120. assert facid >= 0
  121. galaxy["systems"][sid]["faction"] = facid
  122. def _load_assoc_for_constellation(galaxy, constellation, rid):
  123. data = _load_yaml(constellation / "constellation.staticdata")
  124. cid = data["constellationID"]
  125. assert isinstance(cid, int)
  126. assert cid >= 0
  127. galaxy["constellations"][cid]["region"] = rid
  128. if "factionID" in data:
  129. facid = data["factionID"]
  130. assert isinstance(facid, int)
  131. assert facid >= 0
  132. galaxy["constellations"][cid]["faction"] = facid
  133. for system in constellation.iterdir():
  134. if not system.is_dir():
  135. continue
  136. _load_assoc_for_system(galaxy, system, rid, cid)
  137. def _load_assoc_for_region(galaxy, region):
  138. data = _load_yaml(region / "region.staticdata")
  139. rid = data["regionID"]
  140. assert isinstance(rid, int)
  141. assert rid >= 0
  142. if "factionID" in data:
  143. facid = data["factionID"]
  144. assert isinstance(facid, int)
  145. assert facid >= 0
  146. galaxy["regions"][rid]["faction"] = facid
  147. for constellation in region.iterdir():
  148. if not constellation.is_dir():
  149. continue
  150. _load_assoc_for_constellation(galaxy, constellation, rid)
  151. def _load_galaxy_associations(sde_dir, galaxy):
  152. print("Loading galaxy staticdata... ", end="", flush=True)
  153. univdir = sde_dir / "fsd" / "universe"
  154. for base in univdir.iterdir():
  155. if not base.is_dir():
  156. continue
  157. for region in base.iterdir():
  158. if not region.is_dir():
  159. continue
  160. _load_assoc_for_region(galaxy, region)
  161. print("done.")
  162. for cid, constellation in galaxy["constellations"].items():
  163. if constellation["region"] < 0:
  164. print("[WARNING] Orphaned constellation: %d=%s" % (
  165. cid, constellation["name"]))
  166. for sid, system in galaxy["systems"].items():
  167. if system["region"] < 0 or system["constellation"] < 0:
  168. print("[WARNING] Orphaned system: %d=%s" % (sid, system["name"]))
  169. def _load_factions(sde_dir):
  170. print("Loading factions... ", end="", flush=True)
  171. data = _load_yaml(sde_dir / "bsd" / "chrFactions.yaml")
  172. factions = {}
  173. for entry in data:
  174. fid = entry["factionID"]
  175. name = entry["factionName"]
  176. assert isinstance(fid, int)
  177. assert isinstance(name, str)
  178. assert fid >= 0
  179. factions[fid] = {"name": name}
  180. print("done.")
  181. return factions
  182. def _dump_types(out_dir, types):
  183. print("Dumping types... ", end="", flush=True)
  184. _save_yaml(out_dir / "types.yml", types)
  185. print("done.")
  186. def _dump_galaxy(out_dir, galaxy):
  187. print("Dumping galaxy... ", end="", flush=True)
  188. _save_yaml(out_dir / "galaxy.yml", galaxy)
  189. print("done.")
  190. def _dump_entities(out_dir, factions):
  191. print("Dumping entities... ", end="", flush=True)
  192. entities = {"factions": factions}
  193. _save_yaml(out_dir / "entities.yml", entities)
  194. print("done.")
  195. def _compress(out_dir):
  196. targets = ["types", "galaxy", "entities"]
  197. for basename in targets:
  198. print("Compressing %s... " % basename, end="", flush=True)
  199. fn_src = out_dir / (basename + ".yml")
  200. fn_dst = out_dir / (basename + ".yml.gz")
  201. with fn_src.open("rb") as f_in:
  202. with gzip.open(str(fn_dst), "wb") as f_out:
  203. shutil.copyfileobj(f_in, f_out)
  204. print("done.")
  205. def _cleanup(out_dir):
  206. print("Cleaning up... ", end="", flush=True)
  207. targets = ["types", "galaxy", "entities"]
  208. for basename in targets:
  209. (out_dir / (basename + ".yml")).unlink()
  210. print("done.")
  211. def import_sde(sde_dir, out_dir):
  212. """Import the SDE unzipped at sde_dir to out_dir."""
  213. print("EVE Online static data import")
  214. print("- from: %s" % sde_dir)
  215. print("- to: %s" % out_dir)
  216. _verify_categoryids(sde_dir)
  217. groups = _load_groupids(sde_dir)
  218. types = _load_typeids(sde_dir, groups)
  219. _dump_types(out_dir, types)
  220. del groups, types
  221. ids = _load_ids(sde_dir)
  222. print("Counts: regions=%d, constellations=%d, systems=%d" % (
  223. len(ids[_REGION]), len(ids[_CONSTELLATION]), len(ids[_SOLAR_SYSTEM])))
  224. names = _load_names(sde_dir)
  225. galaxy = _build_galaxy_skeleton(ids, names)
  226. del ids, names
  227. _load_galaxy_associations(sde_dir, galaxy)
  228. _dump_galaxy(out_dir, galaxy)
  229. del galaxy
  230. factions = _load_factions(sde_dir)
  231. _dump_entities(out_dir, factions)
  232. del factions
  233. _compress(out_dir)
  234. _cleanup(out_dir)
  235. def main():
  236. if len(sys.argv) < 2:
  237. print("usage: %s <sde_directory>" % sys.argv[0])
  238. exit(1)
  239. sde_dir = Path(sys.argv[1]).resolve()
  240. out_dir = Path(__file__).resolve().parent.parent / "data" / "universe"
  241. import_sde(sde_dir, out_dir)
  242. if __name__ == "__main__":
  243. main()