mirror of
https://github.com/valmojr/armatak.git
synced 2026-06-13 20:53:30 +00:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0340a84e9c | ||
|
|
50cf9b10bd | ||
|
|
6e220e5807 | ||
|
|
c1f61dc4aa | ||
|
|
d8e08b8da8 | ||
|
|
1fee414ff0 | ||
|
|
b41008df8b | ||
|
|
3d775db2cc | ||
|
|
7b5510698e | ||
|
|
3f028b48c8 | ||
|
|
aa7b27ac2e | ||
|
|
2d207965db | ||
|
|
2e2a321006 | ||
|
|
67fa1cfe52 | ||
|
|
730440f4ac | ||
|
|
1d65705aa8 | ||
|
|
f04c0141ef | ||
|
|
e06c199816 | ||
|
|
94c7752844 | ||
|
|
9bdb4770c9 | ||
|
|
98e63a7152 | ||
|
|
3a179ea958 | ||
|
|
af15a44fb6 | ||
|
|
ac18c45bef | ||
|
|
65b8aaebe3 | ||
|
|
b3bd58385e | ||
|
|
29574bc36c | ||
|
|
6208286294 | ||
|
|
2299a3f5c9 | ||
|
|
098de89d95 | ||
|
|
8f7d5425ad | ||
|
|
938f0bcb6a | ||
|
|
577125120d | ||
|
|
5c599877ca | ||
|
|
c1b00cb050 | ||
|
|
319ea9b32a | ||
|
|
eda786931d | ||
|
|
31f7b5178e | ||
|
|
8a6dcff05d | ||
|
|
f2fe8b586c | ||
|
|
bcefc7670f | ||
|
|
12c8781236 | ||
|
|
d81c8fa67b | ||
|
|
6de6a29a09 | ||
|
|
ffcd4feb4e | ||
|
|
39f4936bf7 | ||
|
|
25549cda25 | ||
|
|
5231dae17a | ||
|
|
f669cc1cc0 | ||
|
|
43f1cd3bb2 | ||
|
|
ec9d3693bf | ||
|
|
01efe4e01d | ||
|
|
a997c54170 | ||
|
|
68b0fd1e38 | ||
|
|
9c82832a54 | ||
|
|
d9e7dfe497 | ||
|
|
49afb54b80 | ||
|
|
5d6846c5fa | ||
|
|
9bb4a8feaa | ||
|
|
50b118cbfe | ||
|
|
d11050fcc8 | ||
|
|
3d8baae344 | ||
|
|
1d7cce8409 | ||
|
|
3f4535cf17 | ||
|
|
4412b67d63 | ||
|
|
3128ac0022 | ||
|
|
b230515675 | ||
|
|
ad2f529345 | ||
|
|
162f3c7e7a | ||
|
|
ca4231f669 | ||
|
|
8334ff4be5 | ||
|
|
19907184be | ||
|
|
f2ba112ae4 | ||
|
|
b8bb01e985 |
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,4 +1,5 @@
|
|||||||
**When merged this pull request will:**
|
**When merged this pull request will:**
|
||||||
|
|
||||||
- _Describe what this pull request will do_
|
- _Describe what this pull request will do_
|
||||||
- _Each change in a separate line_
|
- _Each change in a separate line_
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/release_drafter.yaml
vendored
2
.github/workflows/release_drafter.yaml
vendored
@@ -122,7 +122,7 @@ jobs:
|
|||||||
body: |
|
body: |
|
||||||
Changes in this release:
|
Changes in this release:
|
||||||
${{ env.COMMIT_MESSAGES }}
|
${{ env.COMMIT_MESSAGES }}
|
||||||
draft: false
|
draft: true
|
||||||
prerelease: false
|
prerelease: false
|
||||||
- name: Upload Release Asset
|
- name: Upload Release Asset
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ name = "ARMA Team Awareness Kit"
|
|||||||
prefix = "armatak"
|
prefix = "armatak"
|
||||||
|
|
||||||
[version]
|
[version]
|
||||||
build = 9
|
build = 0
|
||||||
major = 0
|
major = 1
|
||||||
minor = 9
|
minor = 1
|
||||||
patch = 9
|
patch = 0
|
||||||
|
|
||||||
git_hash = 0
|
git_hash = 0
|
||||||
|
|
||||||
@@ -47,21 +47,21 @@ workshop = [
|
|||||||
"1231625987", #Debug Console
|
"1231625987", #Debug Console
|
||||||
"751965892", # ACRE2
|
"751965892", # ACRE2
|
||||||
"843577117", # RHSUSAF
|
"843577117", # RHSUSAF
|
||||||
"843425103", # RHSAFRF
|
|
||||||
"843593391", # RHSGREF
|
|
||||||
"735566597", # Project OPFOR
|
|
||||||
"3030830594", # Western Dusk
|
"3030830594", # Western Dusk
|
||||||
"3147473073", # TOTT Core
|
"2268351256", # Tier One Weapons
|
||||||
"3147480843", # TOTT CAG
|
|
||||||
"3147476552", # TOTT Optics
|
|
||||||
"2975268929", # GPNVG
|
|
||||||
"583496184", # CUP Terrains
|
"583496184", # CUP Terrains
|
||||||
"421620913", # Kunduz
|
"583544987", # CUP Maps
|
||||||
"2397360831", # USAF Core
|
"3015795970", # No zoom
|
||||||
"2397376046", # USAF Utility
|
"2941986336", # Hatchet Framework
|
||||||
"2226368165", # USAF AC130
|
"1745501605", # Hatchet H-60 Pack
|
||||||
|
"333310405", # Enhanced Moviments
|
||||||
|
"2034363662", # Enhanced Moviments Rework
|
||||||
|
"2257686620", # Blastcore Murr
|
||||||
|
"3407948300", # JSRS Sound Mod
|
||||||
]
|
]
|
||||||
|
|
||||||
|
mission = "armatak_jtac.Mountains_ACR"
|
||||||
|
|
||||||
parameters = [
|
parameters = [
|
||||||
"-skipIntro",
|
"-skipIntro",
|
||||||
"-noSplash",
|
"-noSplash",
|
||||||
|
|||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -83,7 +83,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "armatak"
|
name = "armatak"
|
||||||
version = "0.9.9"
|
version = "1.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arma-rs",
|
"arma-rs",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "armatak"
|
name = "armatak"
|
||||||
version = "0.9.9"
|
version = "1.0.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
1
addons/client/$PBOPREFIX$
Normal file
1
addons/client/$PBOPREFIX$
Normal file
@@ -0,0 +1 @@
|
|||||||
|
armatak\armatak\addons\client
|
||||||
17
addons/client/CfgEventHandlers.hpp
Normal file
17
addons/client/CfgEventHandlers.hpp
Normal file
@@ -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));
|
||||||
|
};
|
||||||
|
};
|
||||||
2
addons/client/XEH_PREP.hpp
Normal file
2
addons/client/XEH_PREP.hpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
PREP(convertClientLocation);
|
||||||
|
PREP(extractClientPosition);
|
||||||
14
addons/client/XEH_postInit.sqf
Normal file
14
addons/client/XEH_postInit.sqf
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
if (!hasInterface) exitWith {};
|
||||||
|
|
||||||
|
_local_address = "armatak" callExtension ["local_ip", []] select 0;
|
||||||
|
|
||||||
|
"armatak" callExtension ["websocket:start", []];
|
||||||
|
|
||||||
|
SETVAR(player,GVAR(localAddress),_local_address);
|
||||||
|
SETVAR(player,GVAR(eudConnected),false);
|
||||||
|
|
||||||
|
[{
|
||||||
|
"armatak" callExtension ["websocket:location", [player call armatak_client_fnc_extractClientPosition]];
|
||||||
|
}, 1, []] call CBA_fnc_addPerFrameHandler;
|
||||||
9
addons/client/XEH_preInit.sqf
Normal file
9
addons/client/XEH_preInit.sqf
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
ADDON = false;
|
||||||
|
|
||||||
|
PREP_RECOMPILE_START;
|
||||||
|
#include "XEH_PREP.hpp"
|
||||||
|
PREP_RECOMPILE_END;
|
||||||
|
|
||||||
|
ADDON = true;
|
||||||
3
addons/client/XEH_preStart.sqf
Normal file
3
addons/client/XEH_preStart.sqf
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
#include "XEH_PREP.hpp"
|
||||||
19
addons/client/config.cpp
Normal file
19
addons/client/config.cpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
class CfgPatches {
|
||||||
|
class ADDON {
|
||||||
|
name = COMPONENT_NAME;
|
||||||
|
units[] = {};
|
||||||
|
weapons[] = {};
|
||||||
|
requiredAddons[] = {
|
||||||
|
"cba_main",
|
||||||
|
"ace_main",
|
||||||
|
"armatak_main"
|
||||||
|
};
|
||||||
|
requiredVersion = REQUIRED_VERSION;
|
||||||
|
author = PROJECT_AUTHOR;
|
||||||
|
url = "https://github.com/valmojr/armatak";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "CfgEventHandlers.hpp"
|
||||||
@@ -1,3 +1,24 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Valmo Trindade
|
||||||
|
* This function is used to convert the position of a unit to the world world location.
|
||||||
|
*
|
||||||
|
* Argument:
|
||||||
|
* 0: in game latitude <NUMBER> is the latitude of the unit.
|
||||||
|
* 1: in game longitude <NUMBER> is the longitude of the unit.
|
||||||
|
* 2: in game altitude <NUMBER> is the altitude of the unit.
|
||||||
|
* 3: in game bearing <NUMBER> is the bearing of the unit.
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* ARRAY -> [latitude, longitude, altitude, bearing]
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [player] call armatak_client_fnc_convertClientLocation;
|
||||||
|
*
|
||||||
|
* Public: Yes
|
||||||
|
*/
|
||||||
|
|
||||||
params["_latitude", "_longitude", "_altitude"];
|
params["_latitude", "_longitude", "_altitude"];
|
||||||
|
|
||||||
_position = [_latitude, _longitude, _altitude];
|
_position = [_latitude, _longitude, _altitude];
|
||||||
30
addons/client/functions/fnc_extractClientPosition.sqf
Normal file
30
addons/client/functions/fnc_extractClientPosition.sqf
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Valmo Trindade
|
||||||
|
* This function is used to extract the position of a unit and convert it to a format suitable for SIMTAK.
|
||||||
|
*
|
||||||
|
* Argument:
|
||||||
|
* 0: The first argument <OBJECT> is the unit whose position you want to extract.
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* ARRAY -> [latitude, longitude, altitude, bearing]
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [player] call armatak_client_fnc_extractClientPosition;
|
||||||
|
*
|
||||||
|
* Public: Yes
|
||||||
|
*/
|
||||||
|
|
||||||
|
params["_unit"];
|
||||||
|
|
||||||
|
private _location = (getPos _unit) call FUNC(convertClientLocation);
|
||||||
|
|
||||||
|
private _atak_latitude = _location select 0;
|
||||||
|
private _atak_longitude = _location select 1;
|
||||||
|
private _atak_altitude = _location select 2;
|
||||||
|
private _atak_bearing = parseNumber ((getDir _unit) toFixed 0);
|
||||||
|
|
||||||
|
_unit_info = [_atak_latitude,_atak_longitude,_atak_altitude,_atak_bearing];
|
||||||
|
|
||||||
|
_unit_info
|
||||||
17
addons/client/script_component.hpp
Normal file
17
addons/client/script_component.hpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#define COMPONENT client
|
||||||
|
#define COMPONENT_BEAUTIFIED WebSocket Client
|
||||||
|
#include "\armatak\armatak\addons\main\script_mod.hpp"
|
||||||
|
|
||||||
|
// #define DEBUG_MODE_FULL
|
||||||
|
// #define DISABLE_COMPILE_CACHE
|
||||||
|
// #define ENABLE_PERFORMANCE_COUNTERS
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED_CLIENT
|
||||||
|
#define DEBUG_MODE_FULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_SETTINGS_CLIENT
|
||||||
|
#define DEBUG_SETTINGS DEBUG_SETTINGS_CLIENT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "\z\ace\addons\main\script_macros.hpp"
|
||||||
@@ -1 +1 @@
|
|||||||
armatak\armatak\armatak_main
|
armatak\armatak\addons\main
|
||||||
160
addons/main/Cfg3den.hpp
Normal file
160
addons/main/Cfg3den.hpp
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
class Cfg3den {
|
||||||
|
class Object {
|
||||||
|
class AttributeCategories {
|
||||||
|
class armatak_3den_attributes {
|
||||||
|
displayName = "ARMA Team Awareness Kit";
|
||||||
|
class Attributes {
|
||||||
|
class armatak_attribute_unit_callsign {
|
||||||
|
displayName = "Unit Callsign";
|
||||||
|
tooltip = "Unit callsign on TAK";
|
||||||
|
property = "armatak_attribute_unit_callsign";
|
||||||
|
control = "Edit";
|
||||||
|
expression = "_this setVariable ['armatak_attribute_unit_callsign',_value]";
|
||||||
|
defaultValue = "''";
|
||||||
|
condition = "objectBrain";
|
||||||
|
typeName = "STRING";
|
||||||
|
};
|
||||||
|
class armatak_attribute_unit_role {
|
||||||
|
displayName = "Unit Role";
|
||||||
|
tooltip = "Unit role on TAK";
|
||||||
|
property = "armatak_attribute_unit_role";
|
||||||
|
control = "Combo";
|
||||||
|
class Values {
|
||||||
|
class armatak_attribute_unit_role_value_teammember {
|
||||||
|
name = "Team Member";
|
||||||
|
value = "Team Member";
|
||||||
|
default = 1;
|
||||||
|
};
|
||||||
|
class armatak_attribute_unit_role_value_teamleader {
|
||||||
|
name = "Team Leader";
|
||||||
|
value = "Team Lead";
|
||||||
|
};
|
||||||
|
class armatak_attribute_unit_role_value_hq {
|
||||||
|
name = "Headquarters";
|
||||||
|
value = "HQ";
|
||||||
|
};
|
||||||
|
class armatak_attribute_unit_role_value_sniper {
|
||||||
|
name = "Sniper";
|
||||||
|
value = "Sniper";
|
||||||
|
};
|
||||||
|
class armatak_attribute_unit_role_value_medic {
|
||||||
|
name = "Medic";
|
||||||
|
value = "Medic";
|
||||||
|
};
|
||||||
|
class armatak_attribute_unit_role_value_forward_observer {
|
||||||
|
name = "Forward Observer";
|
||||||
|
value = "Forward Observer";
|
||||||
|
};
|
||||||
|
class armatak_attribute_unit_role_value_rto {
|
||||||
|
name = "Radio Telephone Operator";
|
||||||
|
value = "RTO";
|
||||||
|
};
|
||||||
|
class armatak_attribute_unit_role_value_k9 {
|
||||||
|
name = "K9 Operator";
|
||||||
|
value = "K9";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
expression = "_this setVariable ['%s',_value];";
|
||||||
|
unique = 0;
|
||||||
|
condition = "objectBrain";
|
||||||
|
};
|
||||||
|
class armatak_attribute_marker_callsign {
|
||||||
|
displayName = "Marker Callsign";
|
||||||
|
tooltip = "Marker Callsign on TAK";
|
||||||
|
property = "armatak_attribute_marker_callsign";
|
||||||
|
control = "Edit";
|
||||||
|
expression = "_this setVariable ['armatak_attribute_marker_callsign',_value]";
|
||||||
|
defaultValue = "''";
|
||||||
|
condition = "objectVehicle";
|
||||||
|
typeName = "STRING";
|
||||||
|
};
|
||||||
|
class armatak_attribute_marker_type {
|
||||||
|
displayName = "Marker Type";
|
||||||
|
tooltip = "Marker type on TAK";
|
||||||
|
property = "armatak_attribute_marker_type";
|
||||||
|
control = "Edit";
|
||||||
|
expression = "_this setVariable ['armatak_attribute_marker_type',_value]";
|
||||||
|
defaultValue = "''";
|
||||||
|
condition = "objectVehicle";
|
||||||
|
typeName = "STRING";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
class Group {
|
||||||
|
class AttributeCategories {
|
||||||
|
class armatak_3den_group_attributes {
|
||||||
|
displayName = "ARMA Team Awareness Kit";
|
||||||
|
class Attributes {
|
||||||
|
class armatak_attribute_group_color {
|
||||||
|
displayName = "Color";
|
||||||
|
tooltip = "Group on TAK";
|
||||||
|
property = "armatak_attribute_group_color";
|
||||||
|
control = "Combo";
|
||||||
|
class Values {
|
||||||
|
class armatak_attribute_group_color_value_white {
|
||||||
|
name = "White";
|
||||||
|
value = "White";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_yellow {
|
||||||
|
name = "Yellow";
|
||||||
|
value = "Yellow";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_orange {
|
||||||
|
name = "Orange";
|
||||||
|
value = "Orange";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_magenta {
|
||||||
|
name = "Magenta";
|
||||||
|
value = "Magenta";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_red {
|
||||||
|
name = "Red";
|
||||||
|
value = "Red";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_maroon {
|
||||||
|
name = "Maroon";
|
||||||
|
value = "Maroon";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_purple {
|
||||||
|
name = "Purple";
|
||||||
|
value = "Purple";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_darkblue {
|
||||||
|
name = "Dark Blue";
|
||||||
|
value = "DarkBlue";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_blue {
|
||||||
|
name = "Blue";
|
||||||
|
value = "Blue";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_cyan {
|
||||||
|
name = "Cyan";
|
||||||
|
value = "Cyan";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_teal {
|
||||||
|
name = "Teal";
|
||||||
|
value = "Teal";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_green {
|
||||||
|
name = "Green";
|
||||||
|
value = "Green";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_darkgreen {
|
||||||
|
name = "Dark Green";
|
||||||
|
value = "DarkGreen";
|
||||||
|
};
|
||||||
|
class armatak_attribute_group_color_value_brown {
|
||||||
|
name = "Brown";
|
||||||
|
value = "Brown";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
expression = "_this setVariable ['%s',_value];";
|
||||||
|
unique = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
17
addons/main/CfgEventHandlers.hpp
Normal file
17
addons/main/CfgEventHandlers.hpp
Normal file
@@ -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));
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,99 +1,87 @@
|
|||||||
class CfgFunctions {
|
class CfgFunctions {
|
||||||
class armatak {
|
class armatak {
|
||||||
class functions {
|
class functions {
|
||||||
class init {
|
|
||||||
file = "\armatak\armatak\armatak_main\functions\fn_init.sqf";
|
|
||||||
};
|
|
||||||
class video_init {
|
|
||||||
file = "\armatak\armatak\armatak_main\functions\fn_video_init.sqf";
|
|
||||||
};
|
|
||||||
class log_message {
|
|
||||||
file = "\armatak\armatak\armatak_main\functions\fn_log_message.sqf";
|
|
||||||
};
|
|
||||||
class send_digital_pointer_cot {
|
class send_digital_pointer_cot {
|
||||||
file = "\armatak\armatak\armatak_main\functions\api\fn_send_digital_pointer_cot.sqf";
|
file = "\armatak\armatak\addons\main\functions\api\fn_send_digital_pointer_cot.sqf";
|
||||||
};
|
};
|
||||||
class send_drone_cot {
|
class send_drone_cot {
|
||||||
file = "\armatak\armatak\armatak_main\functions\api\fn_send_drone_cot.sqf";
|
file = "\armatak\armatak\addons\main\functions\api\fn_send_drone_cot.sqf";
|
||||||
};
|
};
|
||||||
class send_group_cots {
|
class send_group_cots {
|
||||||
file = "\armatak\armatak\armatak_main\functions\api\fn_send_group_cots.sqf";
|
file = "\armatak\armatak\addons\main\functions\api\fn_send_group_cots.sqf";
|
||||||
};
|
};
|
||||||
class send_human_cot {
|
class send_eud_cot {
|
||||||
file = "\armatak\armatak\armatak_main\functions\api\fn_send_human_cot.sqf";
|
file = "\armatak\armatak\addons\main\functions\api\fn_send_eud_cot.sqf";
|
||||||
};
|
};
|
||||||
class send_marker_cot {
|
class send_marker_cot {
|
||||||
file = "\armatak\armatak\armatak_main\functions\api\fn_send_marker_cot.sqf";
|
file = "\armatak\armatak\addons\main\functions\api\fn_send_marker_cot.sqf";
|
||||||
};
|
};
|
||||||
class send_message_cot {
|
class stop_tcp_socket {
|
||||||
file = "\armatak\armatak\armatak_main\functions\api\fn_send_marker_cot.sqf";
|
file = "\armatak\armatak\addons\main\functions\api\fn_stop_tcp_socket.sqf";
|
||||||
};
|
|
||||||
class extract_callsign {
|
|
||||||
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_callsign.sqf";
|
|
||||||
};
|
};
|
||||||
class extract_group_color {
|
class extract_group_color {
|
||||||
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_group_color.sqf";
|
file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_group_color.sqf";
|
||||||
};
|
};
|
||||||
class extract_group_role {
|
class extract_group_role {
|
||||||
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_group_role.sqf";
|
file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_group_role.sqf";
|
||||||
|
};
|
||||||
|
class extract_marker_callsign {
|
||||||
|
file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_marker_callsign.sqf";
|
||||||
};
|
};
|
||||||
class extract_role {
|
class extract_role {
|
||||||
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_role.sqf";
|
file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_role.sqf";
|
||||||
};
|
};
|
||||||
class extract_position {
|
class extract_unit_callsign {
|
||||||
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_position.sqf";
|
file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_unit_callsign.sqf";
|
||||||
};
|
};
|
||||||
class extract_uuid {
|
class extract_uuid {
|
||||||
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_uuid.sqf";
|
file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_uuid.sqf";
|
||||||
};
|
};
|
||||||
class shorten_name {
|
class shorten_name {
|
||||||
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_shorten_name.sqf";
|
file = "\armatak\armatak\addons\main\functions\extract_data\fn_shorten_name.sqf";
|
||||||
};
|
};
|
||||||
|
|
||||||
class convert_location {
|
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_location.sqf";
|
|
||||||
};
|
|
||||||
class convert_to_altis {
|
class convert_to_altis {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_altis.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_altis.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_bukovina {
|
class convert_to_bukovina {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_bukovina.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_bukovina.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_bystrika {
|
class convert_to_bystrika {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_bystrika.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_bystrika.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_chernarus {
|
class convert_to_chernarus {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_chernarus.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_chernarus.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_cucui {
|
class convert_to_cucui {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_cucui.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_cucui.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_kunduz {
|
class convert_to_kunduz {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_kunduz.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_kunduz.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_livonia {
|
class convert_to_livonia {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_livonia.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_livonia.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_malden {
|
class convert_to_malden {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_malden.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_malden.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_southen_sahrani {
|
class convert_to_southen_sahrani {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_southen_sahrani.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_southen_sahrani.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_stratis {
|
class convert_to_stratis {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_stratis.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_stratis.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_takistan_montains {
|
class convert_to_takistan_montains {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_takistan_montains.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_takistan_montains.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_tanoa {
|
class convert_to_tanoa {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_tanoa.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_tanoa.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_united_sahrani {
|
class convert_to_united_sahrani {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_united_sahrani.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_united_sahrani.sqf";
|
||||||
};
|
};
|
||||||
class convert_to_vr {
|
class convert_to_vr {
|
||||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_vr.sqf";
|
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_vr.sqf";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,172 +0,0 @@
|
|||||||
class CfgFactionClasses {
|
|
||||||
class NO_CATEGORY;
|
|
||||||
class armatak_module_category: NO_CATEGORY {
|
|
||||||
displayName = "Team Awareness Kit";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
class CfgVehicles {
|
|
||||||
class Logic;
|
|
||||||
class Module_F : Logic
|
|
||||||
{
|
|
||||||
class AttributesBase
|
|
||||||
{
|
|
||||||
class Default;
|
|
||||||
class Edit; // Default edit box (i.e. text input field)
|
|
||||||
class Combo; // Default combo box (i.e. drop-down menu)
|
|
||||||
class Checkbox; // Default checkbox (returned value is Boolean)
|
|
||||||
class CheckboxNumber; // Default checkbox (returned value is Number)
|
|
||||||
class ModuleDescription; // Module description
|
|
||||||
class Units; // Selection of units on which the module is applied
|
|
||||||
};
|
|
||||||
|
|
||||||
class ModuleDescription
|
|
||||||
{
|
|
||||||
class AnyBrain;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
class armatak_module_core: Module_F {
|
|
||||||
scope = 2;
|
|
||||||
displayname = "ARMATAK CoT Router";
|
|
||||||
icon = "\a3\Modules_F_Curator\Data\iconRadio_ca.paa";
|
|
||||||
category = "armatak_module_category";
|
|
||||||
function = "armatak_fnc_init";
|
|
||||||
functionPriority = 1;
|
|
||||||
isGlobal = 0;
|
|
||||||
isTriggerActivated = 0;
|
|
||||||
isDisposable = 1;
|
|
||||||
is3den = 0;
|
|
||||||
curatorCanAttach = 0;
|
|
||||||
curatorInfoType = "RscDisplayAttributeModuleNuke";
|
|
||||||
|
|
||||||
canSetArea = 0;
|
|
||||||
canSetAreaShape = 0;
|
|
||||||
canSetAreaHeight = 0;
|
|
||||||
|
|
||||||
class AttributesValues {
|
|
||||||
size3[] = { 1, 1, -1 };
|
|
||||||
isRectangle = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Attributes: AttributesBase {
|
|
||||||
class armatak_module_tak_server_instance_address: Edit {
|
|
||||||
property = "armatak_module_tak_server_instance_address";
|
|
||||||
displayname = "TAK Server Address";
|
|
||||||
tooltip = "TAK Server Instance Address";
|
|
||||||
typeName = "STRING";
|
|
||||||
defaultValue = "localhost";
|
|
||||||
};
|
|
||||||
class armatak_module_tak_server_instance_port: Edit {
|
|
||||||
property = "armatak_module_tak_server_instance_port";
|
|
||||||
displayname = "TAK Server TCP Port";
|
|
||||||
tooltip = "TAK Server instance Port for TCP connection";
|
|
||||||
typeName = "NUMBER";
|
|
||||||
defaultValue = "8088";
|
|
||||||
};
|
|
||||||
class ModuleDescription: ModuleDescription {};
|
|
||||||
};
|
|
||||||
|
|
||||||
class ModuleDescription: ModuleDescription {
|
|
||||||
description = "Generate the initial ARMATAK configuration, syncronizing all players to the TAK server instance";
|
|
||||||
sync[] = {"LocationArea_F"};
|
|
||||||
|
|
||||||
class LocationArea_F {
|
|
||||||
description[] = {
|
|
||||||
"First line",
|
|
||||||
"Second line"
|
|
||||||
};
|
|
||||||
position = 1;
|
|
||||||
direction = 1;
|
|
||||||
optional = 1;
|
|
||||||
duplicate = 1;
|
|
||||||
synced[] = { "BluforUnit", "AnyBrain" };
|
|
||||||
};
|
|
||||||
class BluforUnit
|
|
||||||
{
|
|
||||||
description = "Short description";
|
|
||||||
displayName = "Any BLUFOR unit";
|
|
||||||
icon = "iconMan";
|
|
||||||
side = 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
class armatak_module_video_stream_core: armatak_module_core {
|
|
||||||
scope = 2;
|
|
||||||
displayname = "ARMATAK MediaMTX Video Feed Parser";
|
|
||||||
icon = "\a3\Modules_F_Curator\Data\iconcuratorsetcamera_ca.paa";
|
|
||||||
category = "armatak_module_category";
|
|
||||||
function = "armatak_fnc_video_init";
|
|
||||||
functionPriority = 1;
|
|
||||||
isGlobal = 0;
|
|
||||||
isTriggerActivated = 0;
|
|
||||||
isDisposable = 1;
|
|
||||||
is3den = 0;
|
|
||||||
curatorCanAttach = 0;
|
|
||||||
curatorInfoType = "RscDisplayAttributeModuleNuke";
|
|
||||||
|
|
||||||
canSetArea = 0;
|
|
||||||
canSetAreaShape = 0;
|
|
||||||
canSetAreaHeight = 0;
|
|
||||||
|
|
||||||
class AttributesValues {
|
|
||||||
size3[] = { 1, 1, -1 };
|
|
||||||
isRectangle = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Attributes: AttributesBase {
|
|
||||||
class armatak_module_mediamtx_video_stream_instance_address: Edit {
|
|
||||||
property = "armatak_module_mediamtx_video_stream_instance_address";
|
|
||||||
displayname = "MediaMTX Provider Address";
|
|
||||||
tooltip = "MediaMTX Provider Instance Address";
|
|
||||||
typeName = "STRING";
|
|
||||||
defaultValue = "localhost";
|
|
||||||
};
|
|
||||||
class armatak_module_mediamtx_video_stream_instance_port: Edit {
|
|
||||||
property = "armatak_module_mediamtx_video_stream_instance_port";
|
|
||||||
displayname = "MediaMTX Provider Port";
|
|
||||||
tooltip = "MediaMTX Provider Port for handling video streams";
|
|
||||||
typeName = "STRING";
|
|
||||||
defaultValue = "8554";
|
|
||||||
};
|
|
||||||
class armatak_module_mediamtx_video_stream_instance_auth_user: Edit {
|
|
||||||
property = "armatak_module_mediamtx_video_stream_instance_auth_user";
|
|
||||||
displayname = "MediaMTX Provider Username";
|
|
||||||
tooltip = "MediaMTX Provider Instance Username";
|
|
||||||
typeName = "STRING";
|
|
||||||
defaultValue = "administrator";
|
|
||||||
};
|
|
||||||
class armatak_module_mediamtx_video_stream_instance_auth_pass: Edit {
|
|
||||||
property = "armatak_module_mediamtx_video_stream_instance_auth_pass";
|
|
||||||
displayname = "MediaMTX Provider Password";
|
|
||||||
tooltip = "MediaMTX Provider Instance Password";
|
|
||||||
typeName = "STRING";
|
|
||||||
defaultValue = "password";
|
|
||||||
};
|
|
||||||
class ModuleDescription: ModuleDescription {};
|
|
||||||
};
|
|
||||||
|
|
||||||
class ModuleDescription: ModuleDescription {
|
|
||||||
description = "Generate the initial ARMATAK configuration, syncronizing all players to the TAK server instance";
|
|
||||||
sync[] = {"LocationArea_F"};
|
|
||||||
|
|
||||||
class LocationArea_F {
|
|
||||||
description[] = {
|
|
||||||
"First line",
|
|
||||||
"Second line"
|
|
||||||
};
|
|
||||||
position = 1;
|
|
||||||
direction = 1;
|
|
||||||
optional = 1;
|
|
||||||
duplicate = 1;
|
|
||||||
synced[] = { "BluforUnit", "AnyBrain" };
|
|
||||||
};
|
|
||||||
class BluforUnit
|
|
||||||
{
|
|
||||||
description = "Short description";
|
|
||||||
displayName = "Any BLUFOR unit";
|
|
||||||
icon = "iconMan";
|
|
||||||
side = 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
2
addons/main/XEH_PREP.hpp
Normal file
2
addons/main/XEH_PREP.hpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
PREP(logMessage);
|
||||||
|
PREP(notify);
|
||||||
43
addons/main/XEH_postInit.sqf
Normal file
43
addons/main/XEH_postInit.sqf
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
addMissionEventHandler ["ExtensionCallback", {
|
||||||
|
params ["_name", "_function", "_data"];
|
||||||
|
|
||||||
|
if (_name == "WEBSOCKET") then {
|
||||||
|
[_function, "success", _name] call FUNC(notify);
|
||||||
|
|
||||||
|
switch (_function) do {
|
||||||
|
case "EUD connected": {
|
||||||
|
SETVAR(player,EGVAR(client,eudConnected),true);
|
||||||
|
};
|
||||||
|
case "EUD disconnected": {
|
||||||
|
SETVAR(player,GVAR(eudConnected),false);
|
||||||
|
};
|
||||||
|
default {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_name == "WEBSOCKET WARNING") then {
|
||||||
|
[_function, "warning", "WEBSOCKET"] call FUNC(notify);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_name == "WEBSOCKET ERROR") then {
|
||||||
|
[_function, "error", _name] call FUNC(notify);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_name == "TCP SOCKET") then {
|
||||||
|
[_function, "success", _name] call FUNC(notify);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_name == "TCP SOCKET ERROR") then {
|
||||||
|
[_function, "error", _name] call FUNC(notify);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_name == "VIDEO") then {
|
||||||
|
[_function, "success", _name] call FUNC(notify);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_name == "VIDEO ERROR") then {
|
||||||
|
[_function, "error", _name] call FUNC(notify);
|
||||||
|
};
|
||||||
|
}];
|
||||||
9
addons/main/XEH_preInit.sqf
Normal file
9
addons/main/XEH_preInit.sqf
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
ADDON = false;
|
||||||
|
|
||||||
|
PREP_RECOMPILE_START;
|
||||||
|
#include "XEH_PREP.hpp"
|
||||||
|
PREP_RECOMPILE_END;
|
||||||
|
|
||||||
|
ADDON = true;
|
||||||
3
addons/main/XEH_preStart.sqf
Normal file
3
addons/main/XEH_preStart.sqf
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
#include "XEH_PREP.hpp"
|
||||||
@@ -1,26 +1,46 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
class CfgPatches {
|
class CfgPatches {
|
||||||
class armatak_main {
|
class ADDON {
|
||||||
units[] = {
|
name = COMPONENT_NAME;
|
||||||
"armatak_module_core",
|
units[] = {};
|
||||||
"armatak_module_callsign"
|
weapons[] = {};
|
||||||
};
|
requiredAddons[] = {
|
||||||
weapons[] = {""};
|
|
||||||
author = "Valmo";
|
|
||||||
url = "https://github.com/valmojr/armatak";
|
|
||||||
requiredAddons[] =
|
|
||||||
{
|
|
||||||
"cba_main",
|
"cba_main",
|
||||||
"ace_main"
|
"ace_main"
|
||||||
};
|
};
|
||||||
requiredVersion = 2.06;
|
requiredVersion = REQUIRED_VERSION;
|
||||||
|
author = PROJECT_AUTHOR;
|
||||||
|
url = "https://github.com/valmojr/armatak";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Extended_PostInit_EventHandlers {
|
class CfgMods {
|
||||||
class armatak_main {
|
class PREFIX {
|
||||||
init = "call compileScript ['\armatak\armatak\armatak_main\initPlayerLocal.sqf']";
|
name = "Arma Team Awareness Kit";
|
||||||
|
author = PROJECT_AUTHOR;
|
||||||
|
logo = "logo_ca.paa";
|
||||||
|
logoOver = "logo_hover_ca.paa";
|
||||||
|
tooltip = "ARMATAK";
|
||||||
|
tooltipOwned = "ARMATAK";
|
||||||
|
picture = "picture.paa";
|
||||||
|
actionName = "GitHub";
|
||||||
|
action = "https://github.com/valmojr/armatak";
|
||||||
|
overview = "ARMATAK Addons allows Arma 3 sessions to be parsed to TAK Clients";
|
||||||
|
hideName = 0;
|
||||||
|
hidePicture = 0;
|
||||||
|
dlcColor[] = { 0.23, 0.39, 0.30, 1 };
|
||||||
|
logoSmall = "logo_small_ca.paa";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CfgFactionClasses {
|
||||||
|
class NO_CATEGORY;
|
||||||
|
class GVAR(moduleCategory): NO_CATEGORY {
|
||||||
|
displayName = "Team Awareness Kit";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "CfgEventHandlers.hpp"
|
||||||
#include "CfgFunctions.hpp"
|
#include "CfgFunctions.hpp"
|
||||||
#include "CfgVehicles.hpp"
|
#include "Cfg3den.hpp"
|
||||||
|
|||||||
@@ -10,5 +10,5 @@ if (!isNull _digitalPointer) then {
|
|||||||
|
|
||||||
_dpCot = [_link_uid, _contact_callsign, _digitalPointerPosition select 0, _digitalPointerPosition select 1, _digitalPointerPosition select 2];
|
_dpCot = [_link_uid, _contact_callsign, _digitalPointerPosition select 0, _digitalPointerPosition select 1, _digitalPointerPosition select 2];
|
||||||
|
|
||||||
"armatak" callExtension ["cot_router:send_digital_pointer_cot", [_dpCot]];
|
"armatak" callExtension ["tcp_socket:send_digital_pointer_cot", [_dpCot]];
|
||||||
};
|
};
|
||||||
13
addons/main/functions/api/fn_send_eud_cot.sqf
Normal file
13
addons/main/functions/api/fn_send_eud_cot.sqf
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// function name: armatak_fnc_extract_eud_cot_info
|
||||||
|
// function author: Valmo
|
||||||
|
// function description: Gets the information necessary for generating the EUD Cursor Over Time
|
||||||
|
|
||||||
|
params ["_unit", "_callsign", "_group_name", "_group_role"];
|
||||||
|
|
||||||
|
_position = _unit call armatak_client_fnc_extractClientPosition;
|
||||||
|
|
||||||
|
_uuid = _unit call armatak_fnc_extract_uuid;
|
||||||
|
|
||||||
|
_eud_cot = [_uuid, _position select 0, _position select 1, _position select 2, _callsign, _group_name, _group_role, _position select 3, speed player / 3.6];
|
||||||
|
|
||||||
|
"armatak" callExtension ["tcp_socket:send_eud_cot", [_eud_cot]];
|
||||||
@@ -9,5 +9,5 @@ params["_group"];
|
|||||||
_group_name = [_group] call armatak_fnc_extract_group_color;
|
_group_name = [_group] call armatak_fnc_extract_group_color;
|
||||||
_group_role = [_x] call armatak_fnc_extract_group_role;
|
_group_role = [_x] call armatak_fnc_extract_group_role;
|
||||||
|
|
||||||
[_x, _callsign, _group_name, _group_role] call armatak_fnc_send_human_cot;
|
[_x, _callsign, _group_name, _group_role] call armatak_fnc_send_eud_cot;
|
||||||
} forEach (units _group);
|
} forEach (units _group);
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
// function name: armatak_fnc_extract_human_cot_info
|
|
||||||
// function author: Valmo
|
|
||||||
// function description: Gets the information necessary for generating the Human Cursor Over Time
|
|
||||||
|
|
||||||
params ["_unit", "_callsign", "_group_name", "_group_role"];
|
|
||||||
|
|
||||||
_position = _unit call armatak_fnc_extract_position;
|
|
||||||
_uuid = _unit call armatak_fnc_extract_uuid;
|
|
||||||
|
|
||||||
_human_cot = [_uuid, _position select 0, _position select 1, _position select 2, _callsign, _group_name, _group_role, _position select 3, speed player / 3.6];
|
|
||||||
|
|
||||||
"armatak" callExtension ["cot_router:send_human_cot", [_human_cot]];
|
|
||||||
@@ -4,9 +4,10 @@
|
|||||||
|
|
||||||
params ["_unit", "_type", "_callsign"];
|
params ["_unit", "_type", "_callsign"];
|
||||||
|
|
||||||
_unit_position = _unit call armatak_fnc_extract_position;
|
_unit_position = _unit call armatak_client_fnc_extractClientPosition;
|
||||||
|
|
||||||
_uuid = _unit call armatak_fnc_extract_uuid;
|
_uuid = _unit call armatak_fnc_extract_uuid;
|
||||||
|
|
||||||
_marker_cot = [_uuid, _type, _unit_position select 0, _unit_position select 1, _unit_position select 2, _callsign, _unit_position select 3, speed _unit / 3.6];
|
_marker_cot = [_uuid, _type, _unit_position select 0, _unit_position select 1, _unit_position select 2, _callsign, _unit_position select 3, speed _unit / 3.6];
|
||||||
|
|
||||||
"armatak" callExtension ["cot_router:send_marker_cot", [_marker_cot]];
|
"armatak" callExtension ["tcp_socket:send_marker_cot", [_marker_cot]];
|
||||||
10
addons/main/functions/api/fn_stop_tcp_socket.sqf
Normal file
10
addons/main/functions/api/fn_stop_tcp_socket.sqf
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
_armatak_tcp_socket_is_running = missionNamespace getVariable "armatak_tcp_socket_is_running";
|
||||||
|
|
||||||
|
if (_armatak_tcp_socket_is_running) then {
|
||||||
|
missionNamespace setVariable ["armatak_tcp_socket_is_running", false];
|
||||||
|
|
||||||
|
"armatak" callExtension ["tcp_socket:stop", []];
|
||||||
|
} else {
|
||||||
|
_warning = format ["<t color='#FF0021'>ARMATAK</t><br/> %1", "There is no TCP Socket running to be stopped"];
|
||||||
|
[[_warning, 1.5]] call CBA_fnc_notify;
|
||||||
|
};
|
||||||
@@ -3,7 +3,7 @@ params["_group"];
|
|||||||
_group_name = _group getVariable "_atak_group_name";
|
_group_name = _group getVariable "_atak_group_name";
|
||||||
|
|
||||||
if (isNil "_group_name") then {
|
if (isNil "_group_name") then {
|
||||||
_group_colors = missionNamespace getVariable "_group_colors";
|
_group_colors = missionNamespace getVariable "armatak_group_colors";
|
||||||
_group_name = selectRandom _group_colors;
|
_group_name = selectRandom _group_colors;
|
||||||
|
|
||||||
if (count _group_colors > 0) then {
|
if (count _group_colors > 0) then {
|
||||||
@@ -15,7 +15,7 @@ if (isNil "_group_name") then {
|
|||||||
|
|
||||||
_group_name = _selectedColor;
|
_group_name = _selectedColor;
|
||||||
_group setVariable ["_atak_group_name", _group_name];
|
_group setVariable ["_atak_group_name", _group_name];
|
||||||
missionNamespace setVariable ["_group_colors", _group_colors]
|
missionNamespace setVariable ["armatak_group_colors", _group_colors]
|
||||||
} else {
|
} else {
|
||||||
_group_name = "Red";
|
_group_name = "Red";
|
||||||
_group setVariable ["_atak_group_name", _group_name];
|
_group setVariable ["_atak_group_name", _group_name];
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
// function name: armatak_fnc_extract_callsign
|
// function name: armatak_fnc_extract_marker_callsign
|
||||||
// function author: Valmo
|
// function author: Valmo
|
||||||
// function description: Gets the unit name or classname to be used as TAK callsign
|
// function description: Gets the unit name or classname to be used as TAK callsign in a Marker
|
||||||
|
|
||||||
params["_unit"];
|
params["_unit"];
|
||||||
|
|
||||||
private _callsign = "";
|
private _callsign = "";
|
||||||
|
|
||||||
if (roleDescription _unit != "") then {
|
|
||||||
_callsign = ([name _unit] call armatak_fnc_shorten_name) + " | " + roleDescription _unit;
|
|
||||||
} else {
|
|
||||||
_callsign = name _unit;
|
|
||||||
|
|
||||||
if (_callsign == "Error: No unit") then {
|
|
||||||
_callsign = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "displayName");
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
if ((([_unit] call BIS_fnc_objectType) select 0) == "Vehicle") then {
|
if ((([_unit] call BIS_fnc_objectType) select 0) == "Vehicle") then {
|
||||||
_callsign = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "displayName");
|
_callsign = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "displayName");
|
||||||
|
|
||||||
@@ -34,10 +24,10 @@ if (unitIsUAV _unit) then {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_atak_pre_defined_callsign = _unit getVariable "_atak_callsign";
|
armatak_attribute_marker_callsign = _unit getVariable "armatak_attribute_marker_callsign";
|
||||||
|
|
||||||
if (!isNil "_atak_pre_defined_callsign") then {
|
if (!isNil "armatak_attribute_marker_callsign" or armatak_attribute_marker_callsign != '') then {
|
||||||
_callsign = _atak_pre_defined_callsign;
|
_callsign = armatak_attribute_marker_callsign;
|
||||||
};
|
};
|
||||||
|
|
||||||
_callsign
|
_callsign
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
// function name: armatak_fnc_extract_position
|
|
||||||
// function author: Valmo
|
|
||||||
// function description: Receives a player's unit as param and return the information array for SIMTAK
|
|
||||||
|
|
||||||
params["_unit"];
|
|
||||||
|
|
||||||
private _location = (getPos _unit) call armatak_fnc_convert_location;
|
|
||||||
|
|
||||||
private _atak_latitude = _location select 0;
|
|
||||||
private _atak_longitude = _location select 1;
|
|
||||||
private _atak_altitude = _location select 2;
|
|
||||||
private _atak_bearing = parseNumber ((getDir _unit) toFixed 0);
|
|
||||||
|
|
||||||
_unit_info = [_atak_latitude,_atak_longitude,_atak_altitude,_atak_bearing];
|
|
||||||
|
|
||||||
_unit_info
|
|
||||||
@@ -110,4 +110,11 @@ if ((typeOf (vehicle _unit) != typeOf _unit) or ((_unit_type select 0) == "Vehic
|
|||||||
|
|
||||||
_role = "a-" + _affiliation + "-" + _type;
|
_role = "a-" + _affiliation + "-" + _type;
|
||||||
|
|
||||||
|
|
||||||
|
armatak_attribute_marker_type = _unit getVariable "armatak_attribute_marker_type";
|
||||||
|
|
||||||
|
if (!isNil "armatak_attribute_marker_type" or armatak_attribute_marker_type != '') then {
|
||||||
|
_role = armatak_attribute_marker_type;
|
||||||
|
};
|
||||||
|
|
||||||
_role
|
_role
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// function name: armatak_fnc_extract_unit_callsign
|
||||||
|
// function author: Valmo
|
||||||
|
// function description: Gets the unit name or classname to be used as TAK callsign from a unit
|
||||||
|
|
||||||
|
params["_unit"];
|
||||||
|
|
||||||
|
private _callsign = "";
|
||||||
|
|
||||||
|
if (roleDescription _unit != "") then {
|
||||||
|
_callsign = ([name _unit] call armatak_fnc_shorten_name) + " | " + roleDescription _unit;
|
||||||
|
} else {
|
||||||
|
_callsign = name _unit;
|
||||||
|
|
||||||
|
if (_callsign == "Error: No unit") then {
|
||||||
|
_callsign = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "displayName");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
armatak_attribute_unit_callsign = _unit getVariable "armatak_attribute_unit_callsign";
|
||||||
|
|
||||||
|
if (!isNil "armatak_attribute_unit_callsign" or armatak_attribute_unit_callsign != '') then {
|
||||||
|
_callsign = armatak_attribute_unit_callsign;
|
||||||
|
};
|
||||||
|
|
||||||
|
_callsign
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
params [
|
|
||||||
["_logic", objNull, [objNull]],
|
|
||||||
["_units", [], [[]]],
|
|
||||||
["_activated", true, [true]]
|
|
||||||
];
|
|
||||||
|
|
||||||
if (isServer) exitWith {
|
|
||||||
_warning = format ["<t color='#FF8021'>ARMATAK</t><br/> %1", "Connecting to TAK Server TCP Socket..."];
|
|
||||||
[[_warning, 1.5]] call CBA_fnc_notify;
|
|
||||||
|
|
||||||
addMissionEventHandler ["ExtensionCallback", {
|
|
||||||
params ["_name", "_function", "_data"];
|
|
||||||
|
|
||||||
if (_name == "armatak_tcp_socket") then {
|
|
||||||
_warning = format ["<t color='#00FF21'>ARMATAK</t><br/> %1", _function];
|
|
||||||
[[_warning, 1.5]] call CBA_fnc_notify;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (_name == "armatak_tcp_socket_error") then {
|
|
||||||
_warning = format ["<t color='#FF0021'>ARMATAK</t><br/> %1", _function];
|
|
||||||
[[_warning, 1.5]] call CBA_fnc_notify;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (_name == "armatak_video") then {
|
|
||||||
_warning = format ["<t color='#00FF21'>ARMATAK</t><br/> %1", _function];
|
|
||||||
[[_warning, 1.5]] call CBA_fnc_notify;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (_name == "armatak_video_error") then {
|
|
||||||
_warning = format ["<t color='#FF0021'>ARMATAK</t><br/> %1", _function];
|
|
||||||
[[_warning, 1.5]] call CBA_fnc_notify;
|
|
||||||
};
|
|
||||||
}];
|
|
||||||
|
|
||||||
_tak_server_instance_address = _logic getVariable "armatak_module_tak_server_instance_address";
|
|
||||||
_tak_server_instance_port = _logic getVariable "armatak_module_tak_server_instance_port";
|
|
||||||
|
|
||||||
_tak_server_fulladdress = _tak_server_instance_address + ":" + (str _tak_server_instance_port);
|
|
||||||
|
|
||||||
missionNamespace setVariable ["_atak_server_instance", _tak_server_fulladdress];
|
|
||||||
missionNamespace setVariable ["_group_colors", ["White", "Yellow", "Orange", "Magenta", "Red", "Maroon", "Purple", "DarkBlue", "Blue", "Cyan", "Teal", "Green", "DarkGreen", "Brown"]];
|
|
||||||
|
|
||||||
"armatak" callExtension ["cot_router:start", [_tak_server_fulladdress]];
|
|
||||||
|
|
||||||
_syncUnits = synchronizedObjects _logic;
|
|
||||||
|
|
||||||
missionNamespace setVariable ["_armatak_marked_units", _syncUnits];
|
|
||||||
|
|
||||||
_syncedUnits = missionNamespace getVariable "_armatak_marked_units";
|
|
||||||
|
|
||||||
[{
|
|
||||||
_syncedUnits = missionNamespace getVariable "_armatak_marked_units";
|
|
||||||
|
|
||||||
{
|
|
||||||
_objectType = _x call BIS_fnc_objectType;
|
|
||||||
if ((_objectType select 0) == "Soldier") then {
|
|
||||||
_callsign = [_x] call armatak_fnc_extract_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_human_cot;
|
|
||||||
[_x] call armatak_fnc_send_digital_pointer_cot;
|
|
||||||
};
|
|
||||||
if ((_objectType select 0) == "Vehicle") then {
|
|
||||||
_atak_type = [_x] call armatak_fnc_extract_role;
|
|
||||||
_callsign = [_x] call armatak_fnc_extract_callsign;
|
|
||||||
|
|
||||||
[_x, _atak_type, _callsign] call armatak_fnc_send_marker_cot;
|
|
||||||
};
|
|
||||||
if (unitIsUAV _x) then {
|
|
||||||
[_x] call armatak_fnc_send_drone_cot;
|
|
||||||
[_x] call armatak_fnc_send_digital_pointer_cot;
|
|
||||||
};
|
|
||||||
} forEach _syncedUnits;
|
|
||||||
}, 2, []] call CBA_fnc_addPerFrameHandler;
|
|
||||||
};
|
|
||||||
|
|
||||||
true;
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
params [
|
|
||||||
["_logic", objNull, [objNull]],
|
|
||||||
["_units", [], [[]]],
|
|
||||||
["_activated", true, [true]]
|
|
||||||
];
|
|
||||||
|
|
||||||
if (isServer) exitWith {
|
|
||||||
armatak_module_mediamtx_video_stream_instance_address = _logic getVariable "armatak_module_mediamtx_video_stream_instance_address";
|
|
||||||
armatak_module_mediamtx_video_stream_instance_port = _logic getVariable "armatak_module_mediamtx_video_stream_instance_port";
|
|
||||||
armatak_module_mediamtx_video_stream_instance_auth_user = _logic getVariable "armatak_module_mediamtx_video_stream_instance_auth_user";
|
|
||||||
armatak_module_mediamtx_video_stream_instance_auth_pass = _logic getVariable "armatak_module_mediamtx_video_stream_instance_auth_pass";
|
|
||||||
|
|
||||||
missionNamespace setVariable ["armatak_mediamtx_video_stream_instance_address", armatak_module_mediamtx_video_stream_instance_address];
|
|
||||||
missionNamespace setVariable ["armatak_mediamtx_video_stream_instance_port", armatak_module_mediamtx_video_stream_instance_port];
|
|
||||||
missionNamespace setVariable ["armatak_mediamtx_video_stream_instance_auth_user", armatak_module_mediamtx_video_stream_instance_auth_user];
|
|
||||||
missionNamespace setVariable ["armatak_mediamtx_video_stream_instance_auth_pass", armatak_module_mediamtx_video_stream_instance_auth_pass];
|
|
||||||
|
|
||||||
_startAction = [
|
|
||||||
"ArmatakStartStream",
|
|
||||||
"Start Video Feed",
|
|
||||||
"",
|
|
||||||
{
|
|
||||||
_uuid = (_this select 0) call armatak_fnc_extract_uuid;
|
|
||||||
|
|
||||||
armatak_mediamtx_video_stream_instance_address = missionNamespace getVariable "armatak_mediamtx_video_stream_instance_address";
|
|
||||||
armatak_mediamtx_video_stream_instance_port = missionNamespace getVariable "armatak_mediamtx_video_stream_instance_port";
|
|
||||||
armatak_mediamtx_video_stream_instance_auth_user = missionNamespace getVariable "armatak_mediamtx_video_stream_instance_auth_user";
|
|
||||||
armatak_mediamtx_video_stream_instance_auth_pass = missionNamespace getVariable "armatak_mediamtx_video_stream_instance_auth_pass";
|
|
||||||
|
|
||||||
"armatak" callExtension ["video_stream:start", [armatak_mediamtx_video_stream_instance_address, armatak_mediamtx_video_stream_instance_port, _uuid, armatak_mediamtx_video_stream_instance_auth_user, armatak_mediamtx_video_stream_instance_auth_pass]];
|
|
||||||
(_this select 0) setVariable ["armatak_video_feed_is_streaming", true];
|
|
||||||
},
|
|
||||||
{
|
|
||||||
(_this select 0) getVariable "armatak_video_feed_is_streaming" == false
|
|
||||||
}
|
|
||||||
] call ace_interact_menu_fnc_createAction;
|
|
||||||
[
|
|
||||||
"Man",
|
|
||||||
1,
|
|
||||||
["ACE_SelfActions"],
|
|
||||||
_startAction,
|
|
||||||
true
|
|
||||||
] call ace_interact_menu_fnc_addActionToClass;
|
|
||||||
|
|
||||||
_stopAction = [
|
|
||||||
"ArmatakStopStream",
|
|
||||||
"Stop Video Feed",
|
|
||||||
"",
|
|
||||||
{
|
|
||||||
"armatak" callExtension ["video_stream:stop", []];
|
|
||||||
(_this select 0) setVariable ["armatak_video_feed_is_streaming", false];
|
|
||||||
},
|
|
||||||
{
|
|
||||||
(_this select 0) getVariable "armatak_video_feed_is_streaming"
|
|
||||||
}
|
|
||||||
] call ace_interact_menu_fnc_createAction;
|
|
||||||
[
|
|
||||||
"Man",
|
|
||||||
1,
|
|
||||||
["ACE_SelfActions"],
|
|
||||||
_stopAction,
|
|
||||||
true
|
|
||||||
] call ace_interact_menu_fnc_addActionToClass;
|
|
||||||
if (isMultiplayer) then {
|
|
||||||
{
|
|
||||||
_x setVariable ["armatak_video_feed_is_streaming", false];
|
|
||||||
} forEach playableUnits;
|
|
||||||
} else {
|
|
||||||
player setVariable ["armatak_video_feed_is_streaming", false];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
true;
|
|
||||||
21
addons/main/functions/fnc_notify.sqf
Normal file
21
addons/main/functions/fnc_notify.sqf
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
|
||||||
|
params ["_message", "_type", ["_title", "ARMATAK"]];
|
||||||
|
|
||||||
|
switch (_type) do {
|
||||||
|
case "success": {
|
||||||
|
_warning = format ["<t color='#00FF21'>ARMATAK - %1</t><br/> %2", _title, _message];
|
||||||
|
[[_warning, 1.5]] call CBA_fnc_notify;
|
||||||
|
};
|
||||||
|
case "warning": {
|
||||||
|
_warning = format ["<t color='#ffff16'>ARMATAK - %1</t><br/> %2", _title, _message];
|
||||||
|
[[_warning, 1.5]] call CBA_fnc_notify;
|
||||||
|
};
|
||||||
|
case "error": {
|
||||||
|
_warning = format ["<t color='#FF0021'>ARMATAK - %1</t><br/> %2", _title, _message];
|
||||||
|
[[_warning, 1.5]] call CBA_fnc_notify;
|
||||||
|
};
|
||||||
|
default {
|
||||||
|
systemChat format ["%1 - %2", _title, _message];
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -4,16 +4,16 @@ private _mapWidth = 5120;
|
|||||||
private _mapHeight = 5120;
|
private _mapHeight = 5120;
|
||||||
|
|
||||||
// SW corner (used as origin)
|
// SW corner (used as origin)
|
||||||
private _SW_lat = 36.588437;
|
private _SW_lat = 36.581566;
|
||||||
private _SW_lon = 68.834763;
|
private _SW_lon = 68.839770;
|
||||||
|
|
||||||
// SE corner
|
// SE corner
|
||||||
private _SE_lat = 36.574950;
|
private _SE_lat = 36.581566;
|
||||||
private _SE_lon = 68.899151;
|
private _SE_lon = 68.905867;
|
||||||
|
|
||||||
// NW corner
|
// NW corner
|
||||||
private _NW_lat = 36.640080;
|
private _NW_lat = 36.633309;
|
||||||
private _NW_lon = 68.847941;
|
private _NW_lon = 68.839770;
|
||||||
|
|
||||||
private _edgeSE_lat = _SE_lat - _SW_lat;
|
private _edgeSE_lat = _SE_lat - _SW_lat;
|
||||||
private _edgeSE_lon = _SE_lon - _SW_lon;
|
private _edgeSE_lon = _SE_lon - _SW_lon;
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
if (!hasInterface) exitWith {};
|
|
||||||
|
|
||||||
_local_address = "armatak" callExtension ["local_ip", []] select 0;
|
|
||||||
|
|
||||||
player setVariable ["localAddress", _local_address];
|
|
||||||
|
|
||||||
player addEventHandler ["Respawn", {
|
|
||||||
params["_unit", "_corpse"];
|
|
||||||
[{
|
|
||||||
if (alive _this) then {
|
|
||||||
"armatak" callExtension ["websocket:location", [player call armatak_fnc_extract_position]];
|
|
||||||
};
|
|
||||||
}, 1, []] call CBA_fnc_addPerFrameHandler;
|
|
||||||
}];
|
|
||||||
|
|
||||||
[{
|
|
||||||
"armatak" callExtension ["websocket:location", [player call armatak_fnc_extract_position]];
|
|
||||||
}, 1, []] call CBA_fnc_addPerFrameHandler;
|
|
||||||
17
addons/main/script_component.hpp
Normal file
17
addons/main/script_component.hpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#define COMPONENT main
|
||||||
|
#define COMPONENT_BEAUTIFIED Main
|
||||||
|
#include "\armatak\armatak\addons\main\script_mod.hpp"
|
||||||
|
|
||||||
|
// #define DEBUG_MODE_FULL
|
||||||
|
// #define DISABLE_COMPILE_CACHE
|
||||||
|
// #define ENABLE_PERFORMANCE_COUNTERS
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED_MAIN
|
||||||
|
#define DEBUG_MODE_FULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_SETTINGS_MAIN
|
||||||
|
#define DEBUG_SETTINGS DEBUG_SETTINGS_MAIN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "\z\ace\addons\main\script_macros.hpp"
|
||||||
32
addons/main/script_mod.hpp
Normal file
32
addons/main/script_mod.hpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// COMPONENT should be defined in the script_component.hpp and included BEFORE this hpp
|
||||||
|
|
||||||
|
#define MAINPREFIX armatak
|
||||||
|
#define PREFIX armatak
|
||||||
|
|
||||||
|
#include "script_version.hpp"
|
||||||
|
|
||||||
|
#define VERSION MAJOR.MINOR
|
||||||
|
#define VERSION_STR MAJOR.MINOR.PATCHLVL.BUILD
|
||||||
|
#define VERSION_AR MAJOR,MINOR,PATCHLVL,BUILD
|
||||||
|
|
||||||
|
#define PROJECT_AUTHOR QUOTE(Valmo Trindade)
|
||||||
|
|
||||||
|
// MINIMAL required version for the Mod. Components can specify others..
|
||||||
|
#define REQUIRED_VERSION 2.18
|
||||||
|
#define REQUIRED_CBA_VERSION {3,18,2}
|
||||||
|
|
||||||
|
#ifndef COMPONENT_BEAUTIFIED
|
||||||
|
#define COMPONENT_BEAUTIFIED COMPONENT
|
||||||
|
#endif
|
||||||
|
#ifdef SUBCOMPONENT_BEAUTIFIED
|
||||||
|
#define COMPONENT_NAME QUOTE(ARMATAK - COMPONENT_BEAUTIFIED - SUBCOMPONENT_BEAUTIFIED)
|
||||||
|
#else
|
||||||
|
#define COMPONENT_NAME QUOTE(ARMATAK - COMPONENT_BEAUTIFIED)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Custom ARMATAK MACRO defines
|
||||||
|
|
||||||
|
#define EXTENSION_NAME QUOTE(armatak)
|
||||||
|
|
||||||
|
#define CALLEXT(var) EXTENSION_NAME callExtension [QUOTE(var),[]]
|
||||||
|
#define CALLEXTP(var1, var2) EXTENSION_NAME callExtension [QUOTE(var1), var2] select 0
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#define build 0
|
#define build 0
|
||||||
#define major 1
|
#define major 1
|
||||||
#define minor 0
|
#define minor 1
|
||||||
#define patch 0
|
#define patch 0
|
||||||
1
addons/server/$PBOPREFIX$
Normal file
1
addons/server/$PBOPREFIX$
Normal file
@@ -0,0 +1 @@
|
|||||||
|
armatak\armatak\addons\server
|
||||||
11
addons/server/CfgEventHandlers.hpp
Normal file
11
addons/server/CfgEventHandlers.hpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
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));
|
||||||
|
};
|
||||||
|
};
|
||||||
90
addons/server/CfgVehicles.hpp
Normal file
90
addons/server/CfgVehicles.hpp
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
class CfgVehicles {
|
||||||
|
class Logic;
|
||||||
|
class Module_F : Logic
|
||||||
|
{
|
||||||
|
class AttributesBase
|
||||||
|
{
|
||||||
|
class Default;
|
||||||
|
class Edit;
|
||||||
|
class Combo;
|
||||||
|
class Checkbox;
|
||||||
|
class CheckboxNumber;
|
||||||
|
class ModuleDescription;
|
||||||
|
class Units;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModuleDescription
|
||||||
|
{
|
||||||
|
class AnyBrain;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class GVAR(moduleBase): Module_F {
|
||||||
|
author = PROJECT_AUTHOR;
|
||||||
|
category = QEGVAR(main,moduleCategory);
|
||||||
|
function = QUOTE({});
|
||||||
|
functionPriority = 1;
|
||||||
|
isGlobal = 1;
|
||||||
|
isTriggerActivated = 0;
|
||||||
|
scope = 1;
|
||||||
|
scopeCurator = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GVAR(coreModule): GVAR(moduleBase) {
|
||||||
|
scope = 2;
|
||||||
|
scopeCurator = 0;
|
||||||
|
displayname = "CoT Router";
|
||||||
|
icon = "\a3\Modules_F_Curator\Data\iconRadio_ca.paa";
|
||||||
|
category = QEGVAR(main,moduleCategory);
|
||||||
|
function = QFUNC(3denCoreModuleConfig);
|
||||||
|
functionPriority = 1;
|
||||||
|
isGlobal = 0;
|
||||||
|
isTriggerActivated = 1;
|
||||||
|
isDisposable = 1;
|
||||||
|
is3den = 0;
|
||||||
|
curatorCanAttach = 0;
|
||||||
|
curatorInfoType = "RscDisplayAttributeModuleNuke";
|
||||||
|
canSetArea = 0;
|
||||||
|
canSetAreaShape = 0;
|
||||||
|
canSetAreaHeight = 0;
|
||||||
|
|
||||||
|
class Attributes: AttributesBase {
|
||||||
|
class GVAR(moduleInstanceAddress): Edit {
|
||||||
|
property = QGVAR(moduleInstanceAddress);
|
||||||
|
displayname = "TAK Server Address";
|
||||||
|
tooltip = "TAK Server Instance Address";
|
||||||
|
typeName = "STRING";
|
||||||
|
defaultValue = "localhost";
|
||||||
|
};
|
||||||
|
class GVAR(moduleInstancePort): Edit {
|
||||||
|
property = QGVAR(moduleInstancePort);
|
||||||
|
displayname = "TAK Server TCP Port";
|
||||||
|
tooltip = "TAK Server instance Port for TCP connection";
|
||||||
|
typeName = "NUMBER";
|
||||||
|
defaultValue = "8088";
|
||||||
|
};
|
||||||
|
class ModuleDescription: ModuleDescription {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModuleDescription: ModuleDescription {
|
||||||
|
description = "Generate the initial ARMATAK configuration, syncronizing all players to the TAK server instance";
|
||||||
|
sync[] = {"LocationArea_F"};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class GVAR(coreModuleCurator): GVAR(coreModule) {
|
||||||
|
scope = 1;
|
||||||
|
scopeCurator = 2;
|
||||||
|
function = "";
|
||||||
|
displayName = "CoT Router (Zeus)";
|
||||||
|
curatorInfoType = "armatak_zeus_core_module_dialog";
|
||||||
|
};
|
||||||
|
|
||||||
|
class GVAR(markEntity): GVAR(moduleBase) {
|
||||||
|
curatorCanAttach = 1;
|
||||||
|
category = QEGVAR(main,moduleCategory);
|
||||||
|
displayname = "Mark Entity";
|
||||||
|
function = QFUNC(routerEntityAdd);
|
||||||
|
icon = "\a3\Modules_F_Curator\Data\iconRadio_ca.paa";
|
||||||
|
};
|
||||||
|
};
|
||||||
4
addons/server/XEH_PREP.hpp
Normal file
4
addons/server/XEH_PREP.hpp
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
PREP(3denCoreModuleConfig);
|
||||||
|
PREP(routerEntityAdd);
|
||||||
|
PREP(routerEntityRemove);
|
||||||
|
PREP(ZeusCoreModuleConfig);
|
||||||
9
addons/server/XEH_preInit.sqf
Normal file
9
addons/server/XEH_preInit.sqf
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
ADDON = false;
|
||||||
|
|
||||||
|
PREP_RECOMPILE_START;
|
||||||
|
#include "XEH_PREP.hpp"
|
||||||
|
PREP_RECOMPILE_END;
|
||||||
|
|
||||||
|
ADDON = true;
|
||||||
3
addons/server/XEH_preStart.sqf
Normal file
3
addons/server/XEH_preStart.sqf
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
#include "XEH_PREP.hpp"
|
||||||
25
addons/server/config.cpp
Normal file
25
addons/server/config.cpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
class CfgPatches {
|
||||||
|
class ADDON {
|
||||||
|
name = COMPONENT_NAME;
|
||||||
|
units[] = {
|
||||||
|
QGVAR(coreModule),
|
||||||
|
QGVAR(coreModuleCurator),
|
||||||
|
QGVAR(markEntity)
|
||||||
|
};
|
||||||
|
weapons[] = {};
|
||||||
|
requiredAddons[] = {
|
||||||
|
"cba_main",
|
||||||
|
"ace_main",
|
||||||
|
"armatak_main"
|
||||||
|
};
|
||||||
|
requiredVersion = REQUIRED_VERSION;
|
||||||
|
author = PROJECT_AUTHOR;
|
||||||
|
url = "https://github.com/valmojr/armatak";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "CfgEventHandlers.hpp"
|
||||||
|
#include "dialog.hpp"
|
||||||
|
#include "CfgVehicles.hpp"
|
||||||
174
addons/server/dialog.hpp
Normal file
174
addons/server/dialog.hpp
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
class RscObject;
|
||||||
|
class RscText;
|
||||||
|
class RscFrame;
|
||||||
|
class RscLine;
|
||||||
|
class RscProgress;
|
||||||
|
class RscPicture;
|
||||||
|
class RscBackground;
|
||||||
|
class RscPictureKeepAspect;
|
||||||
|
class RscVideo;
|
||||||
|
class RscHTML;
|
||||||
|
class RscButton;
|
||||||
|
class RscShortcutButton;
|
||||||
|
class RscEdit;
|
||||||
|
class RscCombo;
|
||||||
|
class RscListBox;
|
||||||
|
class RscListNBox;
|
||||||
|
class RscXListBox;
|
||||||
|
class RscTree;
|
||||||
|
class RscSlider;
|
||||||
|
class RscXSliderH;
|
||||||
|
class RscActiveText;
|
||||||
|
class RscActivePicture;
|
||||||
|
class RscActivePictureKeepAspect;
|
||||||
|
class RscStructuredText;
|
||||||
|
class RscToolbox;
|
||||||
|
class RscControlsGroup;
|
||||||
|
class RscControlsGroupNoScrollbars;
|
||||||
|
class RscControlsGroupNoHScrollbars;
|
||||||
|
class RscControlsGroupNoVScrollbars;
|
||||||
|
class RscButtonTextOnly;
|
||||||
|
class RscButtonMenu;
|
||||||
|
class RscButtonMenuOK;
|
||||||
|
class RscButtonMenuCancel;
|
||||||
|
class RscButtonMenuSteam;
|
||||||
|
class RscMapControl;
|
||||||
|
class RscMapControlEmpty;
|
||||||
|
class RscCheckBox;
|
||||||
|
|
||||||
|
class armatak_zeus_core_module_dialog {
|
||||||
|
idd = 999991;
|
||||||
|
movingEnable = 0;
|
||||||
|
class ControlsBackground {
|
||||||
|
class armatak_gui_module_zeus_core_dialog_main_frame: RscBackground {
|
||||||
|
idc = 1800;
|
||||||
|
x = "0.386562 * safezoneW + safezoneX";
|
||||||
|
y = "0.401 * safezoneH + safezoneY";
|
||||||
|
w = "0.216563 * safezoneW";
|
||||||
|
h = "0.242 * safezoneH";
|
||||||
|
colorBackground[]={0,0,0,0.45};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
class Controls {
|
||||||
|
class armatak_gui_module_zeus_core_dialog_address_edit: RscEdit {
|
||||||
|
idc = 14000;
|
||||||
|
text = "localhost";
|
||||||
|
x = "0.391719 * safezoneW + safezoneX";
|
||||||
|
y = "0.445 * safezoneH + safezoneY";
|
||||||
|
w = "0.20625 * safezoneW";
|
||||||
|
h = "0.044 * safezoneH";
|
||||||
|
colorBackground[]={0,0,0,0.5};
|
||||||
|
};
|
||||||
|
class armatak_gui_module_zeus_core_dialog_address_port_edit: RscEdit {
|
||||||
|
idc = 14001;
|
||||||
|
text = "8088";
|
||||||
|
x = "0.391719 * safezoneW + safezoneX";
|
||||||
|
y = "0.522 * safezoneH + safezoneY";
|
||||||
|
w = "0.20625 * safezoneW";
|
||||||
|
h = "0.044 * safezoneH";
|
||||||
|
colorBackground[]={0,0,0,0.5};
|
||||||
|
};
|
||||||
|
class armatak_gui_module_zeus_core_dialog_address_text: RscText {
|
||||||
|
idc = 1000;
|
||||||
|
text = "TAK Server Address";
|
||||||
|
x = "0.391719 * safezoneW + safezoneX";
|
||||||
|
y = "0.412 * safezoneH + safezoneY";
|
||||||
|
w = "0.20625 * safezoneW";
|
||||||
|
h = "0.033 * safezoneH";
|
||||||
|
};
|
||||||
|
class armatak_gui_module_zeus_core_dialog_address_port_text: RscText {
|
||||||
|
idc = 1001;
|
||||||
|
text = "TAK Server Port";
|
||||||
|
x = "0.391719 * safezoneW + safezoneX";
|
||||||
|
y = "0.489 * safezoneH + safezoneY";
|
||||||
|
w = "0.20625 * safezoneW";
|
||||||
|
h = "0.033 * safezoneH";
|
||||||
|
};
|
||||||
|
class armatak_gui_module_zeus_core_dialog_address_button_cancel: RscButton {
|
||||||
|
idc = 1601;
|
||||||
|
text = "Cancel";
|
||||||
|
action = "closeDialog 2;";
|
||||||
|
x = "0.551563 * safezoneW + safezoneX";
|
||||||
|
y = "0.577 * safezoneH + safezoneY";
|
||||||
|
w = "0.0464063 * safezoneW";
|
||||||
|
h = "0.055 * safezoneH";
|
||||||
|
};
|
||||||
|
class armatak_gui_module_zeus_core_dialog_address_button_ok: RscButton {
|
||||||
|
idc = 1600;
|
||||||
|
text = "Ok";
|
||||||
|
action = QUOTE(call FUNC(zeusCoreModuleConfig));
|
||||||
|
x = "0.5 * safezoneW + safezoneX";
|
||||||
|
y = "0.577 * safezoneH + safezoneY";
|
||||||
|
w = "0.0464063 * safezoneW";
|
||||||
|
h = "0.055 * safezoneH";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class armatak_zeus_custom_marker_dialog {
|
||||||
|
idd = 990991;
|
||||||
|
movingEnable = 0;
|
||||||
|
|
||||||
|
class Controls {
|
||||||
|
class RscFrame_1800: RscFrame
|
||||||
|
{
|
||||||
|
idc = 1800;
|
||||||
|
x = "0.37625 * safezoneW + safezoneX";
|
||||||
|
y = "0.357 * safezoneH + safezoneY";
|
||||||
|
w = "0.237187 * safezoneW";
|
||||||
|
h = "0.275 * safezoneH";
|
||||||
|
};
|
||||||
|
class RscEdit_1400: RscEdit
|
||||||
|
{
|
||||||
|
idc = 1400;
|
||||||
|
x = "0.386562 * safezoneW + safezoneX";
|
||||||
|
y = "0.423 * safezoneH + safezoneY";
|
||||||
|
w = "0.216563 * safezoneW";
|
||||||
|
h = "0.044 * safezoneH";
|
||||||
|
};
|
||||||
|
class RscText_1000: RscText
|
||||||
|
{
|
||||||
|
idc = 1000;
|
||||||
|
text = "Entity Callsign";
|
||||||
|
x = "0.386562 * safezoneW + safezoneX";
|
||||||
|
y = "0.379 * safezoneH + safezoneY";
|
||||||
|
w = "0.216563 * safezoneW";
|
||||||
|
h = "0.044 * safezoneH";
|
||||||
|
};
|
||||||
|
class RscText_1001: RscText
|
||||||
|
{
|
||||||
|
idc = 1001;
|
||||||
|
text = "Entity Type (only for vehicles)";
|
||||||
|
x = "0.386562 * safezoneW + safezoneX";
|
||||||
|
y = "0.467 * safezoneH + safezoneY";
|
||||||
|
w = "0.216563 * safezoneW";
|
||||||
|
h = "0.044 * safezoneH";
|
||||||
|
};
|
||||||
|
class RscEdit_1401: RscEdit
|
||||||
|
{
|
||||||
|
idc = 1401;
|
||||||
|
x = "0.386562 * safezoneW + safezoneX";
|
||||||
|
y = "0.511 * safezoneH + safezoneY";
|
||||||
|
w = "0.216563 * safezoneW";
|
||||||
|
h = "0.044 * safezoneH";
|
||||||
|
};
|
||||||
|
class RscButton_1600: RscButton
|
||||||
|
{
|
||||||
|
idc = 1600;
|
||||||
|
text = "Cancel";
|
||||||
|
x = "0.551562 * safezoneW + safezoneX";
|
||||||
|
y = "0.566 * safezoneH + safezoneY";
|
||||||
|
w = "0.0515625 * safezoneW";
|
||||||
|
h = "0.055 * safezoneH";
|
||||||
|
};
|
||||||
|
class RscButton_1601: RscButton
|
||||||
|
{
|
||||||
|
idc = 1601;
|
||||||
|
text = "OK";
|
||||||
|
x = "0.489687 * safezoneW + safezoneX";
|
||||||
|
y = "0.566 * safezoneH + safezoneY";
|
||||||
|
w = "0.0515625 * safezoneW";
|
||||||
|
h = "0.055 * safezoneH";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
56
addons/server/functions/fnc_3denCoreModuleConfig.sqf
Normal file
56
addons/server/functions/fnc_3denCoreModuleConfig.sqf
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
|
||||||
|
params [
|
||||||
|
["_logic", objNull, [objNull]],
|
||||||
|
["_units", [], [[]]],
|
||||||
|
["_activated", true, [true]]
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isServer) exitWith {
|
||||||
|
["Connecting to TCP Socket", "success", "TCP Socket"] call EFUNC(main,notify);
|
||||||
|
|
||||||
|
_tak_server_instance_address = _logic getVariable QGVAR(moduleInstanceAddress);
|
||||||
|
_tak_server_instance_port = _logic getVariable QGVAR(moduleInstancePort);
|
||||||
|
|
||||||
|
_tak_server_fulladdress = _tak_server_instance_address + ":" + (str _tak_server_instance_port);
|
||||||
|
|
||||||
|
missionNamespace setVariable ["armatak_server_instance", _tak_server_fulladdress];
|
||||||
|
missionNamespace setVariable ["armatak_tcp_socket_is_running", true];
|
||||||
|
missionNamespace setVariable ["armatak_group_colors", ["White", "Yellow", "Orange", "Magenta", "Red", "Maroon", "Purple", "DarkBlue", "Blue", "Cyan", "Teal", "Green", "DarkGreen", "Brown"]];
|
||||||
|
|
||||||
|
"armatak" callExtension ["tcp_socket:start", [_tak_server_fulladdress]];
|
||||||
|
|
||||||
|
_syncUnits = synchronizedObjects _logic;
|
||||||
|
|
||||||
|
missionNamespace setVariable ["armatak_marked_units", _syncUnits];
|
||||||
|
|
||||||
|
GVAR(syncedUnits) = missionNamespace getVariable "armatak_marked_units";
|
||||||
|
|
||||||
|
[{
|
||||||
|
GVAR(syncedUnits) = missionNamespace getVariable "armatak_marked_units";
|
||||||
|
|
||||||
|
{
|
||||||
|
_objectType = _x call BIS_fnc_objectType;
|
||||||
|
if ((_objectType select 0) == "Soldier") then {
|
||||||
|
_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;
|
||||||
|
};
|
||||||
|
if ((_objectType select 0) == "Vehicle") then {
|
||||||
|
_atak_type = [_x] call armatak_fnc_extract_role;
|
||||||
|
_callsign = [_x] call armatak_fnc_extract_marker_callsign;
|
||||||
|
|
||||||
|
[_x, _atak_type, _callsign] call armatak_fnc_send_marker_cot;
|
||||||
|
};
|
||||||
|
if (unitIsUAV _x) then {
|
||||||
|
[_x] call armatak_fnc_send_drone_cot;
|
||||||
|
[_x] call armatak_fnc_send_digital_pointer_cot;
|
||||||
|
};
|
||||||
|
} forEach GVAR(syncedUnits);
|
||||||
|
}, 2, []] call CBA_fnc_addPerFrameHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
true;
|
||||||
60
addons/server/functions/fnc_ZeusCoreModuleConfig.sqf
Normal file
60
addons/server/functions/fnc_ZeusCoreModuleConfig.sqf
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
|
||||||
|
params ["_logic"];
|
||||||
|
|
||||||
|
_socket_is_running = missionNamespace getVariable ["armatak_tcp_socket_is_running", false];
|
||||||
|
|
||||||
|
if (_socket_is_running) exitWith {
|
||||||
|
["Socket was called twice","error", "TCP Socket"] call EFUNC(main,notify);
|
||||||
|
closeDialog 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
disableSerialization;
|
||||||
|
|
||||||
|
["Connecting to TCP Socket", "success", "TCP Socket"] call EFUNC(main,notify);
|
||||||
|
|
||||||
|
_tak_server_instance_address = ctrlText 14000;
|
||||||
|
_tak_server_instance_port = ctrlText 14001;
|
||||||
|
|
||||||
|
_tak_server_fulladdress = ((_tak_server_instance_address) + ":" + (_tak_server_instance_port));
|
||||||
|
|
||||||
|
missionNamespace setVariable ["armatak_server_instance", _tak_server_fulladdress];
|
||||||
|
missionNamespace setVariable ["armatak_tcp_socket_is_running", true];
|
||||||
|
missionNamespace setVariable ["armatak_group_colors", ["White", "Yellow", "Orange", "Magenta", "Red", "Maroon", "Purple", "DarkBlue", "Blue", "Cyan", "Teal", "Green", "DarkGreen", "Brown"]];
|
||||||
|
|
||||||
|
"armatak" callExtension ["tcp_socket:start", [_tak_server_fulladdress]];
|
||||||
|
|
||||||
|
_syncUnits = [];
|
||||||
|
|
||||||
|
missionNamespace setVariable ["armatak_marked_units", _syncUnits];
|
||||||
|
|
||||||
|
GVAR(syncedUnits) = missionNamespace getVariable "armatak_marked_units";
|
||||||
|
|
||||||
|
[{
|
||||||
|
GVAR(syncedUnits) = missionNamespace getVariable "armatak_marked_units";
|
||||||
|
|
||||||
|
{
|
||||||
|
_objectType = _x call BIS_fnc_objectType;
|
||||||
|
if ((_objectType select 0) == "Soldier") then {
|
||||||
|
_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;
|
||||||
|
};
|
||||||
|
if ((_objectType select 0) == "Vehicle") then {
|
||||||
|
_atak_type = [_x] call armatak_fnc_extract_role;
|
||||||
|
_callsign = [_x] call armatak_fnc_extract_marker_callsign;
|
||||||
|
|
||||||
|
[_x, _atak_type, _callsign] call armatak_fnc_send_marker_cot;
|
||||||
|
};
|
||||||
|
if (unitIsUAV _x) then {
|
||||||
|
[_x] call armatak_fnc_send_drone_cot;
|
||||||
|
[_x] call armatak_fnc_send_digital_pointer_cot;
|
||||||
|
};
|
||||||
|
} forEach GVAR(syncedUnits);
|
||||||
|
}, 2, []] call CBA_fnc_addPerFrameHandler;
|
||||||
|
|
||||||
|
deleteVehicle _logic;
|
||||||
|
closeDialog 1;
|
||||||
39
addons/server/functions/fnc_routerEntityAdd.sqf
Normal file
39
addons/server/functions/fnc_routerEntityAdd.sqf
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: Valmo
|
||||||
|
* Adds a unit into the global marked units array.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: The module logic <OBJECT>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [LOGIC] call armatak_server_fnc_routerEntityAdd;
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
|
||||||
|
params ["_logic"];
|
||||||
|
|
||||||
|
if (!local _logic) exitWith {};
|
||||||
|
|
||||||
|
private _unit = attachedTo _logic;
|
||||||
|
deleteVehicle _logic;
|
||||||
|
|
||||||
|
switch (false) do {
|
||||||
|
case (!isNull _unit): {
|
||||||
|
deleteVehicle _logic;
|
||||||
|
["Nothing selected", "error", "TCP Socket"] call EFUNC(main,notify);
|
||||||
|
};
|
||||||
|
default {
|
||||||
|
GVAR(syncedUnits) = missionNamespace getVariable "armatak_marked_units";
|
||||||
|
|
||||||
|
GVAR(syncedUnits) pushBack _unit;
|
||||||
|
|
||||||
|
missionNamespace setVariable ["armatak_marked_units", GVAR(syncedUnits)];
|
||||||
|
|
||||||
|
deleteVehicle _logic;
|
||||||
|
};
|
||||||
|
};
|
||||||
41
addons/server/functions/fnc_routerEntityRemove.sqf
Normal file
41
addons/server/functions/fnc_routerEntityRemove.sqf
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: Valmo
|
||||||
|
* Removes a unit from the global marked units array.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: The module logic <OBJECT>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [LOGIC] call armatak_server_fnc_routerEntityRemove;
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
|
||||||
|
params ["_logic"];
|
||||||
|
|
||||||
|
if (!local _logic) exitWith {};
|
||||||
|
|
||||||
|
private _unit = attachedTo _logic;
|
||||||
|
deleteVehicle _logic;
|
||||||
|
|
||||||
|
switch (false) do {
|
||||||
|
case (!isNull _unit): {
|
||||||
|
deleteVehicle _logic;
|
||||||
|
["Nothing selected", "error", "TCP Socket"] call EFUNC(main,notify);
|
||||||
|
};
|
||||||
|
default {
|
||||||
|
{
|
||||||
|
if (_x isEqualTo _unit) then {
|
||||||
|
GVAR(syncedUnits) deleteAt _forEachIndex;
|
||||||
|
};
|
||||||
|
} forEach GVAR(syncedUnits);
|
||||||
|
|
||||||
|
missionNmaespace setVariable ["armatak_marked_units", GVAR(syncedUnits)];
|
||||||
|
|
||||||
|
deleteVehicle _logic;
|
||||||
|
};
|
||||||
|
};
|
||||||
17
addons/server/script_component.hpp
Normal file
17
addons/server/script_component.hpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#define COMPONENT server
|
||||||
|
#define COMPONENT_BEAUTIFIED TCP Socket Client
|
||||||
|
#include "\armatak\armatak\addons\main\script_mod.hpp"
|
||||||
|
|
||||||
|
// #define DEBUG_MODE_FULL
|
||||||
|
// #define DISABLE_COMPILE_CACHE
|
||||||
|
// #define ENABLE_PERFORMANCE_COUNTERS
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED_CLIENT
|
||||||
|
#define DEBUG_MODE_FULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_SETTINGS_CLIENT
|
||||||
|
#define DEBUG_SETTINGS DEBUG_SETTINGS_CLIENT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "\z\ace\addons\main\script_macros.hpp"
|
||||||
1
addons/video/$PBOPREFIX$
Normal file
1
addons/video/$PBOPREFIX$
Normal file
@@ -0,0 +1 @@
|
|||||||
|
armatak\armatak\addons\video
|
||||||
11
addons/video/CfgEventHandlers.hpp
Normal file
11
addons/video/CfgEventHandlers.hpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
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));
|
||||||
|
};
|
||||||
|
};
|
||||||
72
addons/video/CfgVehicles.hpp
Normal file
72
addons/video/CfgVehicles.hpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
class CfgVehicles {
|
||||||
|
class Logic;
|
||||||
|
|
||||||
|
class Module_F : Logic
|
||||||
|
{
|
||||||
|
class AttributesBase
|
||||||
|
{
|
||||||
|
class Default;
|
||||||
|
class Edit;
|
||||||
|
class Combo;
|
||||||
|
class Checkbox;
|
||||||
|
class CheckboxNumber;
|
||||||
|
class ModuleDescription;
|
||||||
|
class Units;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModuleDescription
|
||||||
|
{
|
||||||
|
class AnyBrain;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
class EGVAR(server,moduleBase);
|
||||||
|
class GVAR(videoModule): EGVAR(server,moduleBase) {
|
||||||
|
scope = 2;
|
||||||
|
scopeCurator = 0;
|
||||||
|
displayname = "Video Streaming Handler";
|
||||||
|
icon = "\a3\Modules_F_Curator\Data\iconRadio_ca.paa";
|
||||||
|
category = QEGVAR(main,moduleCategory);
|
||||||
|
function = QFUNC(videoParser);
|
||||||
|
functionPriority = 1;
|
||||||
|
isGlobal = 0;
|
||||||
|
isTriggerActivated = 1;
|
||||||
|
isDisposable = 1;
|
||||||
|
is3den = 0;
|
||||||
|
curatorCanAttach = 0;
|
||||||
|
curatorInfoType = "RscDisplayAttributeModuleNuke";
|
||||||
|
canSetArea = 0;
|
||||||
|
canSetAreaShape = 0;
|
||||||
|
canSetAreaHeight = 0;
|
||||||
|
|
||||||
|
class Attributes: AttributesBase {
|
||||||
|
class GVAR(instanceAddress): Edit {
|
||||||
|
property = QGVAR(instanceAddress);
|
||||||
|
displayname = "MediaMTX Provider Address";
|
||||||
|
tooltip = "MediaMTX Provider Instance Address";
|
||||||
|
typeName = "STRING";
|
||||||
|
defaultValue = "localhost";
|
||||||
|
};
|
||||||
|
class GVAR(instancePort): Edit {
|
||||||
|
property = "armatak_module_mediamtx_video_stream_instance_port";
|
||||||
|
displayname = "MediaMTX Provider Port";
|
||||||
|
tooltip = "MediaMTX Provider Port for handling video streams";
|
||||||
|
typeName = "STRING";
|
||||||
|
defaultValue = "8554";
|
||||||
|
};
|
||||||
|
class GVAR(instanceAuthUser): Edit {
|
||||||
|
property = QGVAR(instanceAuthUser);
|
||||||
|
displayname = "MediaMTX Provider Username";
|
||||||
|
tooltip = "MediaMTX Provider Instance Username";
|
||||||
|
typeName = "STRING";
|
||||||
|
defaultValue = "administrator";
|
||||||
|
};
|
||||||
|
class GVAR(instanceAuthPassword): Edit {
|
||||||
|
property = QGVAR(instanceAuthPassword);
|
||||||
|
displayname = "MediaMTX Provider Password";
|
||||||
|
tooltip = "MediaMTX Provider Instance Password";
|
||||||
|
typeName = "STRING";
|
||||||
|
defaultValue = "password";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
1
addons/video/XEH_PREP.hpp
Normal file
1
addons/video/XEH_PREP.hpp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
PREP(videoParser);
|
||||||
9
addons/video/XEH_preInit.sqf
Normal file
9
addons/video/XEH_preInit.sqf
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
ADDON = false;
|
||||||
|
|
||||||
|
PREP_RECOMPILE_START;
|
||||||
|
#include "XEH_PREP.hpp"
|
||||||
|
PREP_RECOMPILE_END;
|
||||||
|
|
||||||
|
ADDON = true;
|
||||||
3
addons/video/XEH_preStart.sqf
Normal file
3
addons/video/XEH_preStart.sqf
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
#include "XEH_PREP.hpp"
|
||||||
42
addons/video/config.cpp
Normal file
42
addons/video/config.cpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
class CfgPatches {
|
||||||
|
class ADDON {
|
||||||
|
name = COMPONENT_NAME;
|
||||||
|
units[] = {
|
||||||
|
QGVAR(videoModule)
|
||||||
|
};
|
||||||
|
weapons[] = {};
|
||||||
|
requiredAddons[] = {
|
||||||
|
"cba_main",
|
||||||
|
"ace_main",
|
||||||
|
"armatak_main",
|
||||||
|
"armatak_server"
|
||||||
|
};
|
||||||
|
requiredVersion = REQUIRED_VERSION;
|
||||||
|
author = PROJECT_AUTHOR;
|
||||||
|
url = "https://github.com/valmojr/armatak";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class CfgMods {
|
||||||
|
class PREFIX {
|
||||||
|
name = "Arma Team Awareness Kit";
|
||||||
|
author = PROJECT_AUTHOR;
|
||||||
|
logo = "logo_ca.paa";
|
||||||
|
logoOver = "logo_hover_ca.paa";
|
||||||
|
tooltip = "ARMATAK";
|
||||||
|
tooltipOwned = "ARMATAK";
|
||||||
|
picture = "picture.paa";
|
||||||
|
actionName = "GitHub";
|
||||||
|
action = "https://github.com/valmojr/armatak";
|
||||||
|
overview = "ARMATAK Addons allows Arma 3 sessions to be parsed to TAK Clients";
|
||||||
|
hideName = 0;
|
||||||
|
hidePicture = 0;
|
||||||
|
dlcColor[] = { 0.23, 0.39, 0.30, 1 };
|
||||||
|
logoSmall = "logo_small_ca.paa";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "CfgEventHandlers.hpp"
|
||||||
|
#include "CfgVehicles.hpp"
|
||||||
83
addons/video/functions/fnc_videoParser.sqf
Normal file
83
addons/video/functions/fnc_videoParser.sqf
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
|
||||||
|
params [
|
||||||
|
["_logic", objNull, [objNull]],
|
||||||
|
["_units", [], [[]]],
|
||||||
|
["_activated", true, [true]]
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isServer) exitWith {
|
||||||
|
private _instance_address = GETVAR(_logic,GVAR(instanceAddress),false);
|
||||||
|
private _instance_port = GETVAR(_logic,GVAR(instancePort),false);
|
||||||
|
private _instance_auth_user = GETVAR(_logic,GVAR(instanceAuthUser),false);
|
||||||
|
private _instance_auth_pass = GETVAR(_logic,GVAR(instanceAuthPassword),false);
|
||||||
|
|
||||||
|
SETMVAR(GVAR(instanceAddress),_instance_address);
|
||||||
|
SETMVAR(GVAR(instancePort),_instance_port);
|
||||||
|
SETMVAR(GVAR(instanceAuthUser),_instance_auth_user);
|
||||||
|
SETMVAR(GVAR(instanceAuthPassword),_instance_auth_pass);
|
||||||
|
|
||||||
|
_startAction = [
|
||||||
|
QGVAR(startStream),
|
||||||
|
"Start Video Feed",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
_uuid = (_this select 0) call armatak_fnc_extract_uuid;
|
||||||
|
_uuid_short = _uuid select [0, 8];
|
||||||
|
_role = roleDescription (_this select 0);
|
||||||
|
_name = name (_this select 0);
|
||||||
|
|
||||||
|
_role = [_role] call BIS_fnc_filterString;
|
||||||
|
_name = [_name] call BIS_fnc_filterString;
|
||||||
|
|
||||||
|
_stream_path = _name + "_" + _role + "_" + _uuid_short;
|
||||||
|
|
||||||
|
armatak_mediamtx_video_stream_instance_address = GETMVAR(instance_address,false);
|
||||||
|
armatak_mediamtx_video_stream_instance_port = missionNamespace getVariable "instance_port";
|
||||||
|
armatak_mediamtx_video_stream_instance_auth_user = missionNamespace getVariable "instance_auth_user";
|
||||||
|
armatak_mediamtx_video_stream_instance_auth_pass = missionNamespace getVariable "instance_auth_pass";
|
||||||
|
|
||||||
|
"armatak" callExtension ["video_stream:start", [armatak_mediamtx_video_stream_instance_address, armatak_mediamtx_video_stream_instance_port, _stream_path, armatak_mediamtx_video_stream_instance_auth_user, armatak_mediamtx_video_stream_instance_auth_pass]];
|
||||||
|
(_this select 0) setVariable ["armatak_video_feed_is_streaming", true];
|
||||||
|
},
|
||||||
|
{
|
||||||
|
(_this select 0) getVariable "armatak_video_feed_is_streaming" == false
|
||||||
|
}
|
||||||
|
] call ace_interact_menu_fnc_createAction;
|
||||||
|
[
|
||||||
|
"Man",
|
||||||
|
1,
|
||||||
|
["ACE_SelfActions"],
|
||||||
|
_startAction,
|
||||||
|
true
|
||||||
|
] call ace_interact_menu_fnc_addActionToClass;
|
||||||
|
|
||||||
|
_stopAction = [
|
||||||
|
"ArmatakStopStream",
|
||||||
|
"Stop Video Feed",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
"armatak" callExtension ["video_stream:stop", []];
|
||||||
|
SETVAR(_this select 0,GVAR(isStreaming),false);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GETVAR((this select 0),GVAR(isStreaming),false)
|
||||||
|
}
|
||||||
|
] call ace_interact_menu_fnc_createAction;
|
||||||
|
[
|
||||||
|
"Man",
|
||||||
|
1,
|
||||||
|
["ACE_SelfActions"],
|
||||||
|
_stopAction,
|
||||||
|
true
|
||||||
|
] call ace_interact_menu_fnc_addActionToClass;
|
||||||
|
if (isMultiplayer) then {
|
||||||
|
{
|
||||||
|
SETVAR(_x,GVAR(isStreaming),false);
|
||||||
|
} forEach playableUnits;
|
||||||
|
} else {
|
||||||
|
SETVAR(player,GVAR(isStreaming),false);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
true;
|
||||||
17
addons/video/script_component.hpp
Normal file
17
addons/video/script_component.hpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#define COMPONENT video
|
||||||
|
#define COMPONENT_BEAUTIFIED Video Streaming
|
||||||
|
#include "\armatak\armatak\addons\main\script_mod.hpp"
|
||||||
|
|
||||||
|
// #define DEBUG_MODE_FULL
|
||||||
|
// #define DISABLE_COMPILE_CACHE
|
||||||
|
// #define ENABLE_PERFORMANCE_COUNTERS
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED_MAIN
|
||||||
|
#define DEBUG_MODE_FULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_SETTINGS_MAIN
|
||||||
|
#define DEBUG_SETTINGS DEBUG_SETTINGS_MAIN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "\z\ace\addons\main\script_macros.hpp"
|
||||||
1
include/x/cba/addons/main/$PBOPREFIX$
Normal file
1
include/x/cba/addons/main/$PBOPREFIX$
Normal file
@@ -0,0 +1 @@
|
|||||||
|
x\cba\addons\main
|
||||||
1834
include/x/cba/addons/main/script_macros_common.hpp
Normal file
1834
include/x/cba/addons/main/script_macros_common.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1
include/x/cba/addons/xeh/$PBOPREFIX$
Normal file
1
include/x/cba/addons/xeh/$PBOPREFIX$
Normal file
@@ -0,0 +1 @@
|
|||||||
|
x\cba\addons\xeh
|
||||||
146
include/x/cba/addons/xeh/script_xeh.hpp
Normal file
146
include/x/cba/addons/xeh/script_xeh.hpp
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
Header: script_xeh.hpp
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Used internally.
|
||||||
|
*/
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MACRO: EXTENDED_EVENTHANDLERS
|
||||||
|
// Add all XEH event handlers
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define EXTENDED_EVENTHANDLERS init = "call cba_xeh_fnc_init"; \
|
||||||
|
fired = "call cba_xeh_fnc_fired"; \
|
||||||
|
animChanged = "call cba_xeh_fnc_animChanged"; \
|
||||||
|
animDone = "call cba_xeh_fnc_animDone"; \
|
||||||
|
animStateChanged = "call cba_xeh_fnc_animStateChanged"; \
|
||||||
|
assembled = "call cba_xeh_fnc_assembled"; \
|
||||||
|
attached = "call cba_xeh_fnc_attached"; \
|
||||||
|
cargoLoaded = "call cba_xeh_fnc_cargoLoaded"; \
|
||||||
|
cargoUnloaded = "call cba_xeh_fnc_cargoUnloaded"; \
|
||||||
|
containerClosed = "call cba_xeh_fnc_containerClosed"; \
|
||||||
|
containerOpened = "call cba_xeh_fnc_containerOpened"; \
|
||||||
|
controlsShifted = "call cba_xeh_fnc_controlsShifted"; \
|
||||||
|
dammaged = "call cba_xeh_fnc_dammaged"; \
|
||||||
|
deleted = "call cba_xeh_fnc_deleted"; \
|
||||||
|
detached = "call cba_xeh_fnc_detached"; \
|
||||||
|
disassembled = "call cba_xeh_fnc_disassembled"; \
|
||||||
|
engine = "call cba_xeh_fnc_engine"; \
|
||||||
|
epeContact = "call cba_xeh_fnc_epeContact"; \
|
||||||
|
epeContactEnd = "call cba_xeh_fnc_epeContactEnd"; \
|
||||||
|
epeContactStart = "call cba_xeh_fnc_epeContactStart"; \
|
||||||
|
explosion = "call cba_xeh_fnc_explosion"; \
|
||||||
|
firedMan = "call cba_xeh_fnc_firedMan"; \
|
||||||
|
firedNear = "call cba_xeh_fnc_firedNear"; \
|
||||||
|
fuel = "call cba_xeh_fnc_cba_xeh_fuel"; \
|
||||||
|
gear = "call cba_xeh_fnc_gear"; \
|
||||||
|
gestureChanged = "call cba_xeh_fnc_gestureChanged"; \
|
||||||
|
gestureDone = "call cba_xeh_fnc_gestureDone"; \
|
||||||
|
getIn = "call cba_xeh_fnc_getIn"; \
|
||||||
|
getInMan = "call cba_xeh_fnc_getInMan"; \
|
||||||
|
getOut = "call cba_xeh_fnc_getOut"; \
|
||||||
|
getOutMan = "call cba_xeh_fnc_getOutMan"; \
|
||||||
|
handleHeal = "call cba_xeh_fnc_handleHeal"; \
|
||||||
|
hit = "call cba_xeh_fnc_hit"; \
|
||||||
|
hitPart = "call cba_xeh_fnc_hitPart"; \
|
||||||
|
incomingMissile = "call cba_xeh_fnc_incomingMissile"; \
|
||||||
|
inventoryClosed = "call cba_xeh_fnc_inventoryClosed"; \
|
||||||
|
inventoryOpened = "call cba_xeh_fnc_inventoryOpened"; \
|
||||||
|
killed = "call cba_xeh_fnc_killed"; \
|
||||||
|
landedTouchDown = "call cba_xeh_fnc_landedTouchDown"; \
|
||||||
|
landedStopped = "call cba_xeh_fnc_landedStopped"; \
|
||||||
|
leaningChanged = "call cba_xeh_fnc_leaningChanged"; \
|
||||||
|
local = "call cba_xeh_fnc_local"; \
|
||||||
|
magazineReloading = "call cba_xeh_fnc_magazineReloading"; \
|
||||||
|
opticsModeChanged = "call cba_xeh_fnc_opticsModeChanged"; \
|
||||||
|
opticsSwitch = "call cba_xeh_fnc_opticsSwitch"; \
|
||||||
|
put = "call cba_xeh_fnc_put"; \
|
||||||
|
reloaded = "call cba_xeh_fnc_reloaded"; \
|
||||||
|
respawn = "call cba_xeh_fnc_respawn"; \
|
||||||
|
ropeAttach = "call cba_xeh_fnc_ropeAttach"; \
|
||||||
|
ropeBreak = "call cba_xeh_fnc_ropeBreak"; \
|
||||||
|
seatSwitched = "call cba_xeh_fnc_seatSwitched"; \
|
||||||
|
seatSwitchedMan = "call cba_xeh_fnc_seatSwitchedMan"; \
|
||||||
|
slotItemChanged = "call cba_xeh_fnc_slotItemChanged"; \
|
||||||
|
suppressed = "call cba_xeh_fnc_suppressed"; \
|
||||||
|
soundPlayed = "call cba_xeh_fnc_soundPlayed"; \
|
||||||
|
take = "call cba_xeh_fnc_take"; \
|
||||||
|
turnIn = "call cba_xeh_fnc_turnIn"; \
|
||||||
|
turnOut = "call cba_xeh_fnc_turnOut"; \
|
||||||
|
visionModeChanged = "call cba_xeh_fnc_visionModeChanged"; \
|
||||||
|
weaponAssembled = "call cba_xeh_fnc_weaponAssembled"; \
|
||||||
|
weaponChanged = "call cba_xeh_fnc_weaponChanged"; \
|
||||||
|
weaponDisassembled = "call cba_xeh_fnc_weaponDisassembled"; \
|
||||||
|
weaponDeployed = "call cba_xeh_fnc_weaponDeployed"; \
|
||||||
|
weaponRested = "call cba_xeh_fnc_weaponRested";
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
MACRO: DELETE_EVENTHANDLERS
|
||||||
|
|
||||||
|
Removes all event handlers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DELETE_EVENTHANDLERS init = ""; \
|
||||||
|
fired = ""; \
|
||||||
|
animChanged = ""; \
|
||||||
|
animDone = ""; \
|
||||||
|
animStateChanged = ""; \
|
||||||
|
assembled = ""; \
|
||||||
|
attached = ""; \
|
||||||
|
cargoLoaded = ""; \
|
||||||
|
cargoUnloaded = ""; \
|
||||||
|
containerClosed = ""; \
|
||||||
|
containerOpened = ""; \
|
||||||
|
controlsShifted = ""; \
|
||||||
|
dammaged = ""; \
|
||||||
|
deleted = ""; \
|
||||||
|
detached = ""; \
|
||||||
|
disassembled = ""; \
|
||||||
|
engine = ""; \
|
||||||
|
epeContact = ""; \
|
||||||
|
epeContactEnd = ""; \
|
||||||
|
epeContactStart = ""; \
|
||||||
|
explosion = ""; \
|
||||||
|
firedMan = ""; \
|
||||||
|
firedNear = ""; \
|
||||||
|
fuel = ""; \
|
||||||
|
gear = ""; \
|
||||||
|
gestureChanged = ""; \
|
||||||
|
gestureDone = "" \
|
||||||
|
getIn = ""; \
|
||||||
|
getInMan = ""; \
|
||||||
|
getOut = ""; \
|
||||||
|
getOutMan = ""; \
|
||||||
|
handleHeal = ""; \
|
||||||
|
hit = ""; \
|
||||||
|
hitPart = ""; \
|
||||||
|
incomingMissile = ""; \
|
||||||
|
inventoryClosed = ""; \
|
||||||
|
inventoryOpened = ""; \
|
||||||
|
killed = ""; \
|
||||||
|
landedTouchDown = ""; \
|
||||||
|
landedStopped = ""; \
|
||||||
|
leaningChanged = ""; \
|
||||||
|
local = ""; \
|
||||||
|
magazineReloading = ""; \
|
||||||
|
opticsModeChanged = ""; \
|
||||||
|
opticsSwitch = ""; \
|
||||||
|
put = ""; \
|
||||||
|
reloaded = ""; \
|
||||||
|
respawn = ""; \
|
||||||
|
ropeAttach = ""; \
|
||||||
|
ropeBreak = ""; \
|
||||||
|
seatSwitched = ""; \
|
||||||
|
seatSwitchedMan = ""; \
|
||||||
|
soundPlayed = ""; \
|
||||||
|
suppressed = ""; \
|
||||||
|
take = ""; \
|
||||||
|
turnIn = ""; \
|
||||||
|
turnOut = ""; \
|
||||||
|
visionModeChanged = ""; \
|
||||||
|
weaponAssembled = ""; \
|
||||||
|
weaponChanged = ""; \
|
||||||
|
weaponDisassembled = ""; \
|
||||||
|
weaponDeployed = ""; \
|
||||||
|
weaponRested = "";
|
||||||
58
include/z/ace/addons/main/script_debug.hpp
Normal file
58
include/z/ace/addons/main/script_debug.hpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
Fast Recompiling via function
|
||||||
|
**/
|
||||||
|
// #define DISABLE_COMPILE_CACHE
|
||||||
|
// To Use: [] call ACE_PREP_RECOMPILE;
|
||||||
|
|
||||||
|
#ifdef DISABLE_COMPILE_CACHE
|
||||||
|
#define LINKFUNC(x) {call FUNC(x)}
|
||||||
|
#define PREP_RECOMPILE_START if (isNil "ACE_PREP_RECOMPILE") then {ACE_RECOMPILES = []; ACE_PREP_RECOMPILE = {{call _x} forEach ACE_RECOMPILES;}}; private _recomp = {
|
||||||
|
#define PREP_RECOMPILE_END }; call _recomp; ACE_RECOMPILES pushBack _recomp;
|
||||||
|
#else
|
||||||
|
#define LINKFUNC(x) FUNC(x)
|
||||||
|
#define PREP_RECOMPILE_START ; /* disabled */
|
||||||
|
#define PREP_RECOMPILE_END ; /* disabled */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
STACK TRACING
|
||||||
|
**/
|
||||||
|
//#define ENABLE_CALLSTACK
|
||||||
|
//#define ENABLE_PERFORMANCE_COUNTERS
|
||||||
|
//#define DEBUG_EVENTS
|
||||||
|
|
||||||
|
#ifdef ENABLE_CALLSTACK
|
||||||
|
#define CALLSTACK(function) {if(ACE_IS_ERRORED) then { ['AUTO','AUTO'] call ACE_DUMPSTACK_FNC; ACE_IS_ERRORED = false; }; ACE_IS_ERRORED = true; ACE_STACK_TRACE set [ACE_STACK_DEPTH, [diag_tickTime, __FILE__, __LINE__, ACE_CURRENT_FUNCTION, 'ANON', _this]]; ACE_STACK_DEPTH = ACE_STACK_DEPTH + 1; ACE_CURRENT_FUNCTION = 'ANON'; private _ret = _this call ##function; ACE_STACK_DEPTH = ACE_STACK_DEPTH - 1; ACE_IS_ERRORED = false; _ret;}
|
||||||
|
#define CALLSTACK_NAMED(function, functionName) {if(ACE_IS_ERRORED) then { ['AUTO','AUTO'] call ACE_DUMPSTACK_FNC; ACE_IS_ERRORED = false; }; ACE_IS_ERRORED = true; ACE_STACK_TRACE set [ACE_STACK_DEPTH, [diag_tickTime, __FILE__, __LINE__, ACE_CURRENT_FUNCTION, functionName, _this]]; ACE_STACK_DEPTH = ACE_STACK_DEPTH + 1; ACE_CURRENT_FUNCTION = functionName; private _ret = _this call ##function; ACE_STACK_DEPTH = ACE_STACK_DEPTH - 1; ACE_IS_ERRORED = false; _ret;}
|
||||||
|
#define DUMPSTACK ([__FILE__, __LINE__] call ACE_DUMPSTACK_FNC)
|
||||||
|
|
||||||
|
#define FUNC(var1) {if(ACE_IS_ERRORED) then { ['AUTO','AUTO'] call ACE_DUMPSTACK_FNC; ACE_IS_ERRORED = false; }; ACE_IS_ERRORED = true; ACE_STACK_TRACE set [ACE_STACK_DEPTH, [diag_tickTime, __FILE__, __LINE__, ACE_CURRENT_FUNCTION, 'TRIPLES(ADDON,fnc,var1)', _this]]; ACE_STACK_DEPTH = ACE_STACK_DEPTH + 1; ACE_CURRENT_FUNCTION = 'TRIPLES(ADDON,fnc,var1)'; private _ret = _this call TRIPLES(ADDON,fnc,var1); ACE_STACK_DEPTH = ACE_STACK_DEPTH - 1; ACE_IS_ERRORED = false; _ret;}
|
||||||
|
#define EFUNC(var1,var2) {if(ACE_IS_ERRORED) then { ['AUTO','AUTO'] call ACE_DUMPSTACK_FNC; ACE_IS_ERRORED = false; }; ACE_IS_ERRORED = true; ACE_STACK_TRACE set [ACE_STACK_DEPTH, [diag_tickTime, __FILE__, __LINE__, ACE_CURRENT_FUNCTION, 'TRIPLES(DOUBLES(PREFIX,var1),fnc,var2)', _this]]; ACE_STACK_DEPTH = ACE_STACK_DEPTH + 1; ACE_CURRENT_FUNCTION = 'TRIPLES(DOUBLES(PREFIX,var1),fnc,var2)'; private _ret = _this call TRIPLES(DOUBLES(PREFIX,var1),fnc,var2); ACE_STACK_DEPTH = ACE_STACK_DEPTH - 1; ACE_IS_ERRORED = false; _ret;}
|
||||||
|
#else
|
||||||
|
#define CALLSTACK(function) function
|
||||||
|
#define CALLSTACK_NAMED(function, functionName) function
|
||||||
|
#define DUMPSTACK ; /* disabled */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
PERFORMANCE COUNTERS SECTION
|
||||||
|
**/
|
||||||
|
//#define ENABLE_PERFORMANCE_COUNTERS
|
||||||
|
// To Use: [] call ace_common_fnc_dumpPerformanceCounters;
|
||||||
|
|
||||||
|
#ifdef ENABLE_PERFORMANCE_COUNTERS
|
||||||
|
#define CBA_fnc_addPerFrameHandler { private _ret = call CBA_fnc_addPerFrameHandler; if(isNil "ACE_PFH_COUNTER" ) then { ACE_PFH_COUNTER=[]; }; ACE_PFH_COUNTER pushBack [[_ret, __FILE__, __LINE__], _this]; _ret }
|
||||||
|
|
||||||
|
#define CREATE_COUNTER(x) if(isNil "ACE_COUNTERS" ) then { ACE_COUNTERS=[]; }; GVAR(DOUBLES(x,counter))=[]; GVAR(DOUBLES(x,counter)) set[0, QUOTE(GVAR(DOUBLES(x,counter)))]; GVAR(DOUBLES(x,counter)) set[1, diag_tickTime]; ACE_COUNTERS pushBack GVAR(DOUBLES(x,counter));
|
||||||
|
#define BEGIN_COUNTER(x) if(isNil QUOTE(GVAR(DOUBLES(x,counter)))) then { CREATE_COUNTER(x) }; GVAR(DOUBLES(x,counter)) set[2, diag_tickTime];
|
||||||
|
#define END_COUNTER(x) GVAR(DOUBLES(x,counter)) pushBack [(GVAR(DOUBLES(x,counter)) select 2), diag_tickTime];
|
||||||
|
|
||||||
|
#define DUMP_COUNTERS ([__FILE__, __LINE__] call ACE_DUMPCOUNTERS_FNC)
|
||||||
|
#else
|
||||||
|
#define CREATE_COUNTER(x) ; /* disabled */
|
||||||
|
#define BEGIN_COUNTER(x) ; /* disabled */
|
||||||
|
#define END_COUNTER(x) ; /* disabled */
|
||||||
|
#define DUMP_COUNTERS ; /* disabled */
|
||||||
|
#endif
|
||||||
179
include/z/ace/addons/main/script_macros.hpp
Normal file
179
include/z/ace/addons/main/script_macros.hpp
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
#define DEBUG_SYNCHRONOUS
|
||||||
|
#include "\x\cba\addons\main\script_macros_common.hpp"
|
||||||
|
#include "\x\cba\addons\xeh\script_xeh.hpp"
|
||||||
|
|
||||||
|
// Default versioning level
|
||||||
|
#define DEFAULT_VERSIONING_LEVEL 2
|
||||||
|
|
||||||
|
#define DGVAR(varName) if(isNil "ACE_DEBUG_NAMESPACE") then { ACE_DEBUG_NAMESPACE = []; }; if(!(QUOTE(GVAR(varName)) in ACE_DEBUG_NAMESPACE)) then { PUSH(ACE_DEBUG_NAMESPACE, QUOTE(GVAR(varName))); }; GVAR(varName)
|
||||||
|
#define DVAR(varName) if(isNil "ACE_DEBUG_NAMESPACE") then { ACE_DEBUG_NAMESPACE = []; }; if(!(QUOTE(varName) in ACE_DEBUG_NAMESPACE)) then { PUSH(ACE_DEBUG_NAMESPACE, QUOTE(varName)); }; varName
|
||||||
|
#define DFUNC(var1) TRIPLES(ADDON,fnc,var1)
|
||||||
|
#define DEFUNC(var1,var2) TRIPLES(DOUBLES(PREFIX,var1),fnc,var2)
|
||||||
|
|
||||||
|
#undef QFUNC
|
||||||
|
#undef QEFUNC
|
||||||
|
#define QFUNC(var1) QUOTE(DFUNC(var1))
|
||||||
|
#define QEFUNC(var1,var2) QUOTE(DEFUNC(var1,var2))
|
||||||
|
|
||||||
|
#define GETVAR_SYS(var1,var2) getVariable [ARR_2(QUOTE(var1),var2)]
|
||||||
|
#define SETVAR_SYS(var1,var2) setVariable [ARR_2(QUOTE(var1),var2)]
|
||||||
|
#define SETPVAR_SYS(var1,var2) setVariable [ARR_3(QUOTE(var1),var2,true)]
|
||||||
|
|
||||||
|
#undef GETVAR
|
||||||
|
#define GETVAR(var1,var2,var3) (var1 GETVAR_SYS(var2,var3))
|
||||||
|
#define GETMVAR(var1,var2) (missionNamespace GETVAR_SYS(var1,var2))
|
||||||
|
#define GETUVAR(var1,var2) (uiNamespace GETVAR_SYS(var1,var2))
|
||||||
|
#define GETPRVAR(var1,var2) (profileNamespace GETVAR_SYS(var1,var2))
|
||||||
|
#define GETPAVAR(var1,var2) (parsingNamespace GETVAR_SYS(var1,var2))
|
||||||
|
|
||||||
|
#undef SETVAR
|
||||||
|
#define SETVAR(var1,var2,var3) var1 SETVAR_SYS(var2,var3)
|
||||||
|
#define SETPVAR(var1,var2,var3) var1 SETPVAR_SYS(var2,var3)
|
||||||
|
#define SETMVAR(var1,var2) missionNamespace SETVAR_SYS(var1,var2)
|
||||||
|
#define SETUVAR(var1,var2) uiNamespace SETVAR_SYS(var1,var2)
|
||||||
|
#define SETPRVAR(var1,var2) profileNamespace SETVAR_SYS(var1,var2)
|
||||||
|
#define SETPAVAR(var1,var2) parsingNamespace SETVAR_SYS(var1,var2)
|
||||||
|
|
||||||
|
#define GETGVAR(var1,var2) GETMVAR(GVAR(var1),var2)
|
||||||
|
#define GETEGVAR(var1,var2,var3) GETMVAR(EGVAR(var1,var2),var3)
|
||||||
|
|
||||||
|
#define ARR_SELECT(ARRAY,INDEX,DEFAULT) (if (count ARRAY > INDEX) then {ARRAY select INDEX} else {DEFAULT})
|
||||||
|
#define ANY_OF(ARRAY,CONDITION) (ARRAY findIf {CONDITION} != -1)
|
||||||
|
|
||||||
|
// ACEX Merge
|
||||||
|
#define ACEX_PREFIX acex
|
||||||
|
#define XADDON DOUBLES(ACEX_PREFIX,COMPONENT)
|
||||||
|
#define XGVAR(var) DOUBLES(XADDON,var)
|
||||||
|
#define EXGVAR(var1,var2) TRIPLES(ACEX_PREFIX,var1,var2)
|
||||||
|
#define QXGVAR(var) QUOTE(XGVAR(var))
|
||||||
|
#define QEXGVAR(var1,var2) QUOTE(EXGVAR(var1,var2))
|
||||||
|
#define QQXGVAR(var) QUOTE(QXGVAR(var))
|
||||||
|
#define QQEXGVAR(var1,var2) QUOTE(QEXGVAR(var1,var2))
|
||||||
|
#define ACEX_PREP(func) PREP(func); TRIPLES(XADDON,fnc,func) = DFUNC(func)
|
||||||
|
|
||||||
|
|
||||||
|
#define MACRO_ADDWEAPON(WEAPON,COUNT) class _xx_##WEAPON { \
|
||||||
|
weapon = #WEAPON; \
|
||||||
|
count = COUNT; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MACRO_ADDITEM(ITEM,COUNT) class _xx_##ITEM { \
|
||||||
|
name = #ITEM; \
|
||||||
|
count = COUNT; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MACRO_ADDMAGAZINE(MAGAZINE,COUNT) class _xx_##MAGAZINE { \
|
||||||
|
magazine = #MAGAZINE; \
|
||||||
|
count = COUNT; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MACRO_ADDBACKPACK(BACKPACK,COUNT) class _xx_##BACKPACK { \
|
||||||
|
backpack = #BACKPACK; \
|
||||||
|
count = COUNT; \
|
||||||
|
}
|
||||||
|
|
||||||
|
// weapon types
|
||||||
|
#define TYPE_WEAPON_PRIMARY 1
|
||||||
|
#define TYPE_WEAPON_HANDGUN 2
|
||||||
|
#define TYPE_WEAPON_SECONDARY 4
|
||||||
|
// magazine types
|
||||||
|
#define TYPE_MAGAZINE_HANDGUN_AND_GL 16 // mainly
|
||||||
|
#define TYPE_MAGAZINE_PRIMARY_AND_THROW 256
|
||||||
|
#define TYPE_MAGAZINE_SECONDARY_AND_PUT 512 // mainly
|
||||||
|
#define TYPE_MAGAZINE_MISSILE 768
|
||||||
|
// more types
|
||||||
|
#define TYPE_BINOCULAR_AND_NVG 4096
|
||||||
|
#define TYPE_WEAPON_VEHICLE 65536
|
||||||
|
#define TYPE_ITEM 131072
|
||||||
|
// item types
|
||||||
|
#define TYPE_DEFAULT 0
|
||||||
|
#define TYPE_MUZZLE 101
|
||||||
|
#define TYPE_OPTICS 201
|
||||||
|
#define TYPE_FLASHLIGHT 301
|
||||||
|
#define TYPE_BIPOD 302
|
||||||
|
#define TYPE_FIRST_AID_KIT 401
|
||||||
|
#define TYPE_FINS 501 // not implemented
|
||||||
|
#define TYPE_BREATHING_BOMB 601 // not implemented
|
||||||
|
#define TYPE_NVG 602
|
||||||
|
#define TYPE_GOGGLE 603
|
||||||
|
#define TYPE_SCUBA 604 // not implemented
|
||||||
|
#define TYPE_HEADGEAR 605
|
||||||
|
#define TYPE_FACTOR 607
|
||||||
|
#define TYPE_MAP 608
|
||||||
|
#define TYPE_COMPASS 609
|
||||||
|
#define TYPE_WATCH 610
|
||||||
|
#define TYPE_RADIO 611
|
||||||
|
#define TYPE_GPS 612
|
||||||
|
#define TYPE_HMD 616
|
||||||
|
#define TYPE_BINOCULAR 617
|
||||||
|
#define TYPE_MEDIKIT 619
|
||||||
|
#define TYPE_TOOLKIT 620
|
||||||
|
#define TYPE_UAV_TERMINAL 621
|
||||||
|
#define TYPE_VEST 701
|
||||||
|
#define TYPE_UNIFORM 801
|
||||||
|
#define TYPE_BACKPACK 901
|
||||||
|
|
||||||
|
#ifdef DISABLE_COMPILE_CACHE
|
||||||
|
#undef PREP
|
||||||
|
#define PREP(fncName) DFUNC(fncName) = compile preprocessFileLineNumbers QPATHTOF(functions\DOUBLES(fnc,fncName).sqf)
|
||||||
|
#else
|
||||||
|
#undef PREP
|
||||||
|
#define PREP(fncName) [QPATHTOF(functions\DOUBLES(fnc,fncName).sqf), QFUNC(fncName)] call CBA_fnc_compileFunction
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PREP_MODULE(folder) [] call compile preprocessFileLineNumbers QPATHTOF(folder\__PREP__.sqf)
|
||||||
|
|
||||||
|
#define ACE_isHC (!hasInterface && !isDedicated)
|
||||||
|
|
||||||
|
#define IDC_STAMINA_BAR 193
|
||||||
|
|
||||||
|
#define ACE_DEPRECATED(arg1,arg2,arg3) WARNING_3("%1 is deprecated. Support will be dropped in version %2. Replaced by: %3",arg1,arg2,arg3)
|
||||||
|
|
||||||
|
#define PFORMAT_10(MESSAGE,A,B,C,D,E,F,G,H,I,J) \
|
||||||
|
format ['%1: A=%2, B=%3, C=%4, D=%5, E=%6, F=%7, G=%8, H=%9, I=%10 J=%11', MESSAGE, RETNIL(A), RETNIL(B), RETNIL(C), RETNIL(D), RETNIL(E), RETNIL(F), RETNIL(G), RETNIL(H), RETNIL(I), RETNIL(J)]
|
||||||
|
#ifdef DEBUG_MODE_FULL
|
||||||
|
#define TRACE_10(MESSAGE,A,B,C,D,E,F,G,H,I,J) LOG_SYS_FILELINENUMBERS('TRACE',PFORMAT_10(str diag_frameNo + ' ' + (MESSAGE),A,B,C,D,E,F,G,H,I,J))
|
||||||
|
#else
|
||||||
|
#define TRACE_10(MESSAGE,A,B,C,D,E,F,G,H,I,J) /* disabled */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define GRAVITY 9.8066
|
||||||
|
|
||||||
|
#define SD_TO_MIN_MAX(d) ((d) * 3.371) // Standard deviation -> min / max of random [min, mid, max]
|
||||||
|
|
||||||
|
// Angular unit conversion
|
||||||
|
// Conversion factor: 54 / (5 * PI)
|
||||||
|
#define MRAD_TO_MOA(d) ((d) * 3.43774677)
|
||||||
|
// Conversion factor: (5 * PI) / 54
|
||||||
|
#define MOA_TO_MRAD(d) ((d) * 0.29088821)
|
||||||
|
// Conversion factor: 60
|
||||||
|
#define DEG_TO_MOA(d) ((d) * 60)
|
||||||
|
// Conversion factor: 1 / 60
|
||||||
|
#define MOA_TO_DEG(d) ((d) / 60)
|
||||||
|
// Conversion factor: (50 * PI) / 9
|
||||||
|
#define DEG_TO_MRAD(d) ((d) * 17.45329252)
|
||||||
|
// Conversion factor: 9 / (50 * PI)
|
||||||
|
#define MRAD_TO_DEG(d) ((d) / 17.45329252)
|
||||||
|
// Conversion factor: PI / 10800
|
||||||
|
#define MOA_TO_RAD(d) ((d) * 0.00029088)
|
||||||
|
|
||||||
|
#define ZEUS_ACTION_CONDITION ([_target, {QUOTE(QUOTE(ADDON)) in curatorAddons _this}, missionNamespace, QUOTE(QGVAR(zeusCheck)), 1E11, 'ace_interactMenuClosed'] call EFUNC(common,cachedCall))
|
||||||
|
|
||||||
|
#define SUBSKILLS ["aimingAccuracy", "aimingShake", "aimingSpeed", "spotDistance", "spotTime", "courage", "reloadSpeed", "commanding", "general"]
|
||||||
|
|
||||||
|
// macro add a dummy cfgPatch and notLoaded entry
|
||||||
|
#define ACE_PATCH_NOT_LOADED(NAME,CAUSE) \
|
||||||
|
class CfgPatches { \
|
||||||
|
class DOUBLES(NAME,notLoaded) { \
|
||||||
|
units[] = {}; \
|
||||||
|
weapons[] = {}; \
|
||||||
|
requiredVersion = REQUIRED_VERSION; \
|
||||||
|
requiredAddons[] = {"ace_main"}; \
|
||||||
|
VERSION_CONFIG; \
|
||||||
|
}; \
|
||||||
|
}; \
|
||||||
|
class ace_notLoaded { \
|
||||||
|
NAME = CAUSE; \
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "\z\ace\addons\main\script_debug.hpp"
|
||||||
2
mod.cpp
2
mod.cpp
@@ -7,7 +7,7 @@ tooltipOwned = "ARMATAK";
|
|||||||
picture = "picture.paa";
|
picture = "picture.paa";
|
||||||
actionName = "GitHub";
|
actionName = "GitHub";
|
||||||
action = "https://github.com/valmojr/armatak";
|
action = "https://github.com/valmojr/armatak";
|
||||||
overview = "ARMATAK Addons is Full Stack Project to handle Arma 3 Sessions as real loc entities on TAK Clients";
|
overview = "ARMATAK Addons allows Arma 3 sessions to be parsed to TAK Clients";
|
||||||
hideName = 0;
|
hideName = 0;
|
||||||
hidePicture = 0;
|
hidePicture = 0;
|
||||||
dlcColor[] = { 0.23, 0.39, 0.30, 1 };
|
dlcColor[] = { 0.23, 0.39, 0.30, 1 };
|
||||||
|
|||||||
109
src/cot/cot.rs
Normal file
109
src/cot/cot.rs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
use uuid::Uuid;
|
||||||
|
use chrono::{Duration, SecondsFormat, Utc};
|
||||||
|
|
||||||
|
pub struct CursorOverTime {
|
||||||
|
pub uuid: Option<String>,
|
||||||
|
pub r#type: Option<String>,
|
||||||
|
pub point_lat: f64,
|
||||||
|
pub point_lon: f64,
|
||||||
|
pub point_hae: f32,
|
||||||
|
pub point_ce: Option<f32>,
|
||||||
|
pub point_le: Option<f32>,
|
||||||
|
pub contact_callsign: String,
|
||||||
|
pub group_name: Option<String>,
|
||||||
|
pub group_role: Option<String>,
|
||||||
|
pub track_course: Option<i32>,
|
||||||
|
pub track_speed: Option<f32>,
|
||||||
|
pub link_uid: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CursorOverTime {
|
||||||
|
pub fn convert_to_xml(&self) -> String {
|
||||||
|
let uuid = match &self.uuid {
|
||||||
|
Some(uuid) => uuid,
|
||||||
|
None => &Uuid::new_v4().to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let marker_type = match &self.r#type {
|
||||||
|
Some(marker_type) => marker_type,
|
||||||
|
None => &"a-f-G-U-C-I".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
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 mut xml = String::new();
|
||||||
|
|
||||||
|
xml.push_str("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
|
||||||
|
|
||||||
|
xml.push_str(
|
||||||
|
format!("<event type=\"{}\" version=\"2.0\" how=\"m-g\" uid=\"{}\" time=\"{}\" start=\"{}\" stale=\"{}\">",
|
||||||
|
marker_type, uuid, created_time, created_time, stale_time).as_str());
|
||||||
|
|
||||||
|
let point_ce = match &self.point_ce {
|
||||||
|
Some(point_ce) => point_ce,
|
||||||
|
None => &9999999.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let point_le = match &self.point_le {
|
||||||
|
Some(point_le) => point_le,
|
||||||
|
None => &9999999.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
xml.push_str(
|
||||||
|
format!(
|
||||||
|
"<point ce=\"{}\" le=\"{}\" hae=\"{}\" lat=\"{}\" lon=\"{}\" />",
|
||||||
|
point_ce, point_le, self.point_hae, self.point_lat, self.point_lon
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
|
xml.push_str("<detail>");
|
||||||
|
|
||||||
|
xml.push_str("<takv device=\"Samsung S24\" os=\"Arma 3\" platform=\"ARMATAK\" version=\"0.9.0.0\" />");
|
||||||
|
|
||||||
|
if let Some(linked_uid) = &self.link_uid {
|
||||||
|
xml.push_str("<precisionlocation altsrc=\"DTED0\" />");
|
||||||
|
xml.push_str(
|
||||||
|
format!(
|
||||||
|
"<link uid=\"{}\" type=\"a-f-G-U-C\" relation=\"p-p\" />",
|
||||||
|
linked_uid,
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
xml.push_str("<hideLabel />");
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.push_str(format!("<contact callsign=\"{}\" />", self.contact_callsign).as_str());
|
||||||
|
|
||||||
|
xml.push_str(format!("<uid Droid=\"{}\"/>", self.contact_callsign).as_str());
|
||||||
|
|
||||||
|
if let (Some(track_course), Some(track_speed)) = (&self.track_course, &self.track_speed) {
|
||||||
|
xml.push_str(
|
||||||
|
format!(
|
||||||
|
"<track course=\"{}\" speed=\"{}\" />",
|
||||||
|
track_course, track_speed
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
|
||||||
|
xml.push_str("<status battery=\"89\" />");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let (Some(group_name), Some(group_role)) = (&self.group_name, &self.group_role) {
|
||||||
|
xml.push_str(
|
||||||
|
format!(
|
||||||
|
"<__group name=\"{}\" role=\"{}\" />",
|
||||||
|
group_name, group_role
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.push_str("</detail></event>");
|
||||||
|
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/cot/digital_pointer.rs
Normal file
46
src/cot/digital_pointer.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
use arma_rs::{FromArma, FromArmaError};
|
||||||
|
|
||||||
|
use super::cot::CursorOverTime;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct DigitalPointerPayload {
|
||||||
|
pub link_uid: String,
|
||||||
|
pub contact_callsign: String,
|
||||||
|
pub point_lat: f64,
|
||||||
|
pub point_lon: f64,
|
||||||
|
pub point_hae: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromArma for DigitalPointerPayload {
|
||||||
|
fn from_arma(data: String) -> Result<DigitalPointerPayload, FromArmaError> {
|
||||||
|
let (link_uid, contact_callsign, point_lat, point_lon, point_hae) =
|
||||||
|
<(String, String, f64, f64, f32)>::from_arma(data)?;
|
||||||
|
Ok(Self {
|
||||||
|
link_uid,
|
||||||
|
contact_callsign,
|
||||||
|
point_lat,
|
||||||
|
point_lon,
|
||||||
|
point_hae,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DigitalPointerPayload {
|
||||||
|
pub fn to_cot(&self) -> CursorOverTime {
|
||||||
|
CursorOverTime {
|
||||||
|
uuid: Some(format!("{}{}", self.link_uid.clone(), ".SPI1")),
|
||||||
|
r#type: Some("b-m-p-s-p-i".to_string()),
|
||||||
|
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: Some(self.link_uid.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
src/cot/eud.rs
Normal file
62
src/cot/eud.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
use arma_rs::{FromArma, FromArmaError};
|
||||||
|
|
||||||
|
use super::cot::CursorOverTime;
|
||||||
|
|
||||||
|
pub struct EudCoTPayload {
|
||||||
|
pub uuid: String,
|
||||||
|
pub point_lat: f64,
|
||||||
|
pub point_lon: f64,
|
||||||
|
pub point_hae: f32,
|
||||||
|
pub contact_callsign: String,
|
||||||
|
pub group_name: String,
|
||||||
|
pub group_role: String,
|
||||||
|
pub track_course: i32,
|
||||||
|
pub track_speed: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromArma for EudCoTPayload {
|
||||||
|
fn from_arma(data: String) -> Result<EudCoTPayload, FromArmaError> {
|
||||||
|
let (
|
||||||
|
uuid,
|
||||||
|
point_lat,
|
||||||
|
point_lon,
|
||||||
|
point_hae,
|
||||||
|
contact_callsign,
|
||||||
|
group_name,
|
||||||
|
group_role,
|
||||||
|
track_course,
|
||||||
|
track_speed,
|
||||||
|
) = <(String, f64, f64, f32, String, String, String, i32, f32)>::from_arma(data)?;
|
||||||
|
Ok(Self {
|
||||||
|
uuid,
|
||||||
|
point_lat,
|
||||||
|
point_lon,
|
||||||
|
point_hae,
|
||||||
|
contact_callsign,
|
||||||
|
group_name,
|
||||||
|
group_role,
|
||||||
|
track_course,
|
||||||
|
track_speed,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EudCoTPayload {
|
||||||
|
pub fn to_cot(&self) -> CursorOverTime {
|
||||||
|
CursorOverTime {
|
||||||
|
uuid: Some(self.uuid.clone()),
|
||||||
|
r#type: None,
|
||||||
|
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: Some(self.group_name.clone()),
|
||||||
|
group_role: Some(self.group_role.clone()),
|
||||||
|
track_course: Some(self.track_course),
|
||||||
|
track_speed: Some(self.track_speed),
|
||||||
|
link_uid: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/cot/mod.rs
Normal file
4
src/cot/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
pub mod cot;
|
||||||
|
pub mod digital_pointer;
|
||||||
|
pub mod eud;
|
||||||
|
pub mod nato;
|
||||||
59
src/cot/nato.rs
Normal file
59
src/cot/nato.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
use arma_rs::{FromArma, FromArmaError};
|
||||||
|
|
||||||
|
use super::cot::CursorOverTime;
|
||||||
|
|
||||||
|
pub struct MarkerCoTPayload {
|
||||||
|
pub uuid: String,
|
||||||
|
pub r#type: String,
|
||||||
|
pub point_lat: f64,
|
||||||
|
pub point_lon: f64,
|
||||||
|
pub point_hae: f32,
|
||||||
|
pub contact_callsign: String,
|
||||||
|
pub track_course: i32,
|
||||||
|
pub track_speed: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromArma for MarkerCoTPayload {
|
||||||
|
fn from_arma(data: String) -> Result<MarkerCoTPayload, FromArmaError> {
|
||||||
|
let (
|
||||||
|
uuid,
|
||||||
|
r#type,
|
||||||
|
point_lat,
|
||||||
|
point_lon,
|
||||||
|
point_hae,
|
||||||
|
contact_callsign,
|
||||||
|
track_course,
|
||||||
|
track_speed,
|
||||||
|
) = <(String, String, f64, f64, f32, String, i32, f32)>::from_arma(data)?;
|
||||||
|
Ok(Self {
|
||||||
|
uuid,
|
||||||
|
r#type,
|
||||||
|
point_lat,
|
||||||
|
point_lon,
|
||||||
|
point_hae,
|
||||||
|
contact_callsign,
|
||||||
|
track_course,
|
||||||
|
track_speed,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MarkerCoTPayload {
|
||||||
|
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: Some(self.track_course),
|
||||||
|
track_speed: Some(self.track_speed),
|
||||||
|
link_uid: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,267 +0,0 @@
|
|||||||
use arma_rs::{FromArma, FromArmaError};
|
|
||||||
use chrono::{Duration, SecondsFormat, Utc};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
pub struct CursorOverTime {
|
|
||||||
pub uuid: Option<String>,
|
|
||||||
pub r#type: Option<String>,
|
|
||||||
pub point_lat: f64,
|
|
||||||
pub point_lon: f64,
|
|
||||||
pub point_hae: f32,
|
|
||||||
pub point_ce: Option<f32>,
|
|
||||||
pub point_le: Option<f32>,
|
|
||||||
pub contact_callsign: String,
|
|
||||||
pub group_name: Option<String>,
|
|
||||||
pub group_role: Option<String>,
|
|
||||||
pub track_course: Option<i32>,
|
|
||||||
pub track_speed: Option<f32>,
|
|
||||||
pub link_uid: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CursorOverTime {
|
|
||||||
pub fn convert_to_xml(&self) -> String {
|
|
||||||
let uuid = match &self.uuid {
|
|
||||||
Some(uuid) => uuid,
|
|
||||||
None => &Uuid::new_v4().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let marker_type = match &self.r#type {
|
|
||||||
Some(marker_type) => marker_type,
|
|
||||||
None => &"a-f-G-U-C-I".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
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 mut xml = String::new();
|
|
||||||
|
|
||||||
xml.push_str("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
|
|
||||||
|
|
||||||
xml.push_str(
|
|
||||||
format!("<event type=\"{}\" version=\"2.0\" how=\"m-g\" uid=\"{}\" time=\"{}\" start=\"{}\" stale=\"{}\">",
|
|
||||||
marker_type, uuid, created_time, created_time, stale_time).as_str());
|
|
||||||
|
|
||||||
let point_ce = match &self.point_ce {
|
|
||||||
Some(point_ce) => point_ce,
|
|
||||||
None => &9999999.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let point_le = match &self.point_le {
|
|
||||||
Some(point_le) => point_le,
|
|
||||||
None => &9999999.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
xml.push_str(
|
|
||||||
format!(
|
|
||||||
"<point ce=\"{}\" le=\"{}\" hae=\"{}\" lat=\"{}\" lon=\"{}\" />",
|
|
||||||
point_ce, point_le, self.point_hae, self.point_lat, self.point_lon
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
);
|
|
||||||
|
|
||||||
xml.push_str("<detail>");
|
|
||||||
|
|
||||||
xml.push_str("<takv device=\"Samsung S24\" os=\"Arma 3\" platform=\"ARMATAK\" version=\"0.9.0.0\" />");
|
|
||||||
|
|
||||||
if let Some(linked_uid) = &self.link_uid {
|
|
||||||
xml.push_str("<precisionlocation altsrc=\"DTED0\" />");
|
|
||||||
xml.push_str(
|
|
||||||
format!(
|
|
||||||
"<link uid=\"{}\" type=\"a-f-G-U-C\" relation=\"p-p\" />",
|
|
||||||
linked_uid,
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
);
|
|
||||||
xml.push_str("<hideLabel />");
|
|
||||||
}
|
|
||||||
|
|
||||||
xml.push_str(format!("<contact callsign=\"{}\" />", self.contact_callsign).as_str());
|
|
||||||
|
|
||||||
xml.push_str(format!("<uid Droid=\"{}\"/>", self.contact_callsign).as_str());
|
|
||||||
|
|
||||||
if let (Some(track_course), Some(track_speed)) = (&self.track_course, &self.track_speed) {
|
|
||||||
xml.push_str(
|
|
||||||
format!(
|
|
||||||
"<track course=\"{}\" speed=\"{}\" />",
|
|
||||||
track_course, track_speed
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
);
|
|
||||||
|
|
||||||
xml.push_str("<status battery=\"89\" />");
|
|
||||||
}
|
|
||||||
|
|
||||||
if let (Some(group_name), Some(group_role)) = (&self.group_name, &self.group_role) {
|
|
||||||
xml.push_str(
|
|
||||||
format!(
|
|
||||||
"<__group name=\"{}\" role=\"{}\" />",
|
|
||||||
group_name, group_role
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
xml.push_str("</detail></event>");
|
|
||||||
|
|
||||||
return xml;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HumanCoTPayload {
|
|
||||||
pub uuid: String,
|
|
||||||
pub point_lat: f64,
|
|
||||||
pub point_lon: f64,
|
|
||||||
pub point_hae: f32,
|
|
||||||
pub contact_callsign: String,
|
|
||||||
pub group_name: String,
|
|
||||||
pub group_role: String,
|
|
||||||
pub track_course: i32,
|
|
||||||
pub track_speed: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromArma for HumanCoTPayload {
|
|
||||||
fn from_arma(data: String) -> Result<HumanCoTPayload, FromArmaError> {
|
|
||||||
let (
|
|
||||||
uuid,
|
|
||||||
point_lat,
|
|
||||||
point_lon,
|
|
||||||
point_hae,
|
|
||||||
contact_callsign,
|
|
||||||
group_name,
|
|
||||||
group_role,
|
|
||||||
track_course,
|
|
||||||
track_speed,
|
|
||||||
) = <(String, f64, f64, f32, String, String, String, i32, f32)>::from_arma(data)?;
|
|
||||||
Ok(Self {
|
|
||||||
uuid,
|
|
||||||
point_lat,
|
|
||||||
point_lon,
|
|
||||||
point_hae,
|
|
||||||
contact_callsign,
|
|
||||||
group_name,
|
|
||||||
group_role,
|
|
||||||
track_course,
|
|
||||||
track_speed,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HumanCoTPayload {
|
|
||||||
pub fn to_cot(&self) -> CursorOverTime {
|
|
||||||
CursorOverTime {
|
|
||||||
uuid: Some(self.uuid.clone()),
|
|
||||||
r#type: None,
|
|
||||||
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: Some(self.group_name.clone()),
|
|
||||||
group_role: Some(self.group_role.clone()),
|
|
||||||
track_course: Some(self.track_course),
|
|
||||||
track_speed: Some(self.track_speed),
|
|
||||||
link_uid: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MarkerCoTPayload {
|
|
||||||
pub uuid: String,
|
|
||||||
pub r#type: String,
|
|
||||||
pub point_lat: f64,
|
|
||||||
pub point_lon: f64,
|
|
||||||
pub point_hae: f32,
|
|
||||||
pub contact_callsign: String,
|
|
||||||
pub track_course: i32,
|
|
||||||
pub track_speed: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromArma for MarkerCoTPayload {
|
|
||||||
fn from_arma(data: String) -> Result<MarkerCoTPayload, FromArmaError> {
|
|
||||||
let (
|
|
||||||
uuid,
|
|
||||||
r#type,
|
|
||||||
point_lat,
|
|
||||||
point_lon,
|
|
||||||
point_hae,
|
|
||||||
contact_callsign,
|
|
||||||
track_course,
|
|
||||||
track_speed,
|
|
||||||
) = <(String, String, f64, f64, f32, String, i32, f32)>::from_arma(data)?;
|
|
||||||
Ok(Self {
|
|
||||||
uuid,
|
|
||||||
r#type,
|
|
||||||
point_lat,
|
|
||||||
point_lon,
|
|
||||||
point_hae,
|
|
||||||
contact_callsign,
|
|
||||||
track_course,
|
|
||||||
track_speed,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MarkerCoTPayload {
|
|
||||||
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: Some(self.track_course),
|
|
||||||
track_speed: Some(self.track_speed),
|
|
||||||
link_uid: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DigitalPointerPayload {
|
|
||||||
pub link_uid: String,
|
|
||||||
pub contact_callsign: String,
|
|
||||||
pub point_lat: f64,
|
|
||||||
pub point_lon: f64,
|
|
||||||
pub point_hae: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromArma for DigitalPointerPayload {
|
|
||||||
fn from_arma(data: String) -> Result<DigitalPointerPayload, FromArmaError> {
|
|
||||||
let (link_uid, contact_callsign, point_lat, point_lon, point_hae) =
|
|
||||||
<(String, String, f64, f64, f32)>::from_arma(data)?;
|
|
||||||
Ok(Self {
|
|
||||||
link_uid,
|
|
||||||
contact_callsign,
|
|
||||||
point_lat,
|
|
||||||
point_lon,
|
|
||||||
point_hae,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DigitalPointerPayload {
|
|
||||||
pub fn to_cot(&self) -> CursorOverTime {
|
|
||||||
CursorOverTime {
|
|
||||||
uuid: Some(format!("{}{}", self.link_uid.clone(), ".SPI1")),
|
|
||||||
r#type: Some("b-m-p-s-p-i".to_string()),
|
|
||||||
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: Some(self.link_uid.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,7 @@ use std::sync::mpsc::{self, Receiver, Sender};
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use crate::cot_generator::{DigitalPointerPayload, HumanCoTPayload, MarkerCoTPayload};
|
use crate::cot;
|
||||||
|
|
||||||
pub enum TcpCommand {
|
pub enum TcpCommand {
|
||||||
SendMessage(String, Context),
|
SendMessage(String, Context),
|
||||||
@@ -32,12 +32,12 @@ impl TcpClient {
|
|||||||
|
|
||||||
let tcp_thread = thread::spawn(move || match TcpStream::connect(&address) {
|
let tcp_thread = thread::spawn(move || match TcpStream::connect(&address) {
|
||||||
Ok(stream) => {
|
Ok(stream) => {
|
||||||
let _ = ctx.callback_data("armatak_tcp_socket", "Connected to TCP Server", address);
|
let _ = ctx.callback_data("TCP SOCKET", "Connected to TCP Server", address);
|
||||||
*connection_clone.lock().unwrap() = Some(stream);
|
*connection_clone.lock().unwrap() = Some(stream);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let _ = ctx.callback_data(
|
let _ = ctx.callback_data(
|
||||||
"armatak_tcp_socket_error",
|
"TCP SOCKET ERROR",
|
||||||
"TAK Socket connection failed",
|
"TAK Socket connection failed",
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
);
|
);
|
||||||
@@ -53,7 +53,7 @@ impl TcpClient {
|
|||||||
info!("Failed to send message: {}", e);
|
info!("Failed to send message: {}", e);
|
||||||
|
|
||||||
let _ = context.callback_data(
|
let _ = context.callback_data(
|
||||||
"armatak_tcp_socket_error",
|
"TCP SOCKET ERROR",
|
||||||
"TAK Socket disconnected",
|
"TAK Socket disconnected",
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
);
|
);
|
||||||
@@ -62,7 +62,7 @@ impl TcpClient {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let _ = context.callback_null(
|
let _ = context.callback_null(
|
||||||
"armatak_tcp_socket_error",
|
"TCP SOCKET ERROR",
|
||||||
"TAK Socket is not active",
|
"TAK Socket is not active",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -116,28 +116,28 @@ pub fn send_payload(ctx: Context, payload: String) -> &'static str {
|
|||||||
if let Some(ref client) = *TCP_CLIENT.lock().unwrap() {
|
if let Some(ref client) = *TCP_CLIENT.lock().unwrap() {
|
||||||
client.send_payload(ctx, payload);
|
client.send_payload(ctx, payload);
|
||||||
} else {
|
} else {
|
||||||
let _ = ctx.callback_null("armatak_tcp_socket_error", "TCP Client is not running");
|
let _ = ctx.callback_null("TCP SOCKET ERROR", "TCP Client is not running");
|
||||||
info!("TCP client is not running.");
|
info!("TCP client is not running.");
|
||||||
}
|
}
|
||||||
|
|
||||||
"Sending payload to TCP server"
|
"Sending payload to TCP server"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_human_cot(ctx: Context, cursor_over_time: HumanCoTPayload) -> &'static str {
|
pub fn send_eud_cot(ctx: Context, cursor_over_time: cot::eud::EudCoTPayload) -> &'static str {
|
||||||
let payload = cursor_over_time.to_cot().convert_to_xml();
|
let payload = cursor_over_time.to_cot().convert_to_xml();
|
||||||
send_payload(ctx, payload);
|
send_payload(ctx, payload);
|
||||||
|
|
||||||
"Sending Human Cursor Over Time to TCP server"
|
"Sending End User Device Cursor Over Time to TCP server"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_marker_cot(ctx: Context, cursor_over_time: MarkerCoTPayload) -> &'static str {
|
pub fn send_marker_cot(ctx: Context, cursor_over_time: cot::nato::MarkerCoTPayload) -> &'static str {
|
||||||
let payload = cursor_over_time.to_cot().convert_to_xml();
|
let payload = cursor_over_time.to_cot().convert_to_xml();
|
||||||
send_payload(ctx, payload);
|
send_payload(ctx, payload);
|
||||||
|
|
||||||
"Sending Marker Cursor Over Time to TCP server"
|
"Sending Marker Cursor Over Time to TCP server"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_digital_pointer_cot(ctx: Context, cursor_over_time: DigitalPointerPayload) -> &'static str {
|
pub fn send_digital_pointer_cot(ctx: Context, cursor_over_time: cot::digital_pointer::DigitalPointerPayload) -> &'static str {
|
||||||
let payload = cursor_over_time.to_cot().convert_to_xml();
|
let payload = cursor_over_time.to_cot().convert_to_xml();
|
||||||
send_payload(ctx, payload);
|
send_payload(ctx, payload);
|
||||||
|
|
||||||
@@ -147,9 +147,9 @@ pub fn send_digital_pointer_cot(ctx: Context, cursor_over_time: DigitalPointerPa
|
|||||||
pub fn stop(ctx: Context) -> &'static str {
|
pub fn stop(ctx: Context) -> &'static str {
|
||||||
if let Some(ref client) = *TCP_CLIENT.lock().unwrap() {
|
if let Some(ref client) = *TCP_CLIENT.lock().unwrap() {
|
||||||
client.stop();
|
client.stop();
|
||||||
let _ = ctx.callback_null("armatak_tcp_socket", "TCP client stopped");
|
let _ = ctx.callback_null("TCP SOCKET", "TCP client stopped");
|
||||||
} else {
|
} else {
|
||||||
let _ = ctx.callback_null("armatak_tcp_socket_error", "TCP client is not running");
|
let _ = ctx.callback_null("TCP SOCKET ERROR", "TCP client is not running");
|
||||||
}
|
}
|
||||||
|
|
||||||
"Stopping TCP Client"
|
"Stopping TCP Client"
|
||||||
|
|||||||
19
src/lib.rs
19
src/lib.rs
@@ -2,11 +2,12 @@ use arma_rs::{arma, Extension, Group};
|
|||||||
mod structs;
|
mod structs;
|
||||||
mod tests;
|
mod tests;
|
||||||
mod websocket;
|
mod websocket;
|
||||||
mod util;
|
|
||||||
mod cot_router;
|
mod cot_router;
|
||||||
mod cot_generator;
|
|
||||||
mod video_stream;
|
mod video_stream;
|
||||||
|
|
||||||
|
mod cot;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
#[arma]
|
#[arma]
|
||||||
pub fn init() -> Extension {
|
pub fn init() -> Extension {
|
||||||
use log4rs::append::file::FileAppender;
|
use log4rs::append::file::FileAppender;
|
||||||
@@ -30,22 +31,22 @@ pub fn init() -> Extension {
|
|||||||
|
|
||||||
log4rs::init_config(config).unwrap();
|
log4rs::init_config(config).unwrap();
|
||||||
|
|
||||||
websocket::start();
|
|
||||||
|
|
||||||
Extension::build()
|
Extension::build()
|
||||||
.group("websocket", Group::new()
|
.group("websocket", Group::new()
|
||||||
|
.command("start", websocket::start)
|
||||||
|
.command("stop", websocket::stop)
|
||||||
.command("message", websocket::message)
|
.command("message", websocket::message)
|
||||||
.command("location", websocket::location)
|
.command("location", websocket::location)
|
||||||
)
|
)
|
||||||
.command("local_ip", util::get_local_address)
|
.command("local_ip", utils::address::get_local_address)
|
||||||
.command("uuid", util::get_uuid)
|
.command("uuid", utils::uuid::get_uuid)
|
||||||
.command("log", util::log_info)
|
.command("log", utils::log::log_info)
|
||||||
.group(
|
.group(
|
||||||
"cot_router",
|
"tcp_socket",
|
||||||
Group::new()
|
Group::new()
|
||||||
.command("start", cot_router::start)
|
.command("start", cot_router::start)
|
||||||
.command("send_payload", cot_router::send_payload)
|
.command("send_payload", cot_router::send_payload)
|
||||||
.command("send_human_cot", cot_router::send_human_cot)
|
.command("send_eud_cot", cot_router::send_eud_cot)
|
||||||
.command("send_marker_cot", cot_router::send_marker_cot)
|
.command("send_marker_cot", cot_router::send_marker_cot)
|
||||||
.command("send_digital_pointer_cot", cot_router::send_digital_pointer_cot)
|
.command("send_digital_pointer_cot", cot_router::send_digital_pointer_cot)
|
||||||
.command("stop", cot_router::stop)
|
.command("stop", cot_router::stop)
|
||||||
|
|||||||
43
src/util.rs
43
src/util.rs
@@ -1,43 +0,0 @@
|
|||||||
use crate::structs::LogPayload;
|
|
||||||
use log::{error, info, warn};
|
|
||||||
use std::net::{IpAddr, UdpSocket};
|
|
||||||
|
|
||||||
pub fn log_info(data: LogPayload) -> String {
|
|
||||||
match data.status.as_str() {
|
|
||||||
"info" => info!("{}", data.message),
|
|
||||||
"warn" => warn!("{}", data.message),
|
|
||||||
"error" => error!("{}", data.message),
|
|
||||||
_ => error!("{}", "Wrong log call"),
|
|
||||||
}
|
|
||||||
"logged".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_uuid() -> String {
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
let id = Uuid::new_v4().to_string();
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_local_address() -> String {
|
|
||||||
fn get_local_ip() -> Result<IpAddr, String> {
|
|
||||||
let socket = UdpSocket::bind("0.0.0.0:0").map_err(|e| e.to_string())?;
|
|
||||||
socket.connect("8.8.8.8:80").map_err(|e| e.to_string())?;
|
|
||||||
socket
|
|
||||||
.local_addr()
|
|
||||||
.map(|addr| addr.ip())
|
|
||||||
.map_err(|e| e.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
let parsed_data = get_local_ip();
|
|
||||||
|
|
||||||
match parsed_data {
|
|
||||||
Ok(ip) => {
|
|
||||||
return format!("ws://{}:4152", ip.to_string());
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
return "not provided".to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
23
src/utils/address.rs
Normal file
23
src/utils/address.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
use std::net::{IpAddr, UdpSocket};
|
||||||
|
|
||||||
|
pub fn get_local_address() -> String {
|
||||||
|
fn get_local_ip() -> Result<IpAddr, String> {
|
||||||
|
let socket = UdpSocket::bind("0.0.0.0:0").map_err(|e| e.to_string())?;
|
||||||
|
socket.connect("8.8.8.8:80").map_err(|e| e.to_string())?;
|
||||||
|
socket
|
||||||
|
.local_addr()
|
||||||
|
.map(|addr| addr.ip())
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
let parsed_data = get_local_ip();
|
||||||
|
|
||||||
|
match parsed_data {
|
||||||
|
Ok(ip) => {
|
||||||
|
return format!("ws://{}:4152", ip.to_string());
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
return "not provided".to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/utils/log.rs
Normal file
12
src/utils/log.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
use crate::structs::LogPayload;
|
||||||
|
use log::{error, info, warn};
|
||||||
|
|
||||||
|
pub fn log_info(data: LogPayload) -> String {
|
||||||
|
match data.status.as_str() {
|
||||||
|
"info" => info!("{}", data.message),
|
||||||
|
"warn" => warn!("{}", data.message),
|
||||||
|
"error" => error!("{}", data.message),
|
||||||
|
_ => error!("{}", "Wrong log call"),
|
||||||
|
}
|
||||||
|
"logged".to_string()
|
||||||
|
}
|
||||||
3
src/utils/mod.rs
Normal file
3
src/utils/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod uuid;
|
||||||
|
pub mod address;
|
||||||
|
pub mod log;
|
||||||
7
src/utils/uuid.rs
Normal file
7
src/utils/uuid.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn get_uuid() -> String {
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
let id = Uuid::new_v4().to_string();
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ use std::process::Command;
|
|||||||
use std::sync::mpsc::{self, Receiver, Sender};
|
use std::sync::mpsc::{self, Receiver, Sender};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
use std::os::windows::process::CommandExt;
|
use std::os::windows::process::CommandExt;
|
||||||
@@ -26,23 +27,30 @@ pub fn start_stream(
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
ctx.callback_null(
|
ctx.callback_null(
|
||||||
"armatak_video_error",
|
"VIDEO ERROR",
|
||||||
"Screen capture is only supported on Windows",
|
"Screen capture is only supported on Windows",
|
||||||
);
|
);
|
||||||
|
return "screen capture unsupported";
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
let (tx, rx): (Sender<()>, Receiver<()>) = mpsc::channel();
|
let (stop_tx, stop_rx): (Sender<()>, Receiver<()>) = mpsc::channel();
|
||||||
let rtsp_url = format!(
|
let (status_tx, status_rx): (Sender<Result<(), String>>, Receiver<Result<(), String>>) = mpsc::channel();
|
||||||
|
|
||||||
|
let rtsp_url = if username.is_empty() || password.is_empty() {
|
||||||
|
format!("rtsp://{}:{}/{}", address, port, stream_path)
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
"rtsp://{}:{}@{}:{}/{}",
|
"rtsp://{}:{}@{}:{}/{}",
|
||||||
username, password, address, port, stream_path
|
username, password, address, port, stream_path
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let rtsp_url_clone = rtsp_url.clone();
|
let rtsp_url_clone = rtsp_url.clone();
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut cmd = Command::new("ffmpeg");
|
let mut cmd = Command::new("ffmpeg");
|
||||||
|
|
||||||
cmd.args(&[
|
cmd.args(&[
|
||||||
"-f",
|
"-f",
|
||||||
"gdigrab",
|
"gdigrab",
|
||||||
@@ -55,30 +63,57 @@ pub fn start_stream(
|
|||||||
&rtsp_url_clone,
|
&rtsp_url_clone,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mut child = cmd.creation_flags(CREATE_NO_WINDOW).spawn().unwrap();
|
// Try to spawn ffmpeg process
|
||||||
|
let child_result = cmd.creation_flags(CREATE_NO_WINDOW).spawn();
|
||||||
|
|
||||||
if rx.recv().is_err() {
|
match child_result {
|
||||||
let _ = ctx.callback_null("armatak_video_error", "Error receiving stop signal");
|
Ok(mut child) => {
|
||||||
|
let _ = status_tx.send(Ok(()));
|
||||||
|
if stop_rx.recv().is_err() {}
|
||||||
|
let _ = child.kill();
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let _ = status_tx.send(Err(format!("Failed to start FFmpeg: {}", e)));
|
||||||
|
// Return early, nothing else to do
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = child.kill() {
|
|
||||||
let _ = ctx.callback_data(
|
|
||||||
"armatak_video_error",
|
|
||||||
"Failed to Stop FFmpeg",
|
|
||||||
e.to_string(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Save the stop channel so we can stop later
|
||||||
match STREAM_CTRL.lock() {
|
match STREAM_CTRL.lock() {
|
||||||
Ok(mut lock) => *lock = Some(tx),
|
Ok(mut lock) => *lock = Some(stop_tx),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Failed to acquire lock: {}", e);
|
let _ = ctx.callback_data(
|
||||||
|
"VIDEO ERROR",
|
||||||
|
"Failed to acquire lock for stream control",
|
||||||
|
e.to_string(),
|
||||||
|
);
|
||||||
|
return "stream control lock error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait up to 2 seconds to see if ffmpeg started correctly
|
||||||
|
match status_rx.recv_timeout(Duration::from_secs(2)) {
|
||||||
|
Ok(Ok(())) => {
|
||||||
|
let _ = ctx.callback_null("VIDEO", "FFmpeg started successfully");
|
||||||
|
"starting video stream"
|
||||||
|
}
|
||||||
|
Ok(Err(e)) => {
|
||||||
|
let _ = ctx.callback_data("VIDEO ERROR", "FFmpeg failed to start", e);
|
||||||
|
"ffmpeg failed to start"
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
let _ = ctx.callback_null("VIDEO ERROR", "FFmpeg did not respond in time");
|
||||||
|
"ffmpeg did not respond"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"starting video stream"
|
#[cfg(not(any(target_os = "windows", target_os = "linux")))]
|
||||||
|
{
|
||||||
|
ctx.callback_null("VIDEO ERROR", "Screen capture is only supported on Windows");
|
||||||
|
"unsupported platform"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop_stream(ctx: Context) -> &'static str {
|
pub fn stop_stream(ctx: Context) -> &'static str {
|
||||||
@@ -87,24 +122,27 @@ pub fn stop_stream(ctx: Context) -> &'static str {
|
|||||||
if let Some(tx) = lock.take() {
|
if let Some(tx) = lock.take() {
|
||||||
if let Err(e) = tx.send(()) {
|
if let Err(e) = tx.send(()) {
|
||||||
let _ = ctx.callback_data(
|
let _ = ctx.callback_data(
|
||||||
"armatak_video_error",
|
"VIDEO ERROR",
|
||||||
"Failed to send stop signal",
|
"Failed to send stop signal",
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
);
|
);
|
||||||
|
"error sending stop"
|
||||||
|
} else {
|
||||||
|
let _ = ctx.callback_null("VIDEO", "Sent stop signal to FFmpeg");
|
||||||
|
"stopping video stream"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let _ =
|
let _ = ctx.callback_null("VIDEO ERROR", "Tried to stop a nonexistent stream");
|
||||||
ctx.callback_null("armatak_video_error", "Tried to stop a nonexistent stream");
|
"no stream to stop"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let _ = ctx.callback_data(
|
let _ = ctx.callback_data(
|
||||||
"armatak_video_error",
|
"VIDEO ERROR",
|
||||||
"Failed to acquire lock",
|
"Failed to acquire lock for stop",
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
);
|
);
|
||||||
|
"lock error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"stopping video stream"
|
|
||||||
}
|
}
|
||||||
139
src/websocket.rs
139
src/websocket.rs
@@ -1,77 +1,126 @@
|
|||||||
|
use arma_rs::Context;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::sync::mpsc::{self, Receiver, Sender};
|
use std::sync::mpsc::{self, Receiver, Sender};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use ws::{listen, Message, Result as WsResult};
|
use ws::{listen, CloseCode, Handler, Handshake, Message, Result as WsResult, Sender as WsSender};
|
||||||
|
|
||||||
use crate::structs::{IntoMessage, LocationPayload};
|
use crate::structs::{IntoMessage, LocationPayload};
|
||||||
use lazy_static::lazy_static;
|
|
||||||
|
|
||||||
pub enum WsCommand {
|
pub enum WsCommand {
|
||||||
SendMessage(String),
|
SendMessage(String),
|
||||||
Stop,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum WsEvent {
|
||||||
|
FirstClientConnected,
|
||||||
|
LastClientDisconnected,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WsServer {
|
pub struct WsServer {
|
||||||
pub(crate) tx: Sender<WsCommand>,
|
pub(crate) tx: Sender<WsCommand>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct WsHandler {
|
||||||
|
out: WsSender,
|
||||||
|
clients: Arc<Mutex<Vec<WsSender>>>,
|
||||||
|
event_tx: Sender<WsEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler for WsHandler {
|
||||||
|
fn on_open(&mut self, _: Handshake) -> WsResult<()> {
|
||||||
|
let mut clients = self.clients.lock().unwrap();
|
||||||
|
clients.push(self.out.clone());
|
||||||
|
|
||||||
|
let count = clients.len();
|
||||||
|
info!("New client connected. Total clients: {}", count);
|
||||||
|
|
||||||
|
if count == 1 {
|
||||||
|
let _ = self.event_tx.send(WsEvent::FirstClientConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_close(&mut self, _: CloseCode, _: &str) {
|
||||||
|
let mut clients = self.clients.lock().unwrap();
|
||||||
|
clients.retain(|client| client.token() != self.out.token());
|
||||||
|
|
||||||
|
let count = clients.len();
|
||||||
|
info!("Client disconnected. Total clients: {}", count);
|
||||||
|
|
||||||
|
if count == 0 {
|
||||||
|
let _ = self.event_tx.send(WsEvent::LastClientDisconnected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_message(&mut self, msg: Message) -> WsResult<()> {
|
||||||
|
info!("Received: {}", msg);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WsServer {
|
impl WsServer {
|
||||||
pub fn start(&self, rx: Receiver<WsCommand>) {
|
pub fn start(&self, ctx: Context, rx: Receiver<WsCommand>) {
|
||||||
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
||||||
server.stop();
|
server.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
let clients = Arc::new(Mutex::new(Vec::new()));
|
let clients = Arc::new(Mutex::new(Vec::new()));
|
||||||
let clients_clone = Arc::clone(&clients);
|
let clients_clone = Arc::clone(&clients);
|
||||||
|
let (event_tx, event_rx): (Sender<WsEvent>, Receiver<WsEvent>) = mpsc::channel();
|
||||||
|
|
||||||
|
// Start WebSocket listener in a background thread
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut running = true;
|
listen("0.0.0.0:4152", |out| WsHandler {
|
||||||
|
out,
|
||||||
let ws_thread = thread::spawn(move || {
|
clients: Arc::clone(&clients_clone),
|
||||||
listen("0.0.0.0:4152", |out| {
|
event_tx: event_tx.clone(),
|
||||||
let clients_inner = Arc::clone(&clients_clone);
|
}).expect("WebSocket server failed to start");
|
||||||
{
|
|
||||||
let mut clients_guard = clients_inner.lock().unwrap();
|
|
||||||
clients_guard.push(out.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
move |msg: Message| -> WsResult<()> {
|
|
||||||
info!("Received: {}", msg);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
while running {
|
// This thread owns ctx and reacts to commands and events
|
||||||
match rx.recv() {
|
thread::spawn(move || {
|
||||||
|
loop {
|
||||||
|
// WebSocket message commands
|
||||||
|
match rx.try_recv() {
|
||||||
Ok(WsCommand::SendMessage(message)) => {
|
Ok(WsCommand::SendMessage(message)) => {
|
||||||
let clients_guard = clients.lock().unwrap();
|
let clients_guard = clients.lock().unwrap();
|
||||||
for client in clients_guard.iter() {
|
for client in clients_guard.iter() {
|
||||||
client.send(message.clone()).unwrap();
|
let _ = client.send(message.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(WsCommand::Stop) => {
|
Ok(WsCommand::Stop) => {
|
||||||
running = false;
|
|
||||||
info!("Stopping WebSocket server.");
|
info!("Stopping WebSocket server.");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(_) => {}
|
||||||
info!("Error receiving command: {}", error.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ws_thread.join().unwrap();
|
// Handle event callbacks with valid Context
|
||||||
|
match event_rx.try_recv() {
|
||||||
|
Ok(WsEvent::FirstClientConnected) => {
|
||||||
|
let _ = ctx.callback_null("WEBSOCKET", "EUD connected");
|
||||||
|
}
|
||||||
|
Ok(WsEvent::LastClientDisconnected) => {
|
||||||
|
let _ = ctx.callback_null("WEBSOCKET WARNING", "EUD disconnected");
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
thread::sleep(std::time::Duration::from_millis(10));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_message<T: IntoMessage>(&self, payload: T) {
|
pub fn send_message<T: IntoMessage>(&self, payload: T) {
|
||||||
let message = payload.into_message();
|
let message = payload.into_message();
|
||||||
self.tx.send(WsCommand::SendMessage(message)).unwrap();
|
let _ = self.tx.send(WsCommand::SendMessage(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop(&self) {
|
pub fn stop(&self) {
|
||||||
self.tx.send(WsCommand::Stop).unwrap();
|
let _ = self.tx.send(WsCommand::Stop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,36 +128,46 @@ lazy_static! {
|
|||||||
static ref WEBSOCKET_SERVER: Arc<Mutex<Option<WsServer>>> = Arc::new(Mutex::new(None));
|
static ref WEBSOCKET_SERVER: Arc<Mutex<Option<WsServer>>> = Arc::new(Mutex::new(None));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start() -> &'static str {
|
pub fn start(ctx: Context) -> &'static str {
|
||||||
let (tx, rx): (Sender<WsCommand>, Receiver<WsCommand>) = mpsc::channel();
|
let (tx, rx): (Sender<WsCommand>, Receiver<WsCommand>) = mpsc::channel();
|
||||||
|
|
||||||
let server = WsServer { tx };
|
let server = WsServer { tx };
|
||||||
server.start(rx);
|
server.start(ctx, rx);
|
||||||
|
|
||||||
let mut server_guard = WEBSOCKET_SERVER.lock().unwrap();
|
let mut server_guard = WEBSOCKET_SERVER.lock().unwrap();
|
||||||
*server_guard = Some(server);
|
*server_guard = Some(server);
|
||||||
|
|
||||||
info!("WebSocket server started.");
|
|
||||||
|
|
||||||
"Starting WebSocket Server"
|
"Starting WebSocket Server"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message(payload: String) -> &'static str {
|
pub fn message(ctx: Context, payload: String) -> &'static str {
|
||||||
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
||||||
info!("Broadcasting message: {}", payload);
|
info!("Broadcasting message: {}", payload); // why the fuck i did this?
|
||||||
server.send_message(payload);
|
server.send_message(payload);
|
||||||
} else {
|
} else {
|
||||||
info!("WebSocket server is not running.");
|
let _ = ctx.callback_null("WEBSOCKET ERROR", "Websocket is not running");
|
||||||
}
|
}
|
||||||
|
|
||||||
"Sending message to all WebSocket clients"
|
"Sending message to all WebSocket clients"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn location(payload: LocationPayload) -> &'static str {
|
pub fn location(ctx: Context, payload: LocationPayload) -> &'static str {
|
||||||
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
||||||
server.send_message(payload);
|
server.send_message(payload);
|
||||||
} else {
|
} else {
|
||||||
info!("WebSocket server is not running.");
|
let _ = ctx.callback_null("WEBSOCKET ERROR", "Websocket is not running");
|
||||||
}
|
}
|
||||||
"sending location to all WebSocket clients"
|
|
||||||
|
"Sending location to all WebSocket clients"
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop(ctx: Context) -> &'static str {
|
||||||
|
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
||||||
|
server.stop();
|
||||||
|
let _ = ctx.callback_null("WEBSOCKET WARNING", "Websocket stopped");
|
||||||
|
} else {
|
||||||
|
let _ = ctx.callback_null("WEBSOCKET ERROR", "Websocket is not running");
|
||||||
|
}
|
||||||
|
|
||||||
|
"Stopping WebSocket Server"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user