mirror of
https://github.com/valmojr/armatak.git
synced 2026-06-13 15:03:30 +00:00
Compare commits
94 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 | ||
|
|
10d0b6f86c | ||
|
|
db16d94596 | ||
|
|
9fc7a0e1bd | ||
|
|
f9b5860f9b | ||
|
|
51b1a06e6c | ||
|
|
63c60bc81a | ||
|
|
10683d9e2f | ||
|
|
871d6ec9d3 | ||
|
|
6eca9e92b6 | ||
|
|
a8f6b04221 | ||
|
|
7831b25062 | ||
|
|
c490483abb | ||
|
|
1719a16894 | ||
|
|
8e4b967f7d | ||
|
|
91eeee9989 | ||
|
|
48512f587b | ||
|
|
ddf60c439c | ||
|
|
8e1fc2170a | ||
|
|
25628016ee | ||
|
|
2ac29f50a6 |
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,4 +1,5 @@
|
||||
**When merged this pull request will:**
|
||||
|
||||
- _Describe what this pull request will do_
|
||||
- _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: |
|
||||
Changes in this release:
|
||||
${{ env.COMMIT_MESSAGES }}
|
||||
draft: false
|
||||
draft: true
|
||||
prerelease: false
|
||||
- name: Upload Release Asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
|
||||
@@ -5,8 +5,8 @@ prefix = "armatak"
|
||||
|
||||
[version]
|
||||
build = 0
|
||||
major = 0
|
||||
minor = 9
|
||||
major = 1
|
||||
minor = 1
|
||||
patch = 0
|
||||
|
||||
git_hash = 0
|
||||
@@ -44,9 +44,24 @@ workshop = [
|
||||
"1779063631", # Zeus enhanced
|
||||
"1673595418", # User Input Menus
|
||||
"1678581937", # Extended Function Viewer
|
||||
"1231625987" #Debug Console
|
||||
"1231625987", #Debug Console
|
||||
"751965892", # ACRE2
|
||||
"843577117", # RHSUSAF
|
||||
"3030830594", # Western Dusk
|
||||
"2268351256", # Tier One Weapons
|
||||
"583496184", # CUP Terrains
|
||||
"583544987", # CUP Maps
|
||||
"3015795970", # No zoom
|
||||
"2941986336", # Hatchet Framework
|
||||
"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 = [
|
||||
"-skipIntro",
|
||||
"-noSplash",
|
||||
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -83,7 +83,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "armatak"
|
||||
version = "0.9.0"
|
||||
version = "1.0.1"
|
||||
dependencies = [
|
||||
"arma-rs",
|
||||
"chrono",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "armatak"
|
||||
version = "0.9.0"
|
||||
version = "1.0.1"
|
||||
edition = "2021"
|
||||
|
||||
[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"];
|
||||
|
||||
_position = [_latitude, _longitude, _altitude];
|
||||
@@ -42,11 +63,14 @@ switch (toLower worldName) do {
|
||||
_realLocation = _position call armatak_fnc_convert_to_united_sahrani;
|
||||
};
|
||||
case "saralite": {
|
||||
_realLocation = _position call armatak_fnc_convert_to_united_sahrani;
|
||||
_realLocation = _position call armatak_fnc_convert_to_southen_sahrani;
|
||||
};
|
||||
case "enoch": {
|
||||
_realLocation = _position call armatak_fnc_convert_to_livonia;
|
||||
};
|
||||
case "kunduz": {
|
||||
_realLocation = _position call armatak_fnc_convert_to_kunduz;
|
||||
};
|
||||
default {
|
||||
_warning = format ["<t color='#FF8021'>ARMATAK</t><br/> %1", "Unsupported Map"];
|
||||
[[_warning, 1.5]] call CBA_fnc_notify;
|
||||
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,89 +1,87 @@
|
||||
class CfgFunctions {
|
||||
class armatak {
|
||||
class functions {
|
||||
class init {
|
||||
file = "\armatak\armatak\armatak_main\functions\fn_init.sqf";
|
||||
};
|
||||
class log_message {
|
||||
file = "\armatak\armatak\armatak_main\functions\fn_log_message.sqf";
|
||||
};
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
file = "\armatak\armatak\armatak_main\functions\api\fn_send_human_cot.sqf";
|
||||
class send_eud_cot {
|
||||
file = "\armatak\armatak\addons\main\functions\api\fn_send_eud_cot.sqf";
|
||||
};
|
||||
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 {
|
||||
file = "\armatak\armatak\armatak_main\functions\api\fn_send_marker_cot.sqf";
|
||||
};
|
||||
class extract_callsign {
|
||||
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_callsign.sqf";
|
||||
class stop_tcp_socket {
|
||||
file = "\armatak\armatak\addons\main\functions\api\fn_stop_tcp_socket.sqf";
|
||||
};
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_position.sqf";
|
||||
class extract_unit_callsign {
|
||||
file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_unit_callsign.sqf";
|
||||
};
|
||||
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 convert_location {
|
||||
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_location.sqf";
|
||||
class shorten_name {
|
||||
file = "\armatak\armatak\addons\main\functions\extract_data\fn_shorten_name.sqf";
|
||||
};
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_kunduz.sqf";
|
||||
};
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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,96 +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 Units: Units {
|
||||
property = "armatak_module_attached_units";
|
||||
};
|
||||
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 = "8080";
|
||||
};
|
||||
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 armatak_main {
|
||||
units[] = {
|
||||
"armatak_module_core",
|
||||
"armatak_module_callsign"
|
||||
};
|
||||
weapons[] = {""};
|
||||
author = "Valmo";
|
||||
url = "https://github.com/valmojr/armatak";
|
||||
requiredAddons[] =
|
||||
{
|
||||
class ADDON {
|
||||
name = COMPONENT_NAME;
|
||||
units[] = {};
|
||||
weapons[] = {};
|
||||
requiredAddons[] = {
|
||||
"cba_main",
|
||||
"ace_main"
|
||||
};
|
||||
requiredVersion = 2.06;
|
||||
requiredVersion = REQUIRED_VERSION;
|
||||
author = PROJECT_AUTHOR;
|
||||
url = "https://github.com/valmojr/armatak";
|
||||
};
|
||||
};
|
||||
|
||||
class Extended_PostInit_EventHandlers {
|
||||
class armatak_main {
|
||||
init = "call compileScript ['\armatak\armatak\armatak_main\initPlayerLocal.sqf']";
|
||||
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";
|
||||
};
|
||||
};
|
||||
|
||||
class CfgFactionClasses {
|
||||
class NO_CATEGORY;
|
||||
class GVAR(moduleCategory): NO_CATEGORY {
|
||||
displayName = "Team Awareness Kit";
|
||||
};
|
||||
};
|
||||
|
||||
#include "CfgEventHandlers.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];
|
||||
|
||||
"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_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);
|
||||
@@ -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"];
|
||||
|
||||
_unit_position = _unit call armatak_fnc_extract_position;
|
||||
_unit_position = _unit call armatak_client_fnc_extractClientPosition;
|
||||
|
||||
_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];
|
||||
|
||||
"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";
|
||||
|
||||
if (isNil "_group_name") then {
|
||||
_group_colors = missionNamespace getVariable "_group_colors";
|
||||
_group_colors = missionNamespace getVariable "armatak_group_colors";
|
||||
_group_name = selectRandom _group_colors;
|
||||
|
||||
if (count _group_colors > 0) then {
|
||||
@@ -15,7 +15,7 @@ if (isNil "_group_name") then {
|
||||
|
||||
_group_name = _selectedColor;
|
||||
_group setVariable ["_atak_group_name", _group_name];
|
||||
missionNamespace setVariable ["_group_colors", _group_colors]
|
||||
missionNamespace setVariable ["armatak_group_colors", _group_colors]
|
||||
} else {
|
||||
_group_name = "Red";
|
||||
_group setVariable ["_atak_group_name", _group_name];
|
||||
|
||||
@@ -1,26 +1,16 @@
|
||||
// function name: armatak_fnc_extract_callsign
|
||||
// function name: armatak_fnc_extract_marker_callsign
|
||||
// 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"];
|
||||
|
||||
private _callsign = "";
|
||||
|
||||
if (roleDescription _unit != "") then {
|
||||
_callsign = name _unit + " | " + 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 {
|
||||
_callsign = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "displayName");
|
||||
|
||||
if (!isNull driver _unit) then {
|
||||
_callsign = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "displayName") + " | " + name (driver _unit);
|
||||
_callsign = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "displayName") + " | " + ([name (driver _unit)] call armatak_fnc_shorten_name);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -34,10 +24,10 @@ if (unitIsUAV _unit) then {
|
||||
}
|
||||
};
|
||||
|
||||
_pre_defined_callsign = _unit getVariable "_atak_callsign";
|
||||
armatak_attribute_marker_callsign = _unit getVariable "armatak_attribute_marker_callsign";
|
||||
|
||||
if (!isNil "_pre_defined_callsign") then {
|
||||
_callsign = _pre_defined_callsign;
|
||||
if (!isNil "armatak_attribute_marker_callsign" or armatak_attribute_marker_callsign != '') then {
|
||||
_callsign = armatak_attribute_marker_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;
|
||||
|
||||
|
||||
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
|
||||
@@ -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
|
||||
17
addons/main/functions/extract_data/fn_shorten_name.sqf
Normal file
17
addons/main/functions/extract_data/fn_shorten_name.sqf
Normal file
@@ -0,0 +1,17 @@
|
||||
params ["_fullName"];
|
||||
|
||||
private _nameParts = _fullName splitString " ";
|
||||
private _nameCount = count _nameParts;
|
||||
|
||||
if (_nameCount == 1) then {
|
||||
_fullName
|
||||
} else {
|
||||
private _firstName = _nameParts select 0;
|
||||
private _lastName = _nameParts select (_nameCount - 1);
|
||||
|
||||
if ((count _lastName) >= 7) then {
|
||||
_lastName
|
||||
} else {
|
||||
format ["%1 %2", _firstName select [0, 1], _lastName]
|
||||
};
|
||||
};
|
||||
@@ -1,63 +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='#FF8021'>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;
|
||||
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];
|
||||
};
|
||||
};
|
||||
30
addons/main/functions/map/fn_convert_to_kunduz.sqf
Normal file
30
addons/main/functions/map/fn_convert_to_kunduz.sqf
Normal file
@@ -0,0 +1,30 @@
|
||||
params ["_longitudeInGame", "_latitudeInGame", "_altitude"];
|
||||
|
||||
private _mapWidth = 5120;
|
||||
private _mapHeight = 5120;
|
||||
|
||||
// SW corner (used as origin)
|
||||
private _SW_lat = 36.581566;
|
||||
private _SW_lon = 68.839770;
|
||||
|
||||
// SE corner
|
||||
private _SE_lat = 36.581566;
|
||||
private _SE_lon = 68.905867;
|
||||
|
||||
// NW corner
|
||||
private _NW_lat = 36.633309;
|
||||
private _NW_lon = 68.839770;
|
||||
|
||||
private _edgeSE_lat = _SE_lat - _SW_lat;
|
||||
private _edgeSE_lon = _SE_lon - _SW_lon;
|
||||
|
||||
private _edgeNW_lat = _NW_lat - _SW_lat;
|
||||
private _edgeNW_lon = _NW_lon - _SW_lon;
|
||||
|
||||
private _fx = _longitudeInGame / _mapWidth;
|
||||
private _fy = _latitudeInGame / _mapHeight;
|
||||
|
||||
private _realLat = _SW_lat + (_fx * _edgeSE_lat) + (_fy * _edgeNW_lat);
|
||||
private _realLon = _SW_lon + (_fx * _edgeSE_lon) + (_fy * _edgeNW_lon);
|
||||
|
||||
[_realLat, _realLon, _altitude]
|
||||
@@ -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 major 0
|
||||
#define minor 7
|
||||
#define patch 5
|
||||
#define major 1
|
||||
#define minor 1
|
||||
#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";
|
||||
actionName = "GitHub";
|
||||
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;
|
||||
hidePicture = 0;
|
||||
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::thread;
|
||||
|
||||
use crate::cot_generator::{DigitalPointerPayload, HumanCoTPayload, MarkerCoTPayload};
|
||||
use crate::cot;
|
||||
|
||||
pub enum TcpCommand {
|
||||
SendMessage(String, Context),
|
||||
@@ -32,14 +32,14 @@ impl TcpClient {
|
||||
|
||||
let tcp_thread = thread::spawn(move || match TcpStream::connect(&address) {
|
||||
Ok(stream) => {
|
||||
info!("Connected to TCP server at {}", address);
|
||||
let _ = ctx.callback_data("TCP SOCKET", "Connected to TCP Server", address);
|
||||
*connection_clone.lock().unwrap() = Some(stream);
|
||||
}
|
||||
Err(e) => {
|
||||
let _ = ctx.callback_data(
|
||||
"armatak_tcp_socket",
|
||||
"tak_socket_failed_connection",
|
||||
format!("Failed to connect to TCP server: {}", e),
|
||||
"TCP SOCKET ERROR",
|
||||
"TAK Socket connection failed",
|
||||
e.to_string(),
|
||||
);
|
||||
info!("Failed to connect to TCP server: {}", e);
|
||||
}
|
||||
@@ -53,15 +53,17 @@ impl TcpClient {
|
||||
info!("Failed to send message: {}", e);
|
||||
|
||||
let _ = context.callback_data(
|
||||
"armatak_tcp_socket",
|
||||
"tak_socket_disconnected",
|
||||
"TCP SOCKET ERROR",
|
||||
"TAK Socket disconnected",
|
||||
e.to_string(),
|
||||
);
|
||||
|
||||
running = false;
|
||||
}
|
||||
} else {
|
||||
let _ = context.callback_null(
|
||||
"armatak_tcp_socket",
|
||||
"tak_socket_not_active",
|
||||
"TCP SOCKET ERROR",
|
||||
"TAK Socket is not active",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -107,49 +109,47 @@ pub fn start(ctx: Context, address: String) -> &'static str {
|
||||
let mut client_guard = TCP_CLIENT.lock().unwrap();
|
||||
*client_guard = Some(client);
|
||||
|
||||
info!("TCP client started.");
|
||||
|
||||
"Starting TCP Client"
|
||||
}
|
||||
|
||||
pub fn send_payload(ctx: Context, payload: String) -> &'static str {
|
||||
if let Some(ref client) = *TCP_CLIENT.lock().unwrap() {
|
||||
info!("Sending payload: {}", payload);
|
||||
client.send_payload(ctx, payload);
|
||||
} else {
|
||||
let _ = ctx.callback_null("TCP SOCKET ERROR", "TCP Client is not running");
|
||||
info!("TCP client is not running.");
|
||||
}
|
||||
|
||||
"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();
|
||||
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();
|
||||
send_payload(ctx, payload);
|
||||
|
||||
"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();
|
||||
send_payload(ctx, payload);
|
||||
|
||||
"Sending Digital Pointer Cursor Over Time to TCP server"
|
||||
}
|
||||
|
||||
pub fn stop() -> &'static str {
|
||||
pub fn stop(ctx: Context) -> &'static str {
|
||||
if let Some(ref client) = *TCP_CLIENT.lock().unwrap() {
|
||||
client.stop();
|
||||
info!("TCP client stopped.");
|
||||
let _ = ctx.callback_null("TCP SOCKET", "TCP client stopped");
|
||||
} else {
|
||||
info!("TCP client is not running.");
|
||||
let _ = ctx.callback_null("TCP SOCKET ERROR", "TCP client is not running");
|
||||
}
|
||||
|
||||
"Stopping TCP Client"
|
||||
|
||||
26
src/lib.rs
26
src/lib.rs
@@ -2,9 +2,11 @@ use arma_rs::{arma, Extension, Group};
|
||||
mod structs;
|
||||
mod tests;
|
||||
mod websocket;
|
||||
mod util;
|
||||
mod cot_router;
|
||||
mod cot_generator;
|
||||
mod video_stream;
|
||||
|
||||
mod cot;
|
||||
mod utils;
|
||||
|
||||
#[arma]
|
||||
pub fn init() -> Extension {
|
||||
@@ -29,25 +31,31 @@ pub fn init() -> Extension {
|
||||
|
||||
log4rs::init_config(config).unwrap();
|
||||
|
||||
websocket::start();
|
||||
|
||||
Extension::build()
|
||||
.group("websocket", Group::new()
|
||||
.command("start", websocket::start)
|
||||
.command("stop", websocket::stop)
|
||||
.command("message", websocket::message)
|
||||
.command("location", websocket::location)
|
||||
)
|
||||
.command("local_ip", util::get_local_address)
|
||||
.command("uuid", util::get_uuid)
|
||||
.command("log", util::log_info)
|
||||
.command("local_ip", utils::address::get_local_address)
|
||||
.command("uuid", utils::uuid::get_uuid)
|
||||
.command("log", utils::log::log_info)
|
||||
.group(
|
||||
"cot_router",
|
||||
"tcp_socket",
|
||||
Group::new()
|
||||
.command("start", cot_router::start)
|
||||
.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_digital_pointer_cot", cot_router::send_digital_pointer_cot)
|
||||
.command("stop", cot_router::stop)
|
||||
)
|
||||
.group(
|
||||
"video_stream",
|
||||
Group::new()
|
||||
.command("start", video_stream::start_stream)
|
||||
.command("stop", video_stream::stop_stream)
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ mod tests {
|
||||
|
||||
assert!(validation.is_ok())
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn uuid_output_throws_if_passed_args() {
|
||||
let extension = init().testing();
|
||||
|
||||
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;
|
||||
}
|
||||
148
src/video_stream.rs
Normal file
148
src/video_stream.rs
Normal file
@@ -0,0 +1,148 @@
|
||||
use arma_rs::Context;
|
||||
use lazy_static::lazy_static;
|
||||
use std::process::Command;
|
||||
use std::sync::mpsc::{self, Receiver, Sender};
|
||||
use std::sync::Mutex;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
lazy_static! {
|
||||
static ref STREAM_CTRL: Mutex<Option<Sender<()>>> = Mutex::new(None);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
const CREATE_NO_WINDOW: u32 = 0x08000000;
|
||||
|
||||
pub fn start_stream(
|
||||
ctx: Context,
|
||||
address: String,
|
||||
port: String,
|
||||
stream_path: String,
|
||||
username: String,
|
||||
password: String,
|
||||
) -> &'static str {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
ctx.callback_null(
|
||||
"VIDEO ERROR",
|
||||
"Screen capture is only supported on Windows",
|
||||
);
|
||||
return "screen capture unsupported";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let (stop_tx, stop_rx): (Sender<()>, Receiver<()>) = mpsc::channel();
|
||||
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://{}:{}@{}:{}/{}",
|
||||
username, password, address, port, stream_path
|
||||
)
|
||||
};
|
||||
|
||||
let rtsp_url_clone = rtsp_url.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut cmd = Command::new("ffmpeg");
|
||||
cmd.args(&[
|
||||
"-f",
|
||||
"gdigrab",
|
||||
"-i",
|
||||
"desktop",
|
||||
"-f",
|
||||
"rtsp",
|
||||
"-rtsp_transport",
|
||||
"tcp",
|
||||
&rtsp_url_clone,
|
||||
]);
|
||||
|
||||
// Try to spawn ffmpeg process
|
||||
let child_result = cmd.creation_flags(CREATE_NO_WINDOW).spawn();
|
||||
|
||||
match child_result {
|
||||
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
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Save the stop channel so we can stop later
|
||||
match STREAM_CTRL.lock() {
|
||||
Ok(mut lock) => *lock = Some(stop_tx),
|
||||
Err(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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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 {
|
||||
match STREAM_CTRL.lock() {
|
||||
Ok(mut lock) => {
|
||||
if let Some(tx) = lock.take() {
|
||||
if let Err(e) = tx.send(()) {
|
||||
let _ = ctx.callback_data(
|
||||
"VIDEO ERROR",
|
||||
"Failed to send stop signal",
|
||||
e.to_string(),
|
||||
);
|
||||
"error sending stop"
|
||||
} else {
|
||||
let _ = ctx.callback_null("VIDEO", "Sent stop signal to FFmpeg");
|
||||
"stopping video stream"
|
||||
}
|
||||
} else {
|
||||
let _ = ctx.callback_null("VIDEO ERROR", "Tried to stop a nonexistent stream");
|
||||
"no stream to stop"
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
let _ = ctx.callback_data(
|
||||
"VIDEO ERROR",
|
||||
"Failed to acquire lock for stop",
|
||||
e.to_string(),
|
||||
);
|
||||
"lock error"
|
||||
}
|
||||
}
|
||||
}
|
||||
219
src/websocket.rs
219
src/websocket.rs
@@ -1,114 +1,173 @@
|
||||
use arma_rs::Context;
|
||||
use lazy_static::lazy_static;
|
||||
use log::info;
|
||||
use std::sync::mpsc::{self, Receiver, Sender};
|
||||
use std::sync::{Arc, Mutex};
|
||||
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 lazy_static::lazy_static;
|
||||
|
||||
pub enum WsCommand {
|
||||
SendMessage(String),
|
||||
Stop,
|
||||
SendMessage(String),
|
||||
Stop,
|
||||
}
|
||||
|
||||
enum WsEvent {
|
||||
FirstClientConnected,
|
||||
LastClientDisconnected,
|
||||
}
|
||||
|
||||
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 {
|
||||
pub fn start(&self, rx: Receiver<WsCommand>) {
|
||||
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
||||
server.stop();
|
||||
}
|
||||
pub fn start(&self, ctx: Context, rx: Receiver<WsCommand>) {
|
||||
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
let clients = Arc::new(Mutex::new(Vec::new()));
|
||||
let clients_clone = Arc::clone(&clients);
|
||||
let clients = Arc::new(Mutex::new(Vec::new()));
|
||||
let clients_clone = Arc::clone(&clients);
|
||||
let (event_tx, event_rx): (Sender<WsEvent>, Receiver<WsEvent>) = mpsc::channel();
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut running = true;
|
||||
// Start WebSocket listener in a background thread
|
||||
thread::spawn(move || {
|
||||
listen("0.0.0.0:4152", |out| WsHandler {
|
||||
out,
|
||||
clients: Arc::clone(&clients_clone),
|
||||
event_tx: event_tx.clone(),
|
||||
}).expect("WebSocket server failed to start");
|
||||
});
|
||||
|
||||
let ws_thread = thread::spawn(move || {
|
||||
listen("0.0.0.0:4152", |out| {
|
||||
let clients_inner = Arc::clone(&clients_clone);
|
||||
{
|
||||
let mut clients_guard = clients_inner.lock().unwrap();
|
||||
clients_guard.push(out.clone());
|
||||
}
|
||||
// This thread owns ctx and reacts to commands and events
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
// WebSocket message commands
|
||||
match rx.try_recv() {
|
||||
Ok(WsCommand::SendMessage(message)) => {
|
||||
let clients_guard = clients.lock().unwrap();
|
||||
for client in clients_guard.iter() {
|
||||
let _ = client.send(message.clone());
|
||||
}
|
||||
}
|
||||
Ok(WsCommand::Stop) => {
|
||||
info!("Stopping WebSocket server.");
|
||||
break;
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
|
||||
move |msg: Message| -> WsResult<()> {
|
||||
info!("Received: {}", msg);
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
.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(_) => {}
|
||||
}
|
||||
|
||||
while running {
|
||||
match rx.recv() {
|
||||
Ok(WsCommand::SendMessage(message)) => {
|
||||
let clients_guard = clients.lock().unwrap();
|
||||
for client in clients_guard.iter() {
|
||||
client.send(message.clone()).unwrap();
|
||||
}
|
||||
}
|
||||
Ok(WsCommand::Stop) => {
|
||||
running = false;
|
||||
info!("Stopping WebSocket server.");
|
||||
}
|
||||
Err(error) => {
|
||||
info!("Error receiving command: {}", error.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
thread::sleep(std::time::Duration::from_millis(10));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ws_thread.join().unwrap();
|
||||
});
|
||||
}
|
||||
pub fn send_message<T: IntoMessage>(&self, payload: T) {
|
||||
let message = payload.into_message();
|
||||
let _ = self.tx.send(WsCommand::SendMessage(message));
|
||||
}
|
||||
|
||||
pub fn send_message<T: IntoMessage>(&self, payload: T) {
|
||||
let message = payload.into_message();
|
||||
self.tx.send(WsCommand::SendMessage(message)).unwrap();
|
||||
}
|
||||
|
||||
pub fn stop(&self) {
|
||||
self.tx.send(WsCommand::Stop).unwrap();
|
||||
}
|
||||
pub fn stop(&self) {
|
||||
let _ = self.tx.send(WsCommand::Stop);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
let (tx, rx): (Sender<WsCommand>, Receiver<WsCommand>) = mpsc::channel();
|
||||
pub fn start(ctx: Context) -> &'static str {
|
||||
let (tx, rx): (Sender<WsCommand>, Receiver<WsCommand>) = mpsc::channel();
|
||||
|
||||
let server = WsServer { tx };
|
||||
server.start(rx);
|
||||
let server = WsServer { tx };
|
||||
server.start(ctx, rx);
|
||||
|
||||
let mut server_guard = WEBSOCKET_SERVER.lock().unwrap();
|
||||
*server_guard = Some(server);
|
||||
let mut server_guard = WEBSOCKET_SERVER.lock().unwrap();
|
||||
*server_guard = Some(server);
|
||||
|
||||
info!("WebSocket server started.");
|
||||
|
||||
"Starting WebSocket Server"
|
||||
"Starting WebSocket Server"
|
||||
}
|
||||
|
||||
pub fn message(payload: String) -> &'static str {
|
||||
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
||||
info!("Broadcasting message: {}", payload);
|
||||
server.send_message(payload);
|
||||
} else {
|
||||
info!("WebSocket server is not running.");
|
||||
}
|
||||
pub fn message(ctx: Context, payload: String) -> &'static str {
|
||||
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
||||
info!("Broadcasting message: {}", payload); // why the fuck i did this?
|
||||
server.send_message(payload);
|
||||
} else {
|
||||
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 {
|
||||
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
||||
server.send_message(payload);
|
||||
} else {
|
||||
info!("WebSocket server is not running.");
|
||||
}
|
||||
"sending location to all WebSocket clients"
|
||||
pub fn location(ctx: Context, payload: LocationPayload) -> &'static str {
|
||||
if let Some(ref server) = *WEBSOCKET_SERVER.lock().unwrap() {
|
||||
server.send_message(payload);
|
||||
} else {
|
||||
let _ = ctx.callback_null("WEBSOCKET ERROR", "Websocket is not running");
|
||||
}
|
||||
|
||||
"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