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.
- package/README.md +79 -0
- package/air-status.js +28 -0
- package/assets/compass.css +647 -0
- package/assets/kcnav/icons/map_common/136.png +0 -0
- package/assets/kcnav/icons/map_common/137.png +0 -0
- package/assets/kcnav/icons/map_common/19.png +0 -0
- package/assets/kcnav/icons/map_main/17.png +0 -0
- package/assets/kcnav/icons/map_main/18.png +0 -0
- package/assets/kcnav/icons/map_main/40.png +0 -0
- package/assets/kcnav/icons/map_main/42.png +0 -0
- package/assets/kcnav/icons/map_main/46.png +0 -0
- package/assets/kcnav/icons/map_main/47.png +0 -0
- package/assets/kcnav/icons/map_main/48.png +0 -0
- package/assets/kcnav/icons/map_main/53.png +0 -0
- package/assets/kcnav/icons/map_main/54.png +0 -0
- package/assets/kcnav/icons/map_main/62.png +0 -0
- package/assets/kcnav/maps/1-1.webp +0 -0
- package/assets/kcnav/maps/1-2.webp +0 -0
- package/assets/kcnav/maps/1-3.webp +0 -0
- package/assets/kcnav/maps/1-4.webp +0 -0
- package/assets/kcnav/maps/1-5.webp +0 -0
- package/assets/kcnav/maps/1-6.webp +0 -0
- package/assets/kcnav/maps/2-1.webp +0 -0
- package/assets/kcnav/maps/2-2.webp +0 -0
- package/assets/kcnav/maps/2-3.webp +0 -0
- package/assets/kcnav/maps/2-4.webp +0 -0
- package/assets/kcnav/maps/2-5.webp +0 -0
- package/assets/kcnav/maps/3-1.webp +0 -0
- package/assets/kcnav/maps/3-2.webp +0 -0
- package/assets/kcnav/maps/3-3.webp +0 -0
- package/assets/kcnav/maps/3-4.webp +0 -0
- package/assets/kcnav/maps/3-5.webp +0 -0
- package/assets/kcnav/maps/4-1.webp +0 -0
- package/assets/kcnav/maps/4-2.webp +0 -0
- package/assets/kcnav/maps/4-3.webp +0 -0
- package/assets/kcnav/maps/4-4.webp +0 -0
- package/assets/kcnav/maps/4-5.webp +0 -0
- package/assets/kcnav/maps/5-1.webp +0 -0
- package/assets/kcnav/maps/5-2.webp +0 -0
- package/assets/kcnav/maps/5-3.webp +0 -0
- package/assets/kcnav/maps/5-4.webp +0 -0
- package/assets/kcnav/maps/5-5.webp +0 -0
- package/assets/kcnav/maps/5-6.webp +0 -0
- package/assets/kcnav/maps/6-1.webp +0 -0
- package/assets/kcnav/maps/6-2.webp +0 -0
- package/assets/kcnav/maps/6-3.webp +0 -0
- package/assets/kcnav/maps/6-4.webp +0 -0
- package/assets/kcnav/maps/6-5.webp +0 -0
- package/assets/kcnav/maps/7-1.webp +0 -0
- package/assets/kcnav/maps/7-2.webp +0 -0
- package/assets/kcnav/maps/7-3.webp +0 -0
- package/assets/kcnav/maps/7-4.webp +0 -0
- package/assets/kcnav/maps/7-5.webp +0 -0
- package/data/kc3kai-master-ids.json +1 -0
- package/data/kc3kai-ship-stats.json +21545 -0
- package/data/kcnav-node-types-by-map.json +606 -0
- package/data/kcnav-node-types.json +176 -0
- package/data/los-config.json +42 -0
- package/data/maps.json +590 -0
- package/data/normal-maps.json +1590 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-1/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-1/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-1/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-2/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-2/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-2/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-2/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-3/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-3/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-3/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-3/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/M.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/N.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/M.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/P.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/O.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/M.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/M.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/N.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/P.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/N.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/N.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/O.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/S.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/T.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/O.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/M.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/N.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/P.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/Q.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/P.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/M.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/N.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/P.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/S.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/A1.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/A2.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/C1.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/C2.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/K1.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/K2.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/N.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/P.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/Q.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/Q1.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/Q2.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/T.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/U.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/V.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/W.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/X.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/Z.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/M.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/N.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/M.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/F.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/I.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/M.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/M.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/N.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/P.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/H.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/M.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/P.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/A.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/B.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/C.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/D.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/E.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/G.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/J.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/K.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/L.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/M.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/N.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/Q.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/R.json +1 -0
- package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/T.json +1 -0
- package/data/sources/kcnav/enemies/manifest.json +2120 -0
- package/data/sources/kcnav/maps/1-1.json +175 -0
- package/data/sources/kcnav/maps/1-2.json +277 -0
- package/data/sources/kcnav/maps/1-3.json +517 -0
- package/data/sources/kcnav/maps/1-4.json +652 -0
- package/data/sources/kcnav/maps/1-5.json +553 -0
- package/data/sources/kcnav/maps/1-6.json +668 -0
- package/data/sources/kcnav/maps/2-1.json +451 -0
- package/data/sources/kcnav/maps/2-2.json +557 -0
- package/data/sources/kcnav/maps/2-3.json +757 -0
- package/data/sources/kcnav/maps/2-4.json +817 -0
- package/data/sources/kcnav/maps/2-5.json +779 -0
- package/data/sources/kcnav/maps/3-1.json +379 -0
- package/data/sources/kcnav/maps/3-2.json +588 -0
- package/data/sources/kcnav/maps/3-3.json +654 -0
- package/data/sources/kcnav/maps/3-4.json +910 -0
- package/data/sources/kcnav/maps/3-5.json +643 -0
- package/data/sources/kcnav/maps/4-1.json +561 -0
- package/data/sources/kcnav/maps/4-2.json +664 -0
- package/data/sources/kcnav/maps/4-3.json +867 -0
- package/data/sources/kcnav/maps/4-4.json +690 -0
- package/data/sources/kcnav/maps/4-5.json +1232 -0
- package/data/sources/kcnav/maps/5-1.json +517 -0
- package/data/sources/kcnav/maps/5-2.json +791 -0
- package/data/sources/kcnav/maps/5-3.json +889 -0
- package/data/sources/kcnav/maps/5-4.json +851 -0
- package/data/sources/kcnav/maps/5-5.json +1070 -0
- package/data/sources/kcnav/maps/5-6.json +3200 -0
- package/data/sources/kcnav/maps/6-1.json +527 -0
- package/data/sources/kcnav/maps/6-2.json +717 -0
- package/data/sources/kcnav/maps/6-3.json +501 -0
- package/data/sources/kcnav/maps/6-4.json +870 -0
- package/data/sources/kcnav/maps/6-5.json +814 -0
- package/data/sources/kcnav/maps/7-1.json +640 -0
- package/data/sources/kcnav/maps/7-2.json +976 -0
- package/data/sources/kcnav/maps/7-3.json +1529 -0
- package/data/sources/kcnav/maps/7-4.json +1000 -0
- package/data/sources/kcnav/maps/7-5.json +1570 -0
- package/data/sources/kcnav/maps/manifest.json +340 -0
- package/data/sources/kcwiki/routes/1-1.wiki +2 -0
- package/data/sources/kcwiki/routes/1-2.wiki +1 -0
- package/data/sources/kcwiki/routes/1-3.wiki +1 -0
- package/data/sources/kcwiki/routes/1-4.wiki +1 -0
- package/data/sources/kcwiki/routes/1-5.wiki +1 -0
- package/data/sources/kcwiki/routes/1-6.wiki +1 -0
- package/data/sources/kcwiki/routes/2-1.wiki +1 -0
- package/data/sources/kcwiki/routes/2-2.wiki +1 -0
- package/data/sources/kcwiki/routes/2-3.wiki +1 -0
- package/data/sources/kcwiki/routes/2-4.wiki +81 -0
- package/data/sources/kcwiki/routes/2-5.wiki +1 -0
- package/data/sources/kcwiki/routes/3-1.wiki +1 -0
- package/data/sources/kcwiki/routes/3-2.wiki +1 -0
- package/data/sources/kcwiki/routes/3-3.wiki +1 -0
- package/data/sources/kcwiki/routes/3-4.wiki +1 -0
- package/data/sources/kcwiki/routes/3-5.wiki +1 -0
- package/data/sources/kcwiki/routes/4-1.wiki +1 -0
- package/data/sources/kcwiki/routes/4-2.wiki +1 -0
- package/data/sources/kcwiki/routes/4-3.wiki +1 -0
- package/data/sources/kcwiki/routes/4-4.wiki +1 -0
- package/data/sources/kcwiki/routes/4-5.wiki +1 -0
- package/data/sources/kcwiki/routes/5-1.wiki +57 -0
- package/data/sources/kcwiki/routes/5-2.wiki +1 -0
- package/data/sources/kcwiki/routes/5-3.wiki +1 -0
- package/data/sources/kcwiki/routes/5-4.wiki +1 -0
- package/data/sources/kcwiki/routes/5-5.wiki +80 -0
- package/data/sources/kcwiki/routes/5-6.wiki +753 -0
- package/data/sources/kcwiki/routes/6-1.wiki +1 -0
- package/data/sources/kcwiki/routes/6-2.wiki +1 -0
- package/data/sources/kcwiki/routes/6-3.wiki +1 -0
- package/data/sources/kcwiki/routes/6-4.wiki +1 -0
- package/data/sources/kcwiki/routes/6-5.wiki +1 -0
- package/data/sources/kcwiki/routes/7-1.wiki +1 -0
- package/data/sources/kcwiki/routes/7-2.wiki +1 -0
- package/data/sources/kcwiki/routes/7-3.wiki +1 -0
- package/data/sources/kcwiki/routes/7-4.wiki +1 -0
- package/data/sources/kcwiki/routes/7-5.wiki +1 -0
- package/data/sources/kcwiki/routes/README.md +11 -0
- package/data/sources/kcwiki/routes/manifest.json +450 -0
- package/docs/research.md +445 -0
- package/docs/sources.md +85 -0
- package/enemies.js +56 -0
- package/exporters.js +182 -0
- package/index.js +1081 -0
- package/logic.js +603 -0
- package/overview.js +54 -0
- package/package.json +66 -0
- package/scripts/cache-kcnav-enemies.js +97 -0
- package/scripts/cache-kcnav-maps.js +109 -0
- package/scripts/cache-kcwiki-routes.js +96 -0
- package/scripts/compact-kcnav-enemies.js +53 -0
- 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 }
|