Advertisement
sk7z

Untitled

Jul 9th, 2024
51
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.31 KB | None | 0 0
  1. const net = require('net');
  2. const proj4 = require('proj4');
  3. const tac_port = 37564;
  4.  
  5. //クリエ島が神奈川県三浦市の位置になるように位置を調整
  6. let meterX = 356484.821;
  7. let meterY = 3895000.943;
  8.  
  9.  
  10. let start = new Date().getTime()
  11. //explosion idと時間を記録するMap
  12. //idは10000000をベースにインクリメントする
  13. let sendTacviewExplosionMap = new Map();
  14. let sendTacviewVehicleList = [];
  15. let sendExplosionIndex = 10000000;
  16.  
  17. // メートル座標系の定義
  18. const fromProjection = '+proj=utm +zone=54 +ellps=WGS84 +datum=WGS84 +units=m +no_defs';
  19. // 緯度経度の座標系の定義
  20. const toProjection = '+proj=longlat +datum=WGS84 +no_defs';
  21.  
  22. let socketInstance;
  23. let start_date = new Date()
  24. // サーバーの設定
  25. const tac_server = net.createServer((socket) => {
  26. console.log('クライアントが接続しました');
  27.  
  28. // ハンドシェイクに応答
  29. socket.write('XtraLib.Stream.0\n');
  30. socket.write('Tacview.RealTimeTelemetry.0\n');
  31. socket.write('Host test\n');
  32. socket.write('\0');
  33.  
  34. socket.on('data', (data) => {
  35. console.log('クライアントからのデータ:', data.toString());
  36. socketInstance = socket;
  37.  
  38. console.log("データ送信開始")
  39. socket.write('FileType=text/acmi/tacview\n');
  40. socket.write('FileVersion=2.2\n');
  41. const telemetryData = `0,ReferenceTime=${start_date.toISOString()}\n`
  42. socket.write(telemetryData);
  43. console.log(telemetryData);
  44. });
  45.  
  46. socket.on('close', () => {
  47. console.log('接続が閉じられました');
  48. });
  49.  
  50. socket.on('error', (err) => {
  51. console.error('エラーが発生しました:', err.message);
  52. });
  53. });
  54.  
  55. tac_server.listen(tac_port, '0.0.0.0', () => {
  56. console.log(`tacview_serverがport:${tac_port}で待受中`);
  57. });
  58.  
  59. //ストワから受信したデータ
  60. latestJsonData = []
  61. latestJsonData.data = []
  62. //ストワから前回送信したデータ
  63. oldJsonData = []
  64. //WebMAPに送信するデータ 本来は色々やってたデータを渡してるけど サンプルソースなので割愛
  65. sendJsonData = []
  66. sendJsonData.data = []
  67.  
  68.  
  69. let count = 0;
  70.  
  71. setInterval(() => {
  72. //サンプルソースなのでストワから受信したっぽいデータを作成
  73. latestJsonData = []
  74. latestJsonData.data = []
  75. count+= 1;
  76.  
  77. let item = {}
  78. item.g_id = 1; //グループID(ビークルが所属するグループのID)
  79. item.id = 1;//ビークルID ビークルごとに個別のIDを割り当てること
  80. item.x = count;//東に1mずつ動かす
  81. item.y = 0;
  82. item.z = 0;
  83. item.mass = 20000;//重さ(ビークル名取得に使用)
  84. item.pitch_deg = 0;
  85. item.heading_deg = 90;//東向き
  86. item.dmg = 0;//ダメージが発生したときはダメージ量を設定
  87. item.player_list = [];
  88.  
  89. //上記のデータを元にビークル名やチーム名等を設定
  90. item.vehicle_name = "test_jet_A";
  91. item.type = "AirCraft";
  92. item.team = "BLUE";
  93. item.dmg_source_id = 0;
  94. item.dmg_source_name = "";
  95.  
  96. latestJsonData.data.push(item);
  97.  
  98. count+= 10;//東に10mずつ動かす
  99.  
  100. let item_2 = {}
  101. item_2.g_id = 1; //グループID(ビークルが所属するグループのID)
  102. item_2.id = 2;//ビークルID ビークルごとに個別のIDを割り当てること
  103. item_2.x = 0;
  104. item_2.y = count;//北に1mずつずらす
  105. item_2.z = 0;
  106. item_2.pitch_deg = 0;
  107. item_2.heading_deg = 0;//北向き
  108. item_2.dmg = 0;//ダメージが発生したときはダメージ量を設定
  109. item_2.player_list = [];
  110.  
  111. //上記のデータを元にビークル名やチーム名等を設定
  112. item_2.vehicle_name = "test_jet_B";
  113. item_2.type = "AirCraft";
  114. item_2.team = "RED";
  115. item_2.dmg_source_id = 0;
  116. item_2.dmg_source_name = "";
  117.  
  118.  
  119.  
  120. latestJsonData.data.push(item_2);
  121.  
  122. //本来はWebMAPに送信するデータを作成する(ここでは割愛)
  123. sendJsonData = latestJsonData;
  124. //tacViewにデータ送信
  125. sendTelemetryData();
  126.  
  127. //次の受信データが来たときに比較するためにデータをコピー(本来はディープコピーするべきだが、サンプルソースなので割愛)
  128. oldJsonData = sendJsonData;
  129.  
  130. }, 10); // 0.01秒ごとにデータを送信
  131.  
  132.  
  133.  
  134. // テレメトリーデータを送信する関数
  135. function sendTelemetryData() {
  136. if (!socketInstance) {
  137. console.error('クライアントが接続されていません');
  138. return;
  139. }
  140. let telemetryData = '';
  141.  
  142. for (const item of sendJsonData.data) {
  143.  
  144. let result = convertMeterToLatLon(meterX + item.x, meterY + item.y);
  145. let longitude = result.longitude;
  146. let latitude = result.latitude;
  147. let altitude = item.z;
  148. let roll = 0;
  149. let pitch = item.pitch_deg;
  150. let yaw = item.heading_deg;
  151. let vehicle_name = item.vehicle_name;
  152. let pilot
  153. if (item.player_list[0] != null) {
  154. pilot = item.player_list[0];
  155. } else {
  156. pilot = "";
  157. }
  158.  
  159. let type;
  160. let shape;//モデル名(参照 https://github.com/Vyrtuoz/Tacview/tree/master/Database/Default%20Properties)
  161.  
  162. switch (item.type) {
  163. case "AirCraft":
  164. type = "Air+FixedWing";
  165. shape = "FixedWing.F-16.obj"
  166. break;
  167. case "Missile":
  168. type = "Weapon+Missile";
  169. shape = "Missile.AIM-120C.obj"
  170. break;
  171. case "Ship":
  172. //重そうならアーレイバーク、そうでないならスピードボート
  173. if (item.mass > 10000) {
  174. type = "Watercraft.ArleighBurke";
  175. shape = "Watercraft.CG-47.obj"
  176. } else {
  177. type = "Watercraft+SpeedBoat";
  178. shape = "Watercraft.Zodiac.obj"
  179. }
  180. break;
  181. case "Torpedo":
  182. type = "Weapon+Torpedo";
  183. shape = "Core.Torpedo.obj"
  184. break;
  185. case "SubMarine":
  186. type = "Sea+Watercraft+Submarine";
  187. shape = "Watercraft.Ohio.obj"
  188. break;
  189. case "Unknown":
  190. //type = "Unknown";
  191. //何を設定すべきかまだわからない
  192. continue;
  193. }
  194. if (vehicle_name != null && vehicle_name.toLowerCase().includes("decoy")) {
  195. //type = "Decoy";
  196. //何を設定すべきかまだわからない
  197. continue
  198. }
  199. let color;
  200. switch (item.team) {
  201. case "BLUE":
  202. color = "Blue";
  203. break;
  204. case "RED":
  205. color = "Red";
  206. break;
  207. case "YELLOW":
  208. color = "Yellow";
  209. break;
  210. }
  211.  
  212.  
  213.  
  214. telemetryData += `#${(new Date().getTime() - start_date.getTime()) / 1000}\n` +
  215. `0,\n` +
  216. `${item.id},T=${longitude}|${latitude}|${altitude}|${roll}|${pitch}|${yaw},` +
  217. `Type=${type},Name=${vehicle_name},ShortName=${vehicle_name},LongName=${vehicle_name},FullName=${vehicle_name},CallSign=${vehicle_name + "#" + item.id},Pilot=${pilot},Color=${color},Shape=${shape},Parent=${item.g_id},,C\n`;
  218. //sendTacviewVehicleListに存在しない場合、追加
  219. if (!sendTacviewVehicleList.includes(item.id)) {
  220. sendTacviewVehicleList.push(item.id);
  221. }
  222.  
  223. //サンプルソースなのでここは呼ばれない
  224. if (item.dmg > 0) {
  225. //命中判定のイベントログだけど 現状正しい値を渡してない
  226. telemetryData += `#${(new Date().getTime() - start_date.getTime()) / 1000}\n` +
  227. `0,Event=Timeout|SourceId:${item.dmg_source_id}|AmmoType:${item.dmg_source_name}|AmmoCount:1|${item.x}/${item.y}/${item.z}|TargetId:${item.id}|IntendedTarget:Leader|Outcome:damage:${item.dmg}`
  228.  
  229. //爆発のidと時間を記録
  230. sendExplosionIndex++;
  231. sendTacviewExplosionMap.set(sendExplosionIndex, new Date().getTime());
  232. //爆発エフェクトを表示
  233. telemetryData += `#${(new Date().getTime() - start_date.getTime()) / 1000}\n` +
  234. `0,\n` +
  235. `${sendExplosionIndex},T=${longitude}|${latitude}|${altitude}|${roll}|${pitch}|${yaw},` +
  236. `Type=Misc + Explosion,C\n`;
  237. }
  238. }
  239. //爆発エフェクトは勝手に消えないので
  240. //explosionMapを確認して、爆発から3秒以上経過しているものを削除
  241. let newDate = new Date();
  242. for (const [key, value] of sendTacviewExplosionMap) {
  243. if (newDate.getTime() - value > 3000) {
  244. sendTacviewExplosionMap.delete(key);
  245. telemetryData += `#${(new Date().getTime() - start_date.getTime()) / 1000}\n` +
  246. `-${key}`;
  247. }
  248. }
  249.  
  250. //サンプルソースなのでここは呼ばれない
  251. //一つ前の受信データと最新の受信データを比較して 一つ前のデータに存在して最新のデータに存在しないものに対して削除電文を送信
  252. if (oldJsonData != null && oldJsonData.data != null && latestJsonData != null && latestJsonData.data != null) {
  253. for (const oldItem of oldJsonData.data) {
  254. const newItem = latestJsonData.data.find((prev) => prev.id === oldItem.id);
  255. if (!newItem) {
  256. //デストロイベントを記録
  257. telemetryData += `#${(new Date().getTime() - start_date.getTime()) / 1000}\n` +
  258. `0,Event=Destroyed|${oldItem.id}|\n`
  259. //tacviewから該当するIDを削除
  260. telemetryData += `#${(new Date().getTime() - start_date.getTime()) / 1000}\n` +
  261. `-${oldItem.id}\n`;
  262. }
  263. }
  264.  
  265. }
  266. //tacviewに電文送信
  267. socketInstance.write(telemetryData);
  268. console.log(telemetryData);
  269. }
  270.  
  271. // メートル座標を緯度経度に変換する関数
  272. function convertMeterToLatLon(x, y) {
  273. const converted = proj4(fromProjection, toProjection, [x, y]);
  274. return {latitude: converted[1], longitude: converted[0]};
  275. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement