From 720f9da2df2c18763f35427628e4df3669adaadd Mon Sep 17 00:00:00 2001 From: Valmo Trindade Date: Thu, 14 May 2026 18:52:40 -0300 Subject: [PATCH] Added Delete CoT handler for removing serverside CoT when a player invokes the clientside connection --- .../server/functions/fnc_startCotRouter.sqf | 23 ++++++++-- src/cot/delete.rs | 45 +++++++++++++++++++ src/cot/mod.rs | 1 + src/lib.rs | 1 + src/tcp/cot.rs | 6 +++ 5 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 src/cot/delete.rs diff --git a/addons/server/functions/fnc_startCotRouter.sqf b/addons/server/functions/fnc_startCotRouter.sqf index d229e5e..690b199 100644 --- a/addons/server/functions/fnc_startCotRouter.sqf +++ b/addons/server/functions/fnc_startCotRouter.sqf @@ -9,21 +9,38 @@ if (isNil { missionNamespace getVariable "armatak_server_syncedUnits" }) then { missionNamespace setVariable ["armatak_server_syncedUnits", []]; }; +if (isNil { missionNamespace getVariable "armatak_server_clientClaimedEuds" }) then { + missionNamespace setVariable ["armatak_server_clientClaimedEuds", []]; +}; + GVAR(syncedUnits) = missionNamespace getVariable "armatak_server_syncedUnits"; [{ GVAR(syncedUnits) = missionNamespace getVariable "armatak_server_syncedUnits"; + private _clientClaimedEuds = missionNamespace getVariable ["armatak_server_clientClaimedEuds", []]; { _objectType = _x call BIS_fnc_objectType; switch (true) do { case ((_objectType select 0) == "Soldier"): { + private _uuid = _x call armatak_fnc_extract_uuid; + private _isClientEud = _x getVariable [QEGVAR(client,eudConnected), false]; + if (_isClientEud) exitWith { + if !(_uuid in _clientClaimedEuds) then { + private _position = _x call armatak_client_fnc_extractClientPosition; + private _deleteCot = [_uuid, "a-f-G-U-C-I", _position select 1, _position select 2, _position select 3]; + "armatak" callExtension ["tcp_socket:cot:delete", [_deleteCot]]; + _clientClaimedEuds pushBack _uuid; + }; + }; + + _clientClaimedEuds = _clientClaimedEuds - [_uuid]; + _callsign = [_x] call armatak_fnc_extract_unit_callsign; _group_name = [group _x] call armatak_fnc_extract_group_color; _group_role = [_x] call armatak_fnc_extract_group_role; [_x, _callsign, _group_name, _group_role] call armatak_fnc_send_eud_cot; - [_x] call armatak_fnc_send_digital_pointer_cot; }; case (unitIsUAV _x): { if !(_x getVariable ["armatak_uav_mavlink_broadcasting", false]) then { @@ -31,7 +48,6 @@ GVAR(syncedUnits) = missionNamespace getVariable "armatak_server_syncedUnits"; _callsign = [_x] call armatak_fnc_extract_marker_callsign; [_x, _atak_type, _callsign] call armatak_fnc_send_drone_cot; - [_x] call armatak_fnc_send_digital_pointer_cot; _x call armatak_fnc_extract_sensor_data; }; }; @@ -48,12 +64,13 @@ GVAR(syncedUnits) = missionNamespace getVariable "armatak_server_syncedUnits"; _callsign = [_x] call armatak_fnc_extract_marker_callsign; [_x, _atak_type, _callsign] call armatak_fnc_send_drone_cot; - [_x] call armatak_fnc_send_digital_pointer_cot; _x call armatak_fnc_extract_sensor_data; }; }; }; } forEach GVAR(syncedUnits); + + missionNamespace setVariable ["armatak_server_clientClaimedEuds", _clientClaimedEuds]; }, 1, []] call CBA_fnc_addPerFrameHandler; true diff --git a/src/cot/delete.rs b/src/cot/delete.rs new file mode 100644 index 0000000..de175ee --- /dev/null +++ b/src/cot/delete.rs @@ -0,0 +1,45 @@ +use arma_rs::{FromArma, FromArmaError}; +use chrono::{Duration, SecondsFormat, Utc}; + +pub struct DeleteCoTPayload { + pub target_uid: String, + pub target_type: String, + pub point_lat: f64, + pub point_lon: f64, + pub point_hae: f32, +} + +impl FromArma for DeleteCoTPayload { + fn from_arma(data: String) -> Result { + let (target_uid, target_type, point_lat, point_lon, point_hae) = + <(String, String, f64, f64, f32)>::from_arma(data)?; + Ok(Self { + target_uid, + target_type, + point_lat, + point_lon, + point_hae, + }) + } +} + +impl DeleteCoTPayload { + pub fn to_xml(&self) -> String { + let created_time = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true); + let stale_time = + (Utc::now() + Duration::seconds(60)).to_rfc3339_opts(SecondsFormat::Millis, true); + + format!( + "<__forcedelete />", + self.target_uid, + created_time, + created_time, + stale_time, + self.point_hae, + self.point_lat, + self.point_lon, + self.target_uid, + self.target_type + ) + } +} diff --git a/src/cot/mod.rs b/src/cot/mod.rs index bcd9100..76a7c55 100644 --- a/src/cot/mod.rs +++ b/src/cot/mod.rs @@ -1,4 +1,5 @@ pub mod cot; +pub mod delete; pub mod digital_pointer; pub mod draws; pub mod eud; diff --git a/src/lib.rs b/src/lib.rs index 6a43b42..d341285 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,6 +78,7 @@ pub fn init() -> Extension { .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("delete", tcp::cot::send_delete_cot) .command("chat", tcp::cot::send_message_cot) .command("uas_platform", tcp::cot::send_uas_platform_cot) .command("uas_video", tcp::cot::send_uas_video_cot) diff --git a/src/tcp/cot.rs b/src/tcp/cot.rs index 5ffc69b..7cba3c7 100644 --- a/src/tcp/cot.rs +++ b/src/tcp/cot.rs @@ -39,6 +39,12 @@ pub fn send_digital_pointer_cot( "Sending Digital Pointer Cursor Over Time to TCP server" } +pub fn send_delete_cot(ctx: Context, payload: cot::delete::DeleteCoTPayload) -> &'static str { + send_payload(ctx, payload.to_xml()); + + "Sending Delete Cursor Over Time to TCP server" +} + pub fn send_message_cot( ctx: Context, message_payload: cot::message::MessagePayload,