Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- const net = require('net');
- const proj4 = require('proj4');
- const tac_port = 37564;
- //クリエ島が神奈川県三浦市の位置になるように位置を調整
- let meterX = 356484.821;
- let meterY = 3895000.943;
- let start = new Date().getTime()
- //explosion idと時間を記録するMap
- //idは10000000をベースにインクリメントする
- let sendTacviewExplosionMap = new Map();
- let sendTacviewVehicleList = [];
- let sendExplosionIndex = 10000000;
- // メートル座標系の定義
- const fromProjection = '+proj=utm +zone=54 +ellps=WGS84 +datum=WGS84 +units=m +no_defs';
- // 緯度経度の座標系の定義
- const toProjection = '+proj=longlat +datum=WGS84 +no_defs';
- let socketInstance;
- let start_date = new Date()
- // サーバーの設定
- const tac_server = net.createServer((socket) => {
- console.log('クライアントが接続しました');
- // ハンドシェイクに応答
- socket.write('XtraLib.Stream.0\n');
- socket.write('Tacview.RealTimeTelemetry.0\n');
- socket.write('Host test\n');
- socket.write('\0');
- socket.on('data', (data) => {
- console.log('クライアントからのデータ:', data.toString());
- socketInstance = socket;
- console.log("データ送信開始")
- socket.write('FileType=text/acmi/tacview\n');
- socket.write('FileVersion=2.2\n');
- const telemetryData = `0,ReferenceTime=${start_date.toISOString()}\n`
- socket.write(telemetryData);
- console.log(telemetryData);
- });
- socket.on('close', () => {
- console.log('接続が閉じられました');
- });
- socket.on('error', (err) => {
- console.error('エラーが発生しました:', err.message);
- });
- });
- tac_server.listen(tac_port, '0.0.0.0', () => {
- console.log(`tacview_serverがport:${tac_port}で待受中`);
- });
- //ストワから受信したデータ
- latestJsonData = []
- latestJsonData.data = []
- //ストワから前回送信したデータ
- oldJsonData = []
- //WebMAPに送信するデータ 本来は色々やってたデータを渡してるけど サンプルソースなので割愛
- sendJsonData = []
- sendJsonData.data = []
- let count = 0;
- setInterval(() => {
- //サンプルソースなのでストワから受信したっぽいデータを作成
- latestJsonData = []
- latestJsonData.data = []
- count+= 1;
- let item = {}
- item.g_id = 1; //グループID(ビークルが所属するグループのID)
- item.id = 1;//ビークルID ビークルごとに個別のIDを割り当てること
- item.x = count;//東に1mずつ動かす
- item.y = 0;
- item.z = 0;
- item.mass = 20000;//重さ(ビークル名取得に使用)
- item.pitch_deg = 0;
- item.heading_deg = 90;//東向き
- item.dmg = 0;//ダメージが発生したときはダメージ量を設定
- item.player_list = [];
- //上記のデータを元にビークル名やチーム名等を設定
- item.vehicle_name = "test_jet_A";
- item.type = "AirCraft";
- item.team = "BLUE";
- item.dmg_source_id = 0;
- item.dmg_source_name = "";
- latestJsonData.data.push(item);
- count+= 10;//東に10mずつ動かす
- let item_2 = {}
- item_2.g_id = 1; //グループID(ビークルが所属するグループのID)
- item_2.id = 2;//ビークルID ビークルごとに個別のIDを割り当てること
- item_2.x = 0;
- item_2.y = count;//北に1mずつずらす
- item_2.z = 0;
- item_2.pitch_deg = 0;
- item_2.heading_deg = 0;//北向き
- item_2.dmg = 0;//ダメージが発生したときはダメージ量を設定
- item_2.player_list = [];
- //上記のデータを元にビークル名やチーム名等を設定
- item_2.vehicle_name = "test_jet_B";
- item_2.type = "AirCraft";
- item_2.team = "RED";
- item_2.dmg_source_id = 0;
- item_2.dmg_source_name = "";
- latestJsonData.data.push(item_2);
- //本来はWebMAPに送信するデータを作成する(ここでは割愛)
- sendJsonData = latestJsonData;
- //tacViewにデータ送信
- sendTelemetryData();
- //次の受信データが来たときに比較するためにデータをコピー(本来はディープコピーするべきだが、サンプルソースなので割愛)
- oldJsonData = sendJsonData;
- }, 10); // 0.01秒ごとにデータを送信
- // テレメトリーデータを送信する関数
- function sendTelemetryData() {
- if (!socketInstance) {
- console.error('クライアントが接続されていません');
- return;
- }
- let telemetryData = '';
- for (const item of sendJsonData.data) {
- let result = convertMeterToLatLon(meterX + item.x, meterY + item.y);
- let longitude = result.longitude;
- let latitude = result.latitude;
- let altitude = item.z;
- let roll = 0;
- let pitch = item.pitch_deg;
- let yaw = item.heading_deg;
- let vehicle_name = item.vehicle_name;
- let pilot
- if (item.player_list[0] != null) {
- pilot = item.player_list[0];
- } else {
- pilot = "";
- }
- let type;
- let shape;//モデル名(参照 https://github.com/Vyrtuoz/Tacview/tree/master/Database/Default%20Properties)
- switch (item.type) {
- case "AirCraft":
- type = "Air+FixedWing";
- shape = "FixedWing.F-16.obj"
- break;
- case "Missile":
- type = "Weapon+Missile";
- shape = "Missile.AIM-120C.obj"
- break;
- case "Ship":
- //重そうならアーレイバーク、そうでないならスピードボート
- if (item.mass > 10000) {
- type = "Watercraft.ArleighBurke";
- shape = "Watercraft.CG-47.obj"
- } else {
- type = "Watercraft+SpeedBoat";
- shape = "Watercraft.Zodiac.obj"
- }
- break;
- case "Torpedo":
- type = "Weapon+Torpedo";
- shape = "Core.Torpedo.obj"
- break;
- case "SubMarine":
- type = "Sea+Watercraft+Submarine";
- shape = "Watercraft.Ohio.obj"
- break;
- case "Unknown":
- //type = "Unknown";
- //何を設定すべきかまだわからない
- continue;
- }
- if (vehicle_name != null && vehicle_name.toLowerCase().includes("decoy")) {
- //type = "Decoy";
- //何を設定すべきかまだわからない
- continue
- }
- let color;
- switch (item.team) {
- case "BLUE":
- color = "Blue";
- break;
- case "RED":
- color = "Red";
- break;
- case "YELLOW":
- color = "Yellow";
- break;
- }
- telemetryData += `#${(new Date().getTime() - start_date.getTime()) / 1000}\n` +
- `0,\n` +
- `${item.id},T=${longitude}|${latitude}|${altitude}|${roll}|${pitch}|${yaw},` +
- `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`;
- //sendTacviewVehicleListに存在しない場合、追加
- if (!sendTacviewVehicleList.includes(item.id)) {
- sendTacviewVehicleList.push(item.id);
- }
- //サンプルソースなのでここは呼ばれない
- if (item.dmg > 0) {
- //命中判定のイベントログだけど 現状正しい値を渡してない
- telemetryData += `#${(new Date().getTime() - start_date.getTime()) / 1000}\n` +
- `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}`
- //爆発のidと時間を記録
- sendExplosionIndex++;
- sendTacviewExplosionMap.set(sendExplosionIndex, new Date().getTime());
- //爆発エフェクトを表示
- telemetryData += `#${(new Date().getTime() - start_date.getTime()) / 1000}\n` +
- `0,\n` +
- `${sendExplosionIndex},T=${longitude}|${latitude}|${altitude}|${roll}|${pitch}|${yaw},` +
- `Type=Misc + Explosion,C\n`;
- }
- }
- //爆発エフェクトは勝手に消えないので
- //explosionMapを確認して、爆発から3秒以上経過しているものを削除
- let newDate = new Date();
- for (const [key, value] of sendTacviewExplosionMap) {
- if (newDate.getTime() - value > 3000) {
- sendTacviewExplosionMap.delete(key);
- telemetryData += `#${(new Date().getTime() - start_date.getTime()) / 1000}\n` +
- `-${key}`;
- }
- }
- //サンプルソースなのでここは呼ばれない
- //一つ前の受信データと最新の受信データを比較して 一つ前のデータに存在して最新のデータに存在しないものに対して削除電文を送信
- if (oldJsonData != null && oldJsonData.data != null && latestJsonData != null && latestJsonData.data != null) {
- for (const oldItem of oldJsonData.data) {
- const newItem = latestJsonData.data.find((prev) => prev.id === oldItem.id);
- if (!newItem) {
- //デストロイベントを記録
- telemetryData += `#${(new Date().getTime() - start_date.getTime()) / 1000}\n` +
- `0,Event=Destroyed|${oldItem.id}|\n`
- //tacviewから該当するIDを削除
- telemetryData += `#${(new Date().getTime() - start_date.getTime()) / 1000}\n` +
- `-${oldItem.id}\n`;
- }
- }
- }
- //tacviewに電文送信
- socketInstance.write(telemetryData);
- console.log(telemetryData);
- }
- // メートル座標を緯度経度に変換する関数
- function convertMeterToLatLon(x, y) {
- const converted = proj4(fromProjection, toProjection, [x, y]);
- return {latitude: converted[1], longitude: converted[0]};
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement