poi-plugin-compass 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (452) hide show
  1. package/README.md +79 -0
  2. package/air-status.js +28 -0
  3. package/assets/compass.css +647 -0
  4. package/assets/kcnav/icons/map_common/136.png +0 -0
  5. package/assets/kcnav/icons/map_common/137.png +0 -0
  6. package/assets/kcnav/icons/map_common/19.png +0 -0
  7. package/assets/kcnav/icons/map_main/17.png +0 -0
  8. package/assets/kcnav/icons/map_main/18.png +0 -0
  9. package/assets/kcnav/icons/map_main/40.png +0 -0
  10. package/assets/kcnav/icons/map_main/42.png +0 -0
  11. package/assets/kcnav/icons/map_main/46.png +0 -0
  12. package/assets/kcnav/icons/map_main/47.png +0 -0
  13. package/assets/kcnav/icons/map_main/48.png +0 -0
  14. package/assets/kcnav/icons/map_main/53.png +0 -0
  15. package/assets/kcnav/icons/map_main/54.png +0 -0
  16. package/assets/kcnav/icons/map_main/62.png +0 -0
  17. package/assets/kcnav/maps/1-1.webp +0 -0
  18. package/assets/kcnav/maps/1-2.webp +0 -0
  19. package/assets/kcnav/maps/1-3.webp +0 -0
  20. package/assets/kcnav/maps/1-4.webp +0 -0
  21. package/assets/kcnav/maps/1-5.webp +0 -0
  22. package/assets/kcnav/maps/1-6.webp +0 -0
  23. package/assets/kcnav/maps/2-1.webp +0 -0
  24. package/assets/kcnav/maps/2-2.webp +0 -0
  25. package/assets/kcnav/maps/2-3.webp +0 -0
  26. package/assets/kcnav/maps/2-4.webp +0 -0
  27. package/assets/kcnav/maps/2-5.webp +0 -0
  28. package/assets/kcnav/maps/3-1.webp +0 -0
  29. package/assets/kcnav/maps/3-2.webp +0 -0
  30. package/assets/kcnav/maps/3-3.webp +0 -0
  31. package/assets/kcnav/maps/3-4.webp +0 -0
  32. package/assets/kcnav/maps/3-5.webp +0 -0
  33. package/assets/kcnav/maps/4-1.webp +0 -0
  34. package/assets/kcnav/maps/4-2.webp +0 -0
  35. package/assets/kcnav/maps/4-3.webp +0 -0
  36. package/assets/kcnav/maps/4-4.webp +0 -0
  37. package/assets/kcnav/maps/4-5.webp +0 -0
  38. package/assets/kcnav/maps/5-1.webp +0 -0
  39. package/assets/kcnav/maps/5-2.webp +0 -0
  40. package/assets/kcnav/maps/5-3.webp +0 -0
  41. package/assets/kcnav/maps/5-4.webp +0 -0
  42. package/assets/kcnav/maps/5-5.webp +0 -0
  43. package/assets/kcnav/maps/5-6.webp +0 -0
  44. package/assets/kcnav/maps/6-1.webp +0 -0
  45. package/assets/kcnav/maps/6-2.webp +0 -0
  46. package/assets/kcnav/maps/6-3.webp +0 -0
  47. package/assets/kcnav/maps/6-4.webp +0 -0
  48. package/assets/kcnav/maps/6-5.webp +0 -0
  49. package/assets/kcnav/maps/7-1.webp +0 -0
  50. package/assets/kcnav/maps/7-2.webp +0 -0
  51. package/assets/kcnav/maps/7-3.webp +0 -0
  52. package/assets/kcnav/maps/7-4.webp +0 -0
  53. package/assets/kcnav/maps/7-5.webp +0 -0
  54. package/data/kc3kai-master-ids.json +1 -0
  55. package/data/kc3kai-ship-stats.json +21545 -0
  56. package/data/kcnav-node-types-by-map.json +606 -0
  57. package/data/kcnav-node-types.json +176 -0
  58. package/data/los-config.json +42 -0
  59. package/data/maps.json +590 -0
  60. package/data/normal-maps.json +1590 -0
  61. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-1/A.json +1 -0
  62. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-1/B.json +1 -0
  63. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-1/C.json +1 -0
  64. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-2/A.json +1 -0
  65. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-2/C.json +1 -0
  66. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-2/D.json +1 -0
  67. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-2/E.json +1 -0
  68. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-3/C.json +1 -0
  69. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-3/E.json +1 -0
  70. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-3/F.json +1 -0
  71. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-3/J.json +1 -0
  72. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/B.json +1 -0
  73. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/D.json +1 -0
  74. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/H.json +1 -0
  75. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/I.json +1 -0
  76. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/J.json +1 -0
  77. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/L.json +1 -0
  78. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/A.json +1 -0
  79. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/C.json +1 -0
  80. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/D.json +1 -0
  81. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/E.json +1 -0
  82. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/F.json +1 -0
  83. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/H.json +1 -0
  84. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/I.json +1 -0
  85. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/J.json +1 -0
  86. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/B.json +1 -0
  87. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/C.json +1 -0
  88. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/D.json +1 -0
  89. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/E.json +1 -0
  90. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/F.json +1 -0
  91. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/I.json +1 -0
  92. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/J.json +1 -0
  93. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/K.json +1 -0
  94. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/L.json +1 -0
  95. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/A.json +1 -0
  96. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/C.json +1 -0
  97. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/D.json +1 -0
  98. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/F.json +1 -0
  99. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/H.json +1 -0
  100. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/B.json +1 -0
  101. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/D.json +1 -0
  102. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/E.json +1 -0
  103. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/G.json +1 -0
  104. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/K.json +1 -0
  105. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/A.json +1 -0
  106. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/E.json +1 -0
  107. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/F.json +1 -0
  108. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/J.json +1 -0
  109. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/K.json +1 -0
  110. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/M.json +1 -0
  111. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/N.json +1 -0
  112. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/B.json +1 -0
  113. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/E.json +1 -0
  114. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/F.json +1 -0
  115. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/I.json +1 -0
  116. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/L.json +1 -0
  117. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/M.json +1 -0
  118. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/P.json +1 -0
  119. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/B.json +1 -0
  120. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/C.json +1 -0
  121. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/E.json +1 -0
  122. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/F.json +1 -0
  123. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/J.json +1 -0
  124. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/L.json +1 -0
  125. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/O.json +1 -0
  126. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/B.json +1 -0
  127. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/C.json +1 -0
  128. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/D.json +1 -0
  129. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/F.json +1 -0
  130. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/G.json +1 -0
  131. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/A.json +1 -0
  132. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/C.json +1 -0
  133. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/H.json +1 -0
  134. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/J.json +1 -0
  135. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/K.json +1 -0
  136. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/L.json +1 -0
  137. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/A.json +1 -0
  138. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/B.json +1 -0
  139. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/E.json +1 -0
  140. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/G.json +1 -0
  141. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/K.json +1 -0
  142. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/M.json +1 -0
  143. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/A.json +1 -0
  144. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/B.json +1 -0
  145. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/C.json +1 -0
  146. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/G.json +1 -0
  147. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/H.json +1 -0
  148. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/I.json +1 -0
  149. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/M.json +1 -0
  150. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/N.json +1 -0
  151. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/P.json +1 -0
  152. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/B.json +1 -0
  153. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/D.json +1 -0
  154. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/E.json +1 -0
  155. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/F.json +1 -0
  156. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/G.json +1 -0
  157. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/H.json +1 -0
  158. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/K.json +1 -0
  159. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/A.json +1 -0
  160. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/C.json +1 -0
  161. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/D.json +1 -0
  162. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/E.json +1 -0
  163. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/G.json +1 -0
  164. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/H.json +1 -0
  165. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/J.json +1 -0
  166. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/A.json +1 -0
  167. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/B.json +1 -0
  168. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/C.json +1 -0
  169. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/D.json +1 -0
  170. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/E.json +1 -0
  171. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/G.json +1 -0
  172. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/H.json +1 -0
  173. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/L.json +1 -0
  174. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/A.json +1 -0
  175. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/C.json +1 -0
  176. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/D.json +1 -0
  177. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/F.json +1 -0
  178. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/G.json +1 -0
  179. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/H.json +1 -0
  180. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/I.json +1 -0
  181. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/L.json +1 -0
  182. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/N.json +1 -0
  183. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/A.json +1 -0
  184. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/B.json +1 -0
  185. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/E.json +1 -0
  186. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/F.json +1 -0
  187. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/G.json +1 -0
  188. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/H.json +1 -0
  189. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/I.json +1 -0
  190. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/K.json +1 -0
  191. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/B.json +1 -0
  192. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/D.json +1 -0
  193. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/E.json +1 -0
  194. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/F.json +1 -0
  195. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/G.json +1 -0
  196. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/H.json +1 -0
  197. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/J.json +1 -0
  198. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/K.json +1 -0
  199. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/N.json +1 -0
  200. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/O.json +1 -0
  201. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/S.json +1 -0
  202. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/T.json +1 -0
  203. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/B.json +1 -0
  204. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/D.json +1 -0
  205. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/E.json +1 -0
  206. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/F.json +1 -0
  207. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/G.json +1 -0
  208. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/J.json +1 -0
  209. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/C.json +1 -0
  210. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/D.json +1 -0
  211. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/E.json +1 -0
  212. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/F.json +1 -0
  213. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/I.json +1 -0
  214. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/K.json +1 -0
  215. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/L.json +1 -0
  216. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/O.json +1 -0
  217. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/C.json +1 -0
  218. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/I.json +1 -0
  219. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/J.json +1 -0
  220. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/K.json +1 -0
  221. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/M.json +1 -0
  222. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/N.json +1 -0
  223. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/P.json +1 -0
  224. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/Q.json +1 -0
  225. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/C.json +1 -0
  226. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/E.json +1 -0
  227. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/F.json +1 -0
  228. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/G.json +1 -0
  229. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/H.json +1 -0
  230. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/J.json +1 -0
  231. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/L.json +1 -0
  232. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/P.json +1 -0
  233. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/B.json +1 -0
  234. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/C.json +1 -0
  235. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/G.json +1 -0
  236. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/H.json +1 -0
  237. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/J.json +1 -0
  238. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/K.json +1 -0
  239. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/M.json +1 -0
  240. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/N.json +1 -0
  241. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/P.json +1 -0
  242. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/S.json +1 -0
  243. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/A.json +1 -0
  244. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/A1.json +1 -0
  245. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/A2.json +1 -0
  246. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/B.json +1 -0
  247. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/C.json +1 -0
  248. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/C1.json +1 -0
  249. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/C2.json +1 -0
  250. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/D.json +1 -0
  251. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/G.json +1 -0
  252. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/H.json +1 -0
  253. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/J.json +1 -0
  254. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/K.json +1 -0
  255. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/K1.json +1 -0
  256. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/K2.json +1 -0
  257. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/L.json +1 -0
  258. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/N.json +1 -0
  259. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/P.json +1 -0
  260. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/Q.json +1 -0
  261. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/Q1.json +1 -0
  262. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/Q2.json +1 -0
  263. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/T.json +1 -0
  264. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/U.json +1 -0
  265. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/V.json +1 -0
  266. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/W.json +1 -0
  267. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/X.json +1 -0
  268. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/Z.json +1 -0
  269. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/C.json +1 -0
  270. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/D.json +1 -0
  271. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/F.json +1 -0
  272. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/H.json +1 -0
  273. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/I.json +1 -0
  274. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/J.json +1 -0
  275. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/K.json +1 -0
  276. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/B.json +1 -0
  277. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/C.json +1 -0
  278. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/F.json +1 -0
  279. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/H.json +1 -0
  280. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/I.json +1 -0
  281. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/J.json +1 -0
  282. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/K.json +1 -0
  283. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/B.json +1 -0
  284. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/C.json +1 -0
  285. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/D.json +1 -0
  286. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/E.json +1 -0
  287. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/F.json +1 -0
  288. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/J.json +1 -0
  289. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/A.json +1 -0
  290. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/B.json +1 -0
  291. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/C.json +1 -0
  292. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/D.json +1 -0
  293. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/E.json +1 -0
  294. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/F.json +1 -0
  295. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/G.json +1 -0
  296. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/H.json +1 -0
  297. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/I.json +1 -0
  298. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/J.json +1 -0
  299. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/K.json +1 -0
  300. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/L.json +1 -0
  301. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/M.json +1 -0
  302. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/N.json +1 -0
  303. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/A.json +1 -0
  304. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/B.json +1 -0
  305. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/C.json +1 -0
  306. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/D.json +1 -0
  307. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/E.json +1 -0
  308. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/F.json +1 -0
  309. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/G.json +1 -0
  310. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/H.json +1 -0
  311. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/I.json +1 -0
  312. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/J.json +1 -0
  313. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/M.json +1 -0
  314. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/B.json +1 -0
  315. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/C.json +1 -0
  316. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/D.json +1 -0
  317. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/F.json +1 -0
  318. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/G.json +1 -0
  319. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/H.json +1 -0
  320. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/K.json +1 -0
  321. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/B.json +1 -0
  322. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/C.json +1 -0
  323. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/E.json +1 -0
  324. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/G.json +1 -0
  325. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/H.json +1 -0
  326. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/I.json +1 -0
  327. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/J.json +1 -0
  328. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/M.json +1 -0
  329. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/B.json +1 -0
  330. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/C.json +1 -0
  331. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/D.json +1 -0
  332. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/E.json +1 -0
  333. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/J.json +1 -0
  334. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/M.json +1 -0
  335. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/N.json +1 -0
  336. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/P.json +1 -0
  337. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/B.json +1 -0
  338. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/C.json +1 -0
  339. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/D.json +1 -0
  340. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/E.json +1 -0
  341. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/G.json +1 -0
  342. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/H.json +1 -0
  343. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/J.json +1 -0
  344. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/K.json +1 -0
  345. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/L.json +1 -0
  346. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/M.json +1 -0
  347. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/P.json +1 -0
  348. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/A.json +1 -0
  349. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/B.json +1 -0
  350. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/C.json +1 -0
  351. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/D.json +1 -0
  352. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/E.json +1 -0
  353. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/G.json +1 -0
  354. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/J.json +1 -0
  355. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/K.json +1 -0
  356. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/L.json +1 -0
  357. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/M.json +1 -0
  358. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/N.json +1 -0
  359. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/Q.json +1 -0
  360. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/R.json +1 -0
  361. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/T.json +1 -0
  362. package/data/sources/kcnav/enemies/manifest.json +2120 -0
  363. package/data/sources/kcnav/maps/1-1.json +175 -0
  364. package/data/sources/kcnav/maps/1-2.json +277 -0
  365. package/data/sources/kcnav/maps/1-3.json +517 -0
  366. package/data/sources/kcnav/maps/1-4.json +652 -0
  367. package/data/sources/kcnav/maps/1-5.json +553 -0
  368. package/data/sources/kcnav/maps/1-6.json +668 -0
  369. package/data/sources/kcnav/maps/2-1.json +451 -0
  370. package/data/sources/kcnav/maps/2-2.json +557 -0
  371. package/data/sources/kcnav/maps/2-3.json +757 -0
  372. package/data/sources/kcnav/maps/2-4.json +817 -0
  373. package/data/sources/kcnav/maps/2-5.json +779 -0
  374. package/data/sources/kcnav/maps/3-1.json +379 -0
  375. package/data/sources/kcnav/maps/3-2.json +588 -0
  376. package/data/sources/kcnav/maps/3-3.json +654 -0
  377. package/data/sources/kcnav/maps/3-4.json +910 -0
  378. package/data/sources/kcnav/maps/3-5.json +643 -0
  379. package/data/sources/kcnav/maps/4-1.json +561 -0
  380. package/data/sources/kcnav/maps/4-2.json +664 -0
  381. package/data/sources/kcnav/maps/4-3.json +867 -0
  382. package/data/sources/kcnav/maps/4-4.json +690 -0
  383. package/data/sources/kcnav/maps/4-5.json +1232 -0
  384. package/data/sources/kcnav/maps/5-1.json +517 -0
  385. package/data/sources/kcnav/maps/5-2.json +791 -0
  386. package/data/sources/kcnav/maps/5-3.json +889 -0
  387. package/data/sources/kcnav/maps/5-4.json +851 -0
  388. package/data/sources/kcnav/maps/5-5.json +1070 -0
  389. package/data/sources/kcnav/maps/5-6.json +3200 -0
  390. package/data/sources/kcnav/maps/6-1.json +527 -0
  391. package/data/sources/kcnav/maps/6-2.json +717 -0
  392. package/data/sources/kcnav/maps/6-3.json +501 -0
  393. package/data/sources/kcnav/maps/6-4.json +870 -0
  394. package/data/sources/kcnav/maps/6-5.json +814 -0
  395. package/data/sources/kcnav/maps/7-1.json +640 -0
  396. package/data/sources/kcnav/maps/7-2.json +976 -0
  397. package/data/sources/kcnav/maps/7-3.json +1529 -0
  398. package/data/sources/kcnav/maps/7-4.json +1000 -0
  399. package/data/sources/kcnav/maps/7-5.json +1570 -0
  400. package/data/sources/kcnav/maps/manifest.json +340 -0
  401. package/data/sources/kcwiki/routes/1-1.wiki +2 -0
  402. package/data/sources/kcwiki/routes/1-2.wiki +1 -0
  403. package/data/sources/kcwiki/routes/1-3.wiki +1 -0
  404. package/data/sources/kcwiki/routes/1-4.wiki +1 -0
  405. package/data/sources/kcwiki/routes/1-5.wiki +1 -0
  406. package/data/sources/kcwiki/routes/1-6.wiki +1 -0
  407. package/data/sources/kcwiki/routes/2-1.wiki +1 -0
  408. package/data/sources/kcwiki/routes/2-2.wiki +1 -0
  409. package/data/sources/kcwiki/routes/2-3.wiki +1 -0
  410. package/data/sources/kcwiki/routes/2-4.wiki +81 -0
  411. package/data/sources/kcwiki/routes/2-5.wiki +1 -0
  412. package/data/sources/kcwiki/routes/3-1.wiki +1 -0
  413. package/data/sources/kcwiki/routes/3-2.wiki +1 -0
  414. package/data/sources/kcwiki/routes/3-3.wiki +1 -0
  415. package/data/sources/kcwiki/routes/3-4.wiki +1 -0
  416. package/data/sources/kcwiki/routes/3-5.wiki +1 -0
  417. package/data/sources/kcwiki/routes/4-1.wiki +1 -0
  418. package/data/sources/kcwiki/routes/4-2.wiki +1 -0
  419. package/data/sources/kcwiki/routes/4-3.wiki +1 -0
  420. package/data/sources/kcwiki/routes/4-4.wiki +1 -0
  421. package/data/sources/kcwiki/routes/4-5.wiki +1 -0
  422. package/data/sources/kcwiki/routes/5-1.wiki +57 -0
  423. package/data/sources/kcwiki/routes/5-2.wiki +1 -0
  424. package/data/sources/kcwiki/routes/5-3.wiki +1 -0
  425. package/data/sources/kcwiki/routes/5-4.wiki +1 -0
  426. package/data/sources/kcwiki/routes/5-5.wiki +80 -0
  427. package/data/sources/kcwiki/routes/5-6.wiki +753 -0
  428. package/data/sources/kcwiki/routes/6-1.wiki +1 -0
  429. package/data/sources/kcwiki/routes/6-2.wiki +1 -0
  430. package/data/sources/kcwiki/routes/6-3.wiki +1 -0
  431. package/data/sources/kcwiki/routes/6-4.wiki +1 -0
  432. package/data/sources/kcwiki/routes/6-5.wiki +1 -0
  433. package/data/sources/kcwiki/routes/7-1.wiki +1 -0
  434. package/data/sources/kcwiki/routes/7-2.wiki +1 -0
  435. package/data/sources/kcwiki/routes/7-3.wiki +1 -0
  436. package/data/sources/kcwiki/routes/7-4.wiki +1 -0
  437. package/data/sources/kcwiki/routes/7-5.wiki +1 -0
  438. package/data/sources/kcwiki/routes/README.md +11 -0
  439. package/data/sources/kcwiki/routes/manifest.json +450 -0
  440. package/docs/research.md +445 -0
  441. package/docs/sources.md +85 -0
  442. package/enemies.js +56 -0
  443. package/exporters.js +182 -0
  444. package/index.js +1081 -0
  445. package/logic.js +603 -0
  446. package/overview.js +54 -0
  447. package/package.json +66 -0
  448. package/scripts/cache-kcnav-enemies.js +97 -0
  449. package/scripts/cache-kcnav-maps.js +109 -0
  450. package/scripts/cache-kcwiki-routes.js +96 -0
  451. package/scripts/compact-kcnav-enemies.js +53 -0
  452. package/scripts/compress-kcnav-maps.js +90 -0
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "poi-plugin-compass",
3
+ "version": "0.1.0",
4
+ "description": "通常海域舰队罗盘",
5
+ "main": "index.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/RikaKagurasaka/poi-plugin-compass.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/RikaKagurasaka/poi-plugin-compass/issues"
12
+ },
13
+ "homepage": "https://github.com/RikaKagurasaka/poi-plugin-compass#readme",
14
+ "files": [
15
+ "index.js",
16
+ "logic.js",
17
+ "enemies.js",
18
+ "exporters.js",
19
+ "overview.js",
20
+ "air-status.js",
21
+ "data",
22
+ "assets",
23
+ "scripts",
24
+ "README.md",
25
+ "docs"
26
+ ],
27
+ "scripts": {
28
+ "cache:kcwiki": "node scripts/cache-kcwiki-routes.js",
29
+ "cache:kcnav-maps": "node scripts/cache-kcnav-maps.js",
30
+ "cache:kcnav-enemies": "node scripts/cache-kcnav-enemies.js",
31
+ "compress:kcnav-maps": "node scripts/compress-kcnav-maps.js --remove-png",
32
+ "compress:kcnav-enemies": "node scripts/compact-kcnav-enemies.js",
33
+ "check:syntax": "node --check index.js && node --check logic.js && node --check enemies.js && node --check exporters.js && node --check scripts/cache-kcnav-enemies.js && node --check scripts/compress-kcnav-maps.js && node --check scripts/compact-kcnav-enemies.js && node --check test.js && node --check test-enemies.js && node --check test-exporters.js",
34
+ "test": "node test.js && node test-enemies.js && node test-exporters.js && node test-ui.js && node test-overview.js"
35
+ },
36
+ "keywords": [
37
+ "poi-plugin",
38
+ "kancolle",
39
+ "compass",
40
+ "routing"
41
+ ],
42
+ "author": {
43
+ "name": "Rika",
44
+ "url": "https://github.com/RikaKagurasaka"
45
+ },
46
+ "license": "MIT",
47
+ "poiPlugin": {
48
+ "id": "compass",
49
+ "title": "舰队罗盘",
50
+ "description": "通常海域地图、带路条件和路线概率",
51
+ "icon": "fa/compass",
52
+ "priority": 20,
53
+ "apiVer": {
54
+ "11.99.99": "0.1.0"
55
+ }
56
+ },
57
+ "peerDependencies": {
58
+ "react": ">=18.0.0"
59
+ },
60
+ "engines": {
61
+ "node": ">=18.0.0"
62
+ },
63
+ "dependencies": {
64
+ "lzma": "2.3.2"
65
+ }
66
+ }
@@ -0,0 +1,97 @@
1
+ 'use strict'
2
+
3
+ const fs = require('fs')
4
+ const path = require('path')
5
+ const crypto = require('crypto')
6
+ const nodeTypes = require('../data/kcnav-node-types-by-map.json')
7
+ const styles = require('../data/kcnav-node-types.json')
8
+ const root = path.join(__dirname, '../data/sources/kcnav/enemies')
9
+
10
+ function monthWindow(now = new Date()) {
11
+ const end = now.toISOString().slice(0, 10)
12
+ const startDate = new Date(`${end}T00:00:00Z`)
13
+ const day = startDate.getUTCDate()
14
+ startDate.setUTCDate(1)
15
+ startDate.setUTCMonth(startDate.getUTCMonth() - 1)
16
+ const lastDay = new Date(Date.UTC(startDate.getUTCFullYear(), startDate.getUTCMonth() + 1, 0)).getUTCDate()
17
+ startDate.setUTCDate(Math.min(day, lastDay))
18
+ return { start: startDate.toISOString().slice(0, 10), end }
19
+ }
20
+
21
+ function enemyUrl(mapId, node, window) {
22
+ const url = new URL(`https://tsunkit.net/api/routing/maps/${mapId}/nodes/${encodeURIComponent(node)}/enemycomps`)
23
+ url.searchParams.set('start', window.start)
24
+ url.searchParams.set('end', window.end)
25
+ return url.toString()
26
+ }
27
+
28
+ function validateResponse(payload) {
29
+ const result = payload?.result
30
+ if (!result || !Array.isArray(result.entries)
31
+ || (result.entryCount != null && result.entryCount !== result.entries.length)) {
32
+ throw new Error('Invalid or incomplete enemy response')
33
+ }
34
+ for (const entry of result.entries) {
35
+ if (!Array.isArray(entry.mainFleet) || !Array.isArray(entry.escortFleet)
36
+ || !Number.isFinite(entry.count) || entry.count < 0
37
+ || [...entry.mainFleet, ...entry.escortFleet].some((ship) => !Number.isInteger(ship.id))) {
38
+ throw new Error('Invalid enemy composition')
39
+ }
40
+ }
41
+ return result
42
+ }
43
+
44
+ function writeJson(file, value, compact = false) {
45
+ const content = `${JSON.stringify(value, null, compact ? 0 : 2)}\n`
46
+ fs.mkdirSync(path.dirname(file), { recursive: true })
47
+ fs.writeFileSync(`${file}.tmp`, content)
48
+ fs.renameSync(`${file}.tmp`, file)
49
+ return crypto.createHash('sha256').update(content).digest('hex')
50
+ }
51
+
52
+ async function main() {
53
+ const manifestPath = path.join(root, 'manifest.json')
54
+ const previous = fs.existsSync(manifestPath) ? JSON.parse(fs.readFileSync(manifestPath, 'utf8')) : null
55
+ // Resume the same window even across midnight; --refresh explicitly starts a new run.
56
+ const window = previous && !previous.complete && !process.argv.includes('--refresh')
57
+ ? previous.window : monthWindow()
58
+ const sameWindow = previous && previous.window.start === window.start && previous.window.end === window.end
59
+ const manifest = sameWindow && !process.argv.includes('--refresh') ? previous : {
60
+ source: 'KCNav', window, intervalMs: 15000, complete: false, nodes: {},
61
+ }
62
+ const targets = Object.entries(nodeTypes).sort(([a], [b]) => a.localeCompare(b, undefined, { numeric: true }))
63
+ .flatMap(([mapId, nodes]) => Object.entries(nodes)
64
+ .filter(([, type]) => styles[type]?.hasEnemies)
65
+ .map(([node]) => ({ mapId, node })))
66
+ manifest.targetCount = targets.length
67
+ writeJson(manifestPath, manifest)
68
+ for (const [index, { mapId, node }] of targets.entries()) {
69
+ const key = `${mapId}/${node}`
70
+ const saved = manifest.nodes[key]
71
+ if (saved && fs.existsSync(path.join(root, saved.file))) {
72
+ const hash = crypto.createHash('sha256').update(fs.readFileSync(path.join(root, saved.file))).digest('hex')
73
+ if (hash === saved.sha256) continue
74
+ }
75
+ const wait = Math.max(0, 15000 - (Date.now() - Date.parse(manifest.lastRequestAt || '1970-01-01')))
76
+ if (wait) await new Promise((resolve) => setTimeout(resolve, wait))
77
+ manifest.lastRequestAt = new Date().toISOString()
78
+ manifest.complete = false
79
+ writeJson(manifestPath, manifest)
80
+ const url = enemyUrl(mapId, node, window)
81
+ console.log(`${index + 1}/${targets.length} ${key} ${window.start}..${window.end}`)
82
+ const response = await fetch(url, { signal: AbortSignal.timeout(60000) })
83
+ if (!response.ok) throw new Error(`${key}: HTTP ${response.status}; cache retained, rerun to resume`)
84
+ const payload = await response.json()
85
+ const result = validateResponse(payload)
86
+ const file = `${window.start}_${window.end}/${mapId}/${node}.json`
87
+ const sha256 = writeJson(path.join(root, file), payload, true)
88
+ manifest.nodes[key] = { file, url, sha256, fetchedAt: new Date().toISOString(), entries: result.entries.length }
89
+ writeJson(manifestPath, manifest)
90
+ }
91
+ manifest.complete = true
92
+ writeJson(manifestPath, manifest)
93
+ console.log(`Cached ${targets.length} enemy nodes`)
94
+ }
95
+
96
+ if (require.main === module) main().catch((error) => { console.error(error.message); process.exitCode = 1 })
97
+ module.exports = { monthWindow, enemyUrl, validateResponse }
@@ -0,0 +1,109 @@
1
+ 'use strict'
2
+
3
+ const crypto = require('crypto')
4
+ const fs = require('fs')
5
+ const path = require('path')
6
+
7
+ const root = path.resolve(__dirname, '..')
8
+ const outputDir = path.join(root, 'data', 'sources', 'kcnav', 'maps')
9
+ const nodeTypesPath = path.join(root, 'data', 'kcnav-node-types-by-map.json')
10
+ const manifestPath = path.join(outputDir, 'manifest.json')
11
+ const catalogs = [
12
+ require(path.join(root, 'data', 'maps.json')),
13
+ require(path.join(root, 'data', 'normal-maps.json')),
14
+ ]
15
+ const mapIds = Array.from(new Set(catalogs.flatMap((catalog) => Object.keys(catalog.maps))))
16
+ .sort((left, right) => left.localeCompare(right, undefined, { numeric: true }))
17
+
18
+ const DEFAULT_INTERVAL_MS = 15_000
19
+
20
+ function apiUrl(mapId) {
21
+ return `https://tsunkit.net/api/routing/maps/${mapId}/`
22
+ }
23
+
24
+ function sleep(milliseconds) {
25
+ return new Promise((resolve) => setTimeout(resolve, milliseconds))
26
+ }
27
+
28
+ function intervalFromArgs() {
29
+ const index = process.argv.indexOf('--interval-ms')
30
+ if (index < 0) return DEFAULT_INTERVAL_MS
31
+ const value = Number(process.argv[index + 1])
32
+ return Number.isFinite(value) && value >= 0 ? value : DEFAULT_INTERVAL_MS
33
+ }
34
+
35
+ function nodeTypesFromResult(result) {
36
+ const nodeValues = {}
37
+ const spots = result?.spots || {}
38
+ Object.keys(spots).forEach((node) => { nodeValues[node] = -1 })
39
+
40
+ Object.values(spots).forEach((spot) => {
41
+ if (!Array.isArray(spot) || typeof spot[2] !== 'string' || spot[2].toLowerCase() !== 'start') return
42
+ const node = Object.keys(spots).find((key) => spots[key] === spot)
43
+ if (node) nodeValues[node] = 0
44
+ })
45
+
46
+ Object.values(result?.route || {}).forEach((entry) => {
47
+ if (!Array.isArray(entry) || typeof entry[1] !== 'string') return
48
+ const nodeType = Number(entry[2])
49
+ if (Number.isFinite(nodeType)) nodeValues[entry[1]] = nodeType
50
+ })
51
+ return nodeValues
52
+ }
53
+
54
+ function writeJson(filePath, value) {
55
+ fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8')
56
+ }
57
+
58
+ async function fetchMap(mapId) {
59
+ const url = apiUrl(mapId)
60
+ const response = await fetch(url, {
61
+ headers: { 'user-agent': 'poi-plugin-compass-kcnav-cache/0.1' },
62
+ })
63
+ if (!response.ok) throw new Error(`KCNav API ${response.status} for ${mapId}`)
64
+ const payload = await response.json()
65
+ if (!payload?.result || typeof payload.result !== 'object') {
66
+ throw new Error(`KCNav response has no result for ${mapId}`)
67
+ }
68
+ return { url, payload }
69
+ }
70
+
71
+ async function main() {
72
+ const intervalMs = intervalFromArgs()
73
+ fs.mkdirSync(outputDir, { recursive: true })
74
+ const fetchedAt = new Date().toISOString()
75
+ const manifest = []
76
+ const nodeTypesByMap = {}
77
+
78
+ for (const [index, mapId] of mapIds.entries()) {
79
+ if (index > 0) await sleep(intervalMs)
80
+ process.stdout.write(`fetching ${mapId} (${index + 1}/${mapIds.length})\n`)
81
+ const { url, payload } = await fetchMap(mapId)
82
+ const content = `${JSON.stringify(payload, null, 2)}\n`
83
+ const contentFile = `${mapId}.json`
84
+ fs.writeFileSync(path.join(outputDir, contentFile), content, 'utf8')
85
+ nodeTypesByMap[mapId] = nodeTypesFromResult(payload.result)
86
+ manifest.push({
87
+ mapId,
88
+ apiUrl: url,
89
+ contentFile,
90
+ sha256: crypto.createHash('sha256').update(content, 'utf8').digest('hex'),
91
+ nodeCount: Object.keys(payload.result.spots || {}).length,
92
+ nodeTypeCount: Object.keys(nodeTypesByMap[mapId]).length,
93
+ fetchedAt,
94
+ })
95
+ writeJson(manifestPath, { source: 'tsunkit.net', fetchedAt, intervalMs, maps: manifest })
96
+ writeJson(nodeTypesPath, nodeTypesByMap)
97
+ }
98
+
99
+ console.log(`cached ${manifest.length} KCNav maps in ${outputDir}`)
100
+ }
101
+
102
+ if (require.main === module) {
103
+ main().catch((error) => {
104
+ console.error(error.message)
105
+ process.exitCode = 1
106
+ })
107
+ }
108
+
109
+ module.exports = { apiUrl, nodeTypesFromResult, main }
@@ -0,0 +1,96 @@
1
+ 'use strict'
2
+
3
+ const crypto = require('crypto')
4
+ const fs = require('fs')
5
+ const path = require('path')
6
+
7
+ const areaNames = {
8
+ 1: '镇守府海域',
9
+ 2: '南西群岛海域',
10
+ 3: '北方海域',
11
+ 4: '西方海域',
12
+ 5: '南方海域',
13
+ 6: '中部海域',
14
+ 7: '南西海域',
15
+ }
16
+
17
+ const root = path.resolve(__dirname, '..')
18
+ const outputDir = path.join(root, 'data', 'sources', 'kcwiki', 'routes')
19
+ const catalogs = [
20
+ require(path.join(root, 'data', 'maps.json')),
21
+ require(path.join(root, 'data', 'normal-maps.json')),
22
+ ]
23
+ const mapIds = Array.from(new Set(catalogs.flatMap((catalog) => Object.keys(catalog.maps))))
24
+ .sort((left, right) => left.localeCompare(right, undefined, { numeric: true }))
25
+
26
+ function apiUrl(title) {
27
+ const url = new URL('https://zh.kcwiki.cn/api.php')
28
+ url.search = new URLSearchParams({
29
+ action: 'query',
30
+ format: 'json',
31
+ formatversion: '2',
32
+ prop: 'revisions',
33
+ rvprop: 'content|ids|timestamp',
34
+ titles: title,
35
+ }).toString()
36
+ return url
37
+ }
38
+
39
+ function pageTitleForMap(mapId) {
40
+ const [area] = mapId.split('-').map(Number)
41
+ return mapId === '5-6'
42
+ ? `${areaNames[area]}/${mapId}`
43
+ : `${areaNames[area]}/${mapId}/带路条件`
44
+ }
45
+
46
+ async function fetchPage(title) {
47
+ const response = await fetch(apiUrl(title), {
48
+ headers: { 'user-agent': 'poi-plugin-compass-kcwiki-cache/0.1' },
49
+ })
50
+ if (!response.ok) throw new Error(`KCWiki API ${response.status} for ${title}`)
51
+ const payload = await response.json()
52
+ const page = payload?.query?.pages?.[0]
53
+ if (!page || page.missing || !page.revisions?.[0]) throw new Error(`KCWiki page missing: ${title}`)
54
+ const revision = page.revisions[0]
55
+ const content = revision.content ?? revision.slots?.main?.content
56
+ if (typeof content !== 'string') throw new Error(`KCWiki content missing: ${title}`)
57
+ return { page, revision, content }
58
+ }
59
+
60
+ async function main() {
61
+ fs.mkdirSync(outputDir, { recursive: true })
62
+ const fetchedAt = new Date().toISOString()
63
+ const manifest = []
64
+
65
+ for (const mapId of mapIds) {
66
+ const title = pageTitleForMap(mapId)
67
+ const { page, revision, content } = await fetchPage(title)
68
+ const contentFile = `${mapId}.wiki`
69
+ fs.writeFileSync(path.join(outputDir, contentFile), content, 'utf8')
70
+ manifest.push({
71
+ mapId,
72
+ title,
73
+ pageId: page.pageid,
74
+ revisionId: revision.revid,
75
+ revisionTimestamp: revision.timestamp,
76
+ pageUrl: `https://zh.kcwiki.cn/wiki/${encodeURIComponent(title)}`,
77
+ apiUrl: apiUrl(title).toString(),
78
+ contentFile,
79
+ sha256: crypto.createHash('sha256').update(content, 'utf8').digest('hex'),
80
+ fetchedAt,
81
+ })
82
+ await new Promise((resolve) => setTimeout(resolve, 200))
83
+ }
84
+
85
+ fs.writeFileSync(
86
+ path.join(outputDir, 'manifest.json'),
87
+ `${JSON.stringify({ source: 'zh.kcwiki.cn', fetchedAt, maps: manifest }, null, 2)}\n`,
88
+ 'utf8',
89
+ )
90
+ console.log(`cached ${manifest.length} KCWiki route pages in ${outputDir}`)
91
+ }
92
+
93
+ main().catch((error) => {
94
+ console.error(error.message)
95
+ process.exitCode = 1
96
+ })
@@ -0,0 +1,53 @@
1
+ 'use strict'
2
+
3
+ const crypto = require('crypto')
4
+ const fs = require('fs')
5
+ const path = require('path')
6
+
7
+ const root = path.join(__dirname, '../data/sources/kcnav/enemies')
8
+ const manifestPath = path.join(root, 'manifest.json')
9
+
10
+ function compactJson(value) {
11
+ return `${JSON.stringify(value)}\n`
12
+ }
13
+
14
+ function sha256(content) {
15
+ return crypto.createHash('sha256').update(content).digest('hex')
16
+ }
17
+
18
+ function main() {
19
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
20
+ let beforeBytes = 0
21
+ let afterBytes = 0
22
+ let count = 0
23
+ for (const entry of Object.values(manifest.nodes || {})) {
24
+ const file = path.join(root, entry.file)
25
+ const value = JSON.parse(fs.readFileSync(file, 'utf8'))
26
+ const content = compactJson(value)
27
+ const temporary = `${file}.${process.pid}.tmp`
28
+ beforeBytes += fs.statSync(file).size
29
+ fs.writeFileSync(temporary, content)
30
+ fs.renameSync(temporary, file)
31
+ afterBytes += content.length
32
+ entry.sha256 = sha256(content)
33
+ count += 1
34
+ }
35
+ fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`)
36
+ console.log(JSON.stringify({
37
+ files: count,
38
+ beforeBytes,
39
+ afterBytes,
40
+ reductionPercent: Number(((1 - afterBytes / beforeBytes) * 100).toFixed(1)),
41
+ }, null, 2))
42
+ }
43
+
44
+ if (require.main === module) {
45
+ try {
46
+ main()
47
+ } catch (error) {
48
+ console.error(error.message)
49
+ process.exitCode = 1
50
+ }
51
+ }
52
+
53
+ module.exports = { compactJson, main }
@@ -0,0 +1,90 @@
1
+ 'use strict'
2
+
3
+ const fs = require('fs')
4
+ const os = require('os')
5
+ const path = require('path')
6
+ const { execFileSync } = require('child_process')
7
+
8
+ const mapDir = path.join(__dirname, '../assets/kcnav/maps')
9
+
10
+ function commandAvailable(command) {
11
+ try {
12
+ execFileSync(command, ['-version'], { stdio: 'ignore' })
13
+ return true
14
+ } catch (error) {
15
+ return false
16
+ }
17
+ }
18
+
19
+ function optionValue(name, fallback) {
20
+ const index = process.argv.indexOf(name)
21
+ if (index < 0) return fallback
22
+ const value = Number(process.argv[index + 1])
23
+ return Number.isFinite(value) && value >= 0 && value <= 100 ? value : fallback
24
+ }
25
+
26
+ function convert(input, output, quality, tool) {
27
+ const temporary = `${output}.${process.pid}.tmp`
28
+ try {
29
+ if (tool === 'cwebp') {
30
+ execFileSync('cwebp', [
31
+ '-quiet', '-mt', '-m', '4', '-q', String(quality), '-metadata', 'none', input, '-o', temporary,
32
+ ], { stdio: 'inherit' })
33
+ } else {
34
+ execFileSync('ffmpeg', [
35
+ '-y', '-loglevel', 'error', '-i', input, '-map_metadata', '-1',
36
+ '-c:v', 'libwebp', '-q:v', String(quality), '-compression_level', '4', temporary,
37
+ ], { stdio: 'inherit' })
38
+ }
39
+ fs.renameSync(temporary, output)
40
+ } finally {
41
+ if (fs.existsSync(temporary)) fs.unlinkSync(temporary)
42
+ }
43
+ }
44
+
45
+ function main() {
46
+ const quality = optionValue('--quality', 85)
47
+ const removePng = process.argv.includes('--remove-png')
48
+ const tool = commandAvailable('cwebp') ? 'cwebp' : commandAvailable('ffmpeg') ? 'ffmpeg' : null
49
+ if (!tool) throw new Error('需要 cwebp 或 ffmpeg 才能压缩 KCNav 地图')
50
+
51
+ const pngFiles = fs.readdirSync(mapDir).filter((file) => file.endsWith('.png')).sort()
52
+ if (!pngFiles.length) {
53
+ const webpFiles = fs.readdirSync(mapDir).filter((file) => file.endsWith('.webp')).sort()
54
+ console.log(`没有待转换的 PNG 地图;现有 WebP ${webpFiles.length} 张`)
55
+ return
56
+ }
57
+
58
+ let sourceBytes = 0
59
+ let outputBytes = 0
60
+ for (const file of pngFiles) {
61
+ const input = path.join(mapDir, file)
62
+ const output = path.join(mapDir, file.replace(/\.png$/, '.webp'))
63
+ convert(input, output, quality, tool)
64
+ sourceBytes += fs.statSync(input).size
65
+ outputBytes += fs.statSync(output).size
66
+ if (removePng) fs.unlinkSync(input)
67
+ }
68
+
69
+ console.log(JSON.stringify({
70
+ tool,
71
+ quality,
72
+ maps: pngFiles.length,
73
+ sourceBytes,
74
+ outputBytes,
75
+ reductionPercent: Number(((1 - outputBytes / sourceBytes) * 100).toFixed(1)),
76
+ removedPng: removePng,
77
+ tempDirectory: os.tmpdir(),
78
+ }, null, 2))
79
+ }
80
+
81
+ if (require.main === module) {
82
+ try {
83
+ main()
84
+ } catch (error) {
85
+ console.error(error.message)
86
+ process.exitCode = 1
87
+ }
88
+ }
89
+
90
+ module.exports = { main }