From 882a35c2cd29e206a815b26769ba71a5ca14ac1f Mon Sep 17 00:00:00 2001 From: Valmo Trindade Date: Mon, 11 May 2026 16:25:52 -0300 Subject: [PATCH] Added report marker functions and stale time param to CoT type --- .../main/functions/api/fn_report_marker.sqf | 95 +++++++++++++++++++ src/cot/cot.rs | 6 +- src/cot/digital_pointer.rs | 2 +- src/cot/eud.rs | 2 +- src/cot/gps.rs | 2 +- src/cot/mod.rs | 1 + src/cot/nato.rs | 1 + src/cot/report_marker.rs | 63 ++++++++++++ src/lib.rs | 2 +- 9 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 addons/main/functions/api/fn_report_marker.sqf create mode 100644 src/cot/report_marker.rs diff --git a/addons/main/functions/api/fn_report_marker.sqf b/addons/main/functions/api/fn_report_marker.sqf new file mode 100644 index 0000000..1e7b2f8 --- /dev/null +++ b/addons/main/functions/api/fn_report_marker.sqf @@ -0,0 +1,95 @@ +// function name: armatak_fnc_report_marker +// function author: Valmo +// function description: Sends a one-shot TAK report marker with an independent stale time. +// +// Arguments: +// 0: Source position or object +// 1: Affiliation or raw CoT type (default: "unknown") +// Supported affiliations: "friendly", "enemy", "hostile", "neutral", "unknown" +// 2: Marker kind (default: "infantry") +// Supported kinds: "infantry", "tank", "car", "apc", "helicopter", "plane", "ship", "static" +// 3: Callsign (default: "Report") +// 4: Remarks (default: "") +// 5: Stale time in seconds (default: 3600) +// +// Example: +// [cursorObject, "enemy", "tank", "Enemy Tank", "Reported enemy tank"] call armatak_fnc_report_marker; +// [screenToWorld [0.5, 0.5], "unknown", "infantry", "Unknown Contact", "Unknown contact reported", 7200] call armatak_fnc_report_marker; +// [cursorObject, "a-h-G-U-C-A-T", "Enemy Tank", "Reported enemy tank", 7200] call armatak_fnc_report_marker; +// +// Public: Yes + +params [ + ["_source", objNull, [objNull, []]], + ["_affiliationOrType", "unknown", [""]], + ["_kindOrCallsign", "infantry", [""]], + ["_callsignOrRemarks", "Report", [""]], + ["_remarksOrStaleSeconds", "", ["", 0]], + ["_staleSeconds", 3600, [0]] +]; + +private _type = ""; +private _callsign = _callsignOrRemarks; +private _remarks = _remarksOrStaleSeconds; + +if ((_affiliationOrType select [0, 2]) isEqualTo "a-") then { + _type = _affiliationOrType; + _callsign = _kindOrCallsign; + _remarks = _callsignOrRemarks; + + if (_remarksOrStaleSeconds isEqualType 0) then { + _staleSeconds = _remarksOrStaleSeconds; + }; +} else { + private _affiliation = switch (toLower _affiliationOrType) do { + case "friendly": {"f"}; + case "enemy": {"h"}; + case "hostile": {"h"}; + case "neutral": {"n"}; + default {"u"}; + }; + + private _kind = switch (toLower _kindOrCallsign) do { + case "tank": {"G-U-C-A-T"}; + case "car": {"G-U-C-I-M"}; + case "apc": {"G-U-C-I-I"}; + case "helicopter": {"A-M-H"}; + case "plane": {"A-M-F"}; + case "ship": {"S"}; + case "static": {"G-U-C-F-M"}; + default {"G-U-C-I"}; + }; + + _type = "a-" + _affiliation + "-" + _kind; + + if (_remarksOrStaleSeconds isEqualType 0) then { + _staleSeconds = _remarksOrStaleSeconds; + _remarks = ""; + }; +}; + +private _position = if (_source isEqualType objNull) then { + getPos _source +} else { + _source +}; + +if ((count _position) < 2) exitWith { + "" +}; + +private _altitude = _position param [2, 0, [0]]; +private _realLocation = [_position select 0, _position select 1, _altitude] call armatak_client_fnc_convertClientLocation; +private _uuid = "armatak" callExtension ["uuid", []] select 0; +private _payload = [ + _uuid, + _type, + _realLocation select 0, + _realLocation select 1, + _realLocation select 2, + _callsign, + _staleSeconds max 1, + _remarks +]; + +"armatak" callExtension ["tcp_socket:cot:report_marker", [_payload]]; diff --git a/src/cot/cot.rs b/src/cot/cot.rs index c214f6f..b2304ae 100644 --- a/src/cot/cot.rs +++ b/src/cot/cot.rs @@ -18,6 +18,7 @@ pub struct CursorOverTime { pub link_uid: Option, pub remarker: Option, pub video_url: Option, + pub stale_seconds: Option, } impl CursorOverTime { @@ -34,8 +35,9 @@ impl CursorOverTime { let created_time = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true); - let stale_time = - (Utc::now() + Duration::seconds(360)).to_rfc3339_opts(SecondsFormat::Millis, true); + let stale_seconds = self.stale_seconds.unwrap_or(360).max(1); + let stale_time = (Utc::now() + Duration::seconds(stale_seconds)) + .to_rfc3339_opts(SecondsFormat::Millis, true); let mut xml = String::new(); diff --git a/src/cot/digital_pointer.rs b/src/cot/digital_pointer.rs index 762bb45..3ad7580 100644 --- a/src/cot/digital_pointer.rs +++ b/src/cot/digital_pointer.rs @@ -41,7 +41,7 @@ impl DigitalPointerPayload { link_uid: Some(self.link_uid.clone()), remarker: None, video_url: None, + stale_seconds: None, } } } - diff --git a/src/cot/eud.rs b/src/cot/eud.rs index 30b5481..71f5735 100644 --- a/src/cot/eud.rs +++ b/src/cot/eud.rs @@ -58,7 +58,7 @@ impl EudCoTPayload { link_uid: None, remarker: None, video_url: None, + stale_seconds: None, } } } - diff --git a/src/cot/gps.rs b/src/cot/gps.rs index 8fad780..5d68102 100644 --- a/src/cot/gps.rs +++ b/src/cot/gps.rs @@ -55,7 +55,7 @@ impl ExternalPositionPayload { link_uid: None, remarker: Some(self.remarker.clone()), video_url: None, + stale_seconds: None, } } } - diff --git a/src/cot/mod.rs b/src/cot/mod.rs index dc732b2..bcd9100 100644 --- a/src/cot/mod.rs +++ b/src/cot/mod.rs @@ -5,5 +5,6 @@ pub mod eud; pub mod gps; pub mod message; pub mod nato; +pub mod report_marker; pub mod uas; pub mod video; diff --git a/src/cot/nato.rs b/src/cot/nato.rs index 515c370..0422af8 100644 --- a/src/cot/nato.rs +++ b/src/cot/nato.rs @@ -87,6 +87,7 @@ impl MarkerCoTPayload { link_uid: None, remarker: None, video_url: self.video_url.clone(), + stale_seconds: None, } } } diff --git a/src/cot/report_marker.rs b/src/cot/report_marker.rs new file mode 100644 index 0000000..7e519c0 --- /dev/null +++ b/src/cot/report_marker.rs @@ -0,0 +1,63 @@ +use arma_rs::{FromArma, FromArmaError}; + +use super::cot::CursorOverTime; + +pub struct ReportMarkerCoTPayload { + pub uuid: String, + pub r#type: String, + pub point_lat: f64, + pub point_lon: f64, + pub point_hae: f32, + pub contact_callsign: String, + pub stale_seconds: i64, + pub remarks: String, +} + +impl FromArma for ReportMarkerCoTPayload { + fn from_arma(data: String) -> Result { + let ( + uuid, + r#type, + point_lat, + point_lon, + point_hae, + contact_callsign, + stale_seconds, + remarks, + ) = <(String, String, f64, f64, f32, String, i64, String)>::from_arma(data)?; + + Ok(Self { + uuid, + r#type, + point_lat, + point_lon, + point_hae, + contact_callsign, + stale_seconds, + remarks, + }) + } +} + +impl ReportMarkerCoTPayload { + pub fn to_cot(&self) -> CursorOverTime { + CursorOverTime { + uuid: Some(self.uuid.clone()), + r#type: Some(self.r#type.clone()), + point_lat: self.point_lat, + point_lon: self.point_lon, + point_hae: self.point_hae, + point_ce: None, + point_le: None, + contact_callsign: self.contact_callsign.clone(), + group_name: None, + group_role: None, + track_course: None, + track_speed: None, + link_uid: None, + remarker: Some(self.remarks.clone()), + video_url: None, + stale_seconds: Some(self.stale_seconds), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index ce21446..6a43b42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ use arma_rs::{arma, Extension, Group}; use rustls::crypto::aws_lc_rs; -mod uas; mod mdns; mod structs; mod tcp; @@ -77,6 +76,7 @@ pub fn init() -> Extension { Group::new() .command("eud", tcp::cot::send_eud_cot) .command("marker", tcp::cot::send_marker_cot) + .command("report_marker", tcp::cot::send_report_marker_cot) .command("digital_pointer", tcp::cot::send_digital_pointer_cot) .command("chat", tcp::cot::send_message_cot) .command("uas_platform", tcp::cot::send_uas_platform_cot)