From 99f8d991be5e938bc62e2b026c84dcfc1b3df89c Mon Sep 17 00:00:00 2001 From: Valmo Trindade Date: Tue, 5 May 2026 07:48:54 -0300 Subject: [PATCH] Added MavLink mocked drone support as client side feature --- addons/uav/$PBOPREFIX$ | 1 + addons/uav/CfgEventHandlers.hpp | 17 ++++ addons/uav/XEH_PREP.hpp | 3 + addons/uav/XEH_postInit.sqf | 5 + addons/uav/XEH_preInit.sqf | 9 ++ addons/uav/XEH_preStart.sqf | 3 + addons/uav/config.cpp | 20 ++++ .../functions/fnc_startMavlinkBroadcast.sqf | 16 +++ .../functions/fnc_stopMavlinkBroadcast.sqf | 16 +++ .../functions/fnc_updateMavlinkBroadcast.sqf | 97 +++++++++++++++++++ addons/uav/script_component.hpp | 17 ++++ 11 files changed, 204 insertions(+) create mode 100644 addons/uav/$PBOPREFIX$ create mode 100644 addons/uav/CfgEventHandlers.hpp create mode 100644 addons/uav/XEH_PREP.hpp create mode 100644 addons/uav/XEH_postInit.sqf create mode 100644 addons/uav/XEH_preInit.sqf create mode 100644 addons/uav/XEH_preStart.sqf create mode 100644 addons/uav/config.cpp create mode 100644 addons/uav/functions/fnc_startMavlinkBroadcast.sqf create mode 100644 addons/uav/functions/fnc_stopMavlinkBroadcast.sqf create mode 100644 addons/uav/functions/fnc_updateMavlinkBroadcast.sqf create mode 100644 addons/uav/script_component.hpp diff --git a/addons/uav/$PBOPREFIX$ b/addons/uav/$PBOPREFIX$ new file mode 100644 index 0000000..9254ab9 --- /dev/null +++ b/addons/uav/$PBOPREFIX$ @@ -0,0 +1 @@ +armatak\armatak\addons\uav diff --git a/addons/uav/CfgEventHandlers.hpp b/addons/uav/CfgEventHandlers.hpp new file mode 100644 index 0000000..f6503c2 --- /dev/null +++ b/addons/uav/CfgEventHandlers.hpp @@ -0,0 +1,17 @@ +class Extended_PreStart_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_preStart)); + }; +}; + +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_preInit)); + }; +}; + +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_postInit)); + }; +}; diff --git a/addons/uav/XEH_PREP.hpp b/addons/uav/XEH_PREP.hpp new file mode 100644 index 0000000..e7715f6 --- /dev/null +++ b/addons/uav/XEH_PREP.hpp @@ -0,0 +1,3 @@ +PREP(startMavlinkBroadcast); +PREP(stopMavlinkBroadcast); +PREP(updateMavlinkBroadcast); diff --git a/addons/uav/XEH_postInit.sqf b/addons/uav/XEH_postInit.sqf new file mode 100644 index 0000000..ae3d479 --- /dev/null +++ b/addons/uav/XEH_postInit.sqf @@ -0,0 +1,5 @@ +#include "script_component.hpp" + +if (!hasInterface) exitWith {}; + +SETVAR(player,GVAR(mavlinkPFH),-1); diff --git a/addons/uav/XEH_preInit.sqf b/addons/uav/XEH_preInit.sqf new file mode 100644 index 0000000..b47cf66 --- /dev/null +++ b/addons/uav/XEH_preInit.sqf @@ -0,0 +1,9 @@ +#include "script_component.hpp" + +ADDON = false; + +PREP_RECOMPILE_START; +#include "XEH_PREP.hpp" +PREP_RECOMPILE_END; + +ADDON = true; diff --git a/addons/uav/XEH_preStart.sqf b/addons/uav/XEH_preStart.sqf new file mode 100644 index 0000000..0228885 --- /dev/null +++ b/addons/uav/XEH_preStart.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +#include "XEH_PREP.hpp" diff --git a/addons/uav/config.cpp b/addons/uav/config.cpp new file mode 100644 index 0000000..1b2d6a1 --- /dev/null +++ b/addons/uav/config.cpp @@ -0,0 +1,20 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredAddons[] = { + "cba_main", + "ace_main", + "armatak_main", + "armatak_client" + }; + requiredVersion = REQUIRED_VERSION; + author = PROJECT_AUTHOR; + url = "https://github.com/valmojr/armatak"; + }; +}; + +#include "CfgEventHandlers.hpp" diff --git a/addons/uav/functions/fnc_startMavlinkBroadcast.sqf b/addons/uav/functions/fnc_startMavlinkBroadcast.sqf new file mode 100644 index 0000000..6c452c6 --- /dev/null +++ b/addons/uav/functions/fnc_startMavlinkBroadcast.sqf @@ -0,0 +1,16 @@ +#include "..\script_component.hpp" + +if (!hasInterface) exitWith {}; + +private _existingPfh = player getVariable [QGVAR(mavlinkPFH), -1]; +if (_existingPfh >= 0) then { + [_existingPfh] call CBA_fnc_removePerFrameHandler; +}; + +player setVariable [QGVAR(broadcastingUav), objNull]; + +private _pfh = [{ + call FUNC(updateMavlinkBroadcast); +}, 0.5, []] call CBA_fnc_addPerFrameHandler; + +player setVariable [QGVAR(mavlinkPFH), _pfh]; diff --git a/addons/uav/functions/fnc_stopMavlinkBroadcast.sqf b/addons/uav/functions/fnc_stopMavlinkBroadcast.sqf new file mode 100644 index 0000000..837e944 --- /dev/null +++ b/addons/uav/functions/fnc_stopMavlinkBroadcast.sqf @@ -0,0 +1,16 @@ +#include "..\script_component.hpp" + +if (!hasInterface) exitWith {}; + +private _existingPfh = player getVariable [QGVAR(mavlinkPFH), -1]; +if (_existingPfh >= 0) then { + [_existingPfh] call CBA_fnc_removePerFrameHandler; + player setVariable [QGVAR(mavlinkPFH), -1]; +}; + +private _broadcastingUav = player getVariable [QGVAR(broadcastingUav), objNull]; +if (!isNull _broadcastingUav) then { + systemChat "UAV broadcasting stopped"; +}; + +player setVariable [QGVAR(broadcastingUav), objNull]; diff --git a/addons/uav/functions/fnc_updateMavlinkBroadcast.sqf b/addons/uav/functions/fnc_updateMavlinkBroadcast.sqf new file mode 100644 index 0000000..427b697 --- /dev/null +++ b/addons/uav/functions/fnc_updateMavlinkBroadcast.sqf @@ -0,0 +1,97 @@ +#include "..\script_component.hpp" + +if !(player getVariable [QEGVAR(client,eudConnected), false]) exitWith {}; + +private _uav = getConnectedUAV player; +private _broadcastingUav = player getVariable [QGVAR(broadcastingUav), objNull]; + +if (isNull _uav) exitWith { + if (!isNull _broadcastingUav) then { + player setVariable [QGVAR(broadcastingUav), objNull]; + systemChat "UAV broadcasting stopped"; + "armatak" callExtension ["log", [["info", "UAV broadcasting stopped because player is no longer connected to a UAV"]]]; + }; +}; + +if (_broadcastingUav isNotEqualTo _uav) then { + player setVariable [QGVAR(broadcastingUav), _uav]; + private _callsign = [_uav] call armatak_fnc_extract_marker_callsign; + systemChat format ["Broadcasting UAV %1", _callsign]; + "armatak" callExtension ["log", [["info", format ["Broadcasting UAV %1 via MAVLink mock to %2", _callsign, player getVariable [QEGVAR(client,mavlink_address), ""]]]]]; +}; + +private _mavlinkAddress = player getVariable [QEGVAR(client,mavlink_address), ""]; +if (_mavlinkAddress isEqualTo "") exitWith {}; + +private _pos = [_uav] call EFUNC(client,extractClientPosition); +private _dir = vectorDir _uav; +private _up = vectorUp _uav; +private _yaw = getDir _uav; +private _pitch = asin (((_dir select 2) max -1) min 1); +private _roll = asin (((_up select 0) max -1) min 1); +private _relAlt = ((getPosATL _uav) select 2) max 0; +private _uavType = if (_uav isKindOf "Plane") then {1} else {[2, 3] select (_uav isKindOf "Helicopter")}; + +private _bodyPayload = [ + _mavlinkAddress, + 1, + 1, + _uavType, + _pos select 1, + _pos select 2, + _pos select 3, + _relAlt, + _pos select 5, + _pos select 6, + _roll, + _pitch, + _yaw, + parseNumber isEngineOn _uav +]; + +"armatak" callExtension ["mavlink_mock:send_uas_telemetry", [_bodyPayload]]; + +private _laser = laserTarget _uav; +if (!isNull _laser) then { + private _originASL = getPosASL _uav; + private _targetWorld = getPosWorld _laser; + private _targetAslZ = (getPosASL _laser) select 2; + private _spiASL = [_targetWorld select 0, _targetWorld select 1, _targetAslZ]; + + private _los = _spiASL vectorDiff _originASL; + private _losMag = vectorMagnitude _los; + + if (_losMag > 0) then { + _los = _los vectorMultiply (1 / _losMag); + + private _dirX = _los select 0; + private _dirY = _los select 1; + private _dirZ = _los select 2; + private _horizontalMag = sqrt ((_dirX * _dirX) + (_dirY * _dirY)); + + private _camYaw = ((_dirX atan2 _dirY) + 360) mod 360; + private _camPitch = _dirZ atan2 (_horizontalMag max 0.001); + + private _spiAgl = ASLToAGL _spiASL; + private _camRelAlt = (_spiAgl select 2) max 0; + + private _camPayload = [ + _mavlinkAddress, + 2, + 1, + _uavType, + _pos select 1, + _pos select 2, + _pos select 3, + _camRelAlt, + _camYaw, + 0, + 0, + _camPitch, + _camYaw, + 1 + ]; + + "armatak" callExtension ["mavlink_mock:send_uas_telemetry", [_camPayload]]; + }; +}; diff --git a/addons/uav/script_component.hpp b/addons/uav/script_component.hpp new file mode 100644 index 0000000..6dd00bd --- /dev/null +++ b/addons/uav/script_component.hpp @@ -0,0 +1,17 @@ +#define COMPONENT uav +#define COMPONENT_BEAUTIFIED UAV +#include "\armatak\armatak\addons\main\script_mod.hpp" + +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE +// #define ENABLE_PERFORMANCE_COUNTERS + +#ifdef DEBUG_ENABLED_UAV + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_UAV + #define DEBUG_SETTINGS DEBUG_SETTINGS_UAV +#endif + +#include "\z\ace\addons\main\script_macros.hpp"