163 Commits

Author SHA1 Message Date
Valmo Trindade 7e4379ada4 Added enemy marker function to ease enemy marking 2025-11-20 04:51:10 -03:00
Valmo Trindade 572b2a360f ADded zagorsk reserverd forest map 2025-11-20 04:50:52 -03:00
Valmo Trindade 083ccd2906 Linted cot refresh rate 2025-11-15 06:56:47 -03:00
Valmo Trindade 35a45d2cd4 fixed drone handler 2025-11-15 06:48:03 -03:00
Valmo Trindade 2b241fbeaf Fixed extract position function and dependency chain 2025-11-15 01:57:23 -03:00
Valmo Trindade ad9ba834cc Merge pull request #22 from Roborob1234/patch-1
Update fn_convert_to_stratis.sqf
2025-10-18 02:29:58 -03:00
Rob Haddow 469403d9b5 Update fn_convert_to_stratis.sqf
[Fix] Corrected NW corner from my earlier work, NW corner had the Lat value of the S edge.
2025-10-17 19:28:17 -05:00
Valmo Trindade 01ea754f57 Merge pull request #21 from Roborob1234/Rob's-tinkering
Stratis and Tanoa coordinate update
2025-10-14 19:24:37 -03:00
Rob Haddow fd8a25790e Update fn_convert_to_stratis.sqf
Updated Stratis with in game map size and accurized map corners
2025-10-13 12:15:04 -05:00
Rob Haddow 9ede7237b8 Merge branch 'valmojr:main' into patch-2 2025-10-13 11:30:43 -05:00
Valmo Trindade 1242b1f79f Fixed drone params on callsign function 2025-10-12 20:44:38 -03:00
Valmo Trindade 9f8f326446 fixed params on log function 2025-10-12 20:44:25 -03:00
Valmo Trindade bf3b0cf0d4 Added ConfigOf props 2025-10-12 20:44:17 -03:00
Valmo Trindade 42098401f2 Fixed syntax on ConverClientPosition function 2025-10-12 20:43:36 -03:00
Valmo Trindade cad4aaa1a5 Added Tanoa to switch case function to manage positions 2025-10-12 20:31:00 -03:00
Roborob1234 ef787a6a09 Update fn_convert_to_tanoa.sqf
Updated Tanoa map size from Altis Default and changed IRL Map edges to align with results from US FCC lat lon calculator: https://www.fcc.gov/media/radio/dms-decimal
2025-10-12 18:14:49 -05:00
Valmo Trindade 2e017f97c9 Removed executable because brett said dont need it 2025-09-09 14:16:02 -03:00
Valmo Trindade fbd58d9426 Removed SIMTAK apk from includes, added executable for linux 2025-09-04 11:24:29 -03:00
Valmo Trindade 894a11f087 Removed FFMPEG Video Streaming support for now, it has many variables to deal with it yet 2025-07-30 23:10:55 -03:00
Valmo Trindade dacb38fe45 Added github action to push into production mod when a release is approved 2025-07-30 23:09:51 -03:00
Valmo Trindade 2298254e24 Changed UDP Socket bind address to match the LOCAL address and point to a LOCAL target address, this will fit 99% of the use cases and avoid many mistakes 2025-07-30 15:15:38 -03:00
Valmo Trindade 853000a5c9 fixed LFS images 2025-07-30 14:31:06 -03:00
Valmo Trindade d0b47dd315 changed arma 3 executable to fit my linux proton installation 2025-07-30 12:48:02 -03:00
Valmo Trindade 3c9dd1bea4 removed websocket component from extension part 2025-07-16 13:18:07 -03:00
Valmo Trindade 4d89ea7bc5 removed unused dialog imports 2025-07-16 13:05:02 -03:00
Valmo Trindade b97d13121e (WIP) refacotred video stream generator 2025-07-16 12:46:53 -03:00
Valmo Trindade dcfdb0451c removed stop UDP Socket function because it was not implemented, and will not be soo close 2025-07-16 12:46:43 -03:00
Valmo Trindade 83b9082e87 added end of line in all files 2025-07-16 12:46:12 -03:00
Valmo Trindade 2ab83a17b9 refactored lfs objects 2025-07-12 12:17:55 -03:00
Valmo Trindade 4ae35335e2 Added fail callback UDP switch to turn of config on clientside 2025-06-25 13:10:15 -03:00
Valmo Trindade a1bf9472ae added static video geoencoding to test KLV data 2025-06-24 19:34:08 -03:00
Valmo Trindade 15129bb344 removed useless mod metadata from addons/video config 2025-06-23 02:25:36 -03:00
Valmo Trindade f143d80c34 added more cool mod preset 2025-06-23 02:25:22 -03:00
Valmo Trindade e713c2f35f refactored video stream handler to handle RTSP feed on linux with multiple OS data, avoinding DRY 2025-06-19 23:44:19 -03:00
Valmo Trindade b1fac90e78 Switched release description to match the commit tag only 2025-06-19 20:25:20 -03:00
Valmo Trindade 8341288457 Removed unused mods to hemtt launcher 2025-06-17 23:35:02 -03:00
Valmo Trindade 4ad2b2d6dd Added video feed support for Linux clients 2025-06-17 05:21:11 -03:00
Valmo Trindade 485e67120c reduce the external gps position frequency to 2Hz 2025-06-17 05:16:32 -03:00
Valmo Trindade 60f04bc4e8 added start and stop functions for the UDP Socket 2025-06-17 03:57:23 -03:00
Valmo Trindade 35742847a7 linted extract group color function and parsed colors gvar 2025-06-17 03:57:13 -03:00
Valmo Trindade c8c2b639ea removed group info from client side, because sadly it won't work as a handler for it 2025-06-17 03:56:48 -03:00
Valmo Trindade 0453470f1f defined group colors as a init gvar 2025-06-17 03:54:56 -03:00
Valmo Trindade d9da877da6 added ace self action to create the eud connection dialog 2025-06-17 03:43:07 -03:00
Valmo Trindade ed2b09a5f6 defined rust as main language of the project 2025-06-17 03:42:36 -03:00
Valmo Trindade c1198ef287 added dialog to input data for eud connection 2025-06-17 03:42:26 -03:00
Valmo Trindade 58f6d3f349 removed unused imports on server dialogs 2025-06-17 03:42:15 -03:00
Valmo Trindade 67a7fa99af removed gradle config 2025-06-17 02:23:59 -03:00
Valmo Trindade 220c56f01d Removed SIMTAK for the workflows on GH actions 2025-06-17 02:23:40 -03:00
Valmo Trindade 30be943581 FINALLY removed the SIMTAK application for my project, it was a good start, but it's time to move on and i got it native on ATAK, thanks @Andonyth for the help 2025-06-17 02:12:28 -03:00
Valmo Trindade a859e55c1b Managed dependencies and remove many legacy features dependencies and unused stuff 2025-06-17 02:03:37 -03:00
Valmo Trindade f491b06664 Improved callbacks for UDP sockets 2025-06-17 01:54:30 -03:00
Valmo Trindade 874686c975 changed the extractClientPosition to fit the external gps use case 2025-06-17 01:42:37 -03:00
Valmo Trindade 2a7c1b8ae8 removed websocket stuff from the functions because i can make this go to the trash can 2025-06-17 01:41:50 -03:00
Valmo Trindade 8ddbefee18 Improved callback handlers to get UDP socket stuff 2025-06-17 01:41:22 -03:00
Valmo Trindade 2b190d72c5 fixed callsign function calls on cot generators 2025-06-17 01:40:49 -03:00
Valmo Trindade 9fb8311aca Added UDP Socket, because now i can mock a external GPS on EUD and that's awesome 2025-06-17 01:40:26 -03:00
Valmo Trindade d4f6ddb0fa linted linux block because now i actually have to care about linux 2025-06-17 01:38:43 -03:00
Valmo Trindade 0dd12a275b removed unused structs from root project 2025-06-17 01:38:12 -03:00
Valmo Trindade c45708066e renamed tcp socket folder for a name that actually makes any sense 2025-06-17 01:37:45 -03:00
Valmo Trindade 0de4cf75e8 Added GPS CoT Structs 2025-06-17 01:37:28 -03:00
Valmo Trindade 9bb4483266 linted digital pointer structs 2025-06-16 04:27:06 -03:00
Valmo Trindade ffc75cf4c4 added handler (personal) for the linux hemtt launch params 2025-06-16 04:26:55 -03:00
Valmo Trindade 2919805844 fixed uni callsign extraction on group cot sender 2025-06-16 04:26:15 -03:00
Valmo Trindade f3bff2b9cf Added Kunduz Valley Map Support 2025-06-01 04:19:35 -03:00
Valmo Trindade 74cda1c9a6 fixed extract position call on laser marker 2025-06-01 03:19:47 -03:00
Valmo Trindade 6c667d69b8 improved router entity add and remove function 2025-05-28 00:32:57 -03:00
Valmo Trindade 5f62304965 change if hell to switchcase on 3denCoremodule config func 2025-05-28 00:32:37 -03:00
Valmo Trindade 082831951e change if hell to switchcase on callback handlers func 2025-05-28 00:32:20 -03:00
Valmo Trindade 645a16394b change if hell to switchcase on zeusCoremodule config func 2025-05-28 00:32:00 -03:00
Valmo Trindade 0340a84e9c TEMP removed cfgvehicles 2025-05-22 23:22:14 -03:00
Valmo Trindade 50cf9b10bd TEMP moved CfgVehicles 2025-05-22 23:20:48 -03:00
Valmo Trindade 6e220e5807 changed release drafter cannon to prepare the release but not to do it 2025-05-22 23:14:12 -03:00
Valmo Trindade c1f61dc4aa Added initial custom marker dialog and fixed core module background 2025-05-22 23:12:36 -03:00
Valmo Trindade d8e08b8da8 removed group stuff because arma 3 code sucks 2025-05-22 23:12:17 -03:00
Valmo Trindade 1fee414ff0 added condition for adding groups into cot router 2025-05-22 03:34:11 -03:00
Valmo Trindade b41008df8b improved curator core module gui, still missing background color 2025-05-22 03:24:47 -03:00
Valmo Trindade 3d775db2cc removed core module logic after use 2025-05-22 03:24:24 -03:00
Valmo Trindade 7b5510698e refactored video streaming module 2025-05-22 03:24:10 -03:00
Valmo Trindade 3f028b48c8 Improved server module defines 2025-05-21 20:04:33 -03:00
Valmo Trindade aa7b27ac2e Added functions for adding and removing entities into the marked entitis gvar for the CoT Router 2025-05-21 20:03:59 -03:00
Valmo Trindade 2d207965db removed unused funcs 2025-05-20 21:42:15 -03:00
Valmo Trindade 2e2a321006 Added Mark Entity curator module to add entities in game 2025-05-20 21:40:27 -03:00
Valmo Trindade 67fa1cfe52 added synced units as global variables 2025-05-20 01:49:17 -03:00
Valmo Trindade 730440f4ac fixed position convert function calls 2025-05-20 01:48:55 -03:00
Valmo Trindade 1d65705aa8 Refactored server addon Cfgvehicle to allow core module to work on zeus 2025-05-19 23:35:12 -03:00
Valmo Trindade f04c0141ef Moved dialog window for TCP Socket connection startup to server addon 2025-05-19 23:34:18 -03:00
Valmo Trindade e06c199816 fixed CfgPatches modules 2025-05-19 22:54:26 -03:00
Valmo Trindade 94c7752844 Removed CfgVehicles from main addon 2025-05-19 21:58:23 -03:00
Valmo Trindade 9bdb4770c9 added notify func to cot router function 2025-05-19 21:57:32 -03:00
Valmo Trindade 98e63a7152 Rollbacked Client MEHs to the main addon to center all MEH 2025-05-18 17:58:25 -03:00
Valmo Trindade 3a179ea958 Fixed GVAR external calls 2025-05-17 23:24:30 -03:00
Valmo Trindade af15a44fb6 Moved Server and video info from main to its own addons 2025-05-17 23:15:02 -03:00
Valmo Trindade ac18c45bef Added MEH for EUD connection to set vars on players 2025-05-17 22:11:05 -03:00
Valmo Trindade 65b8aaebe3 removed video function from main 2025-05-17 22:10:47 -03:00
Valmo Trindade b3bd58385e Created video addon 2025-05-17 22:10:28 -03:00
Valmo Trindade 29574bc36c Improved callback for EUD connections in websocket 2025-05-17 05:26:36 -03:00
Valmo Trindade 6208286294 linted callback EH logging 2025-05-17 05:02:39 -03:00
Valmo Trindade 2299a3f5c9 linted video streaming callbacks 2025-05-17 05:01:50 -03:00
Valmo Trindade 098de89d95 linted TCP Socket callbacks 2025-05-17 05:01:40 -03:00
Valmo Trindade 8f7d5425ad linted all websocket callbacks 2025-05-17 04:47:01 -03:00
Valmo Trindade 938f0bcb6a Fixed postInit EH classnames 2025-05-17 04:07:03 -03:00
Valmo Trindade 577125120d Added systemChat for unhandled notify calls 2025-05-16 03:35:08 -03:00
Valmo Trindade 5c599877ca Removed callback handler, added XEH stuff to main addon 2025-05-16 03:34:51 -03:00
Valmo Trindade c1b00cb050 Switched WebSocket start motor to allow callbacks when client connects 2025-05-16 03:33:08 -03:00
Valmo Trindade 319ea9b32a added XEH_postInit to start websocket on client side 2025-05-16 01:11:22 -03:00
Valmo Trindade eda786931d added initial version of server addon to handle TCP socket into the TAK Server 2025-05-16 00:38:42 -03:00
Valmo Trindade 31f7b5178e changed main addon prefix 2025-05-16 00:25:35 -03:00
Valmo Trindade 8a6dcff05d added notify function for DRY 2025-05-16 00:25:24 -03:00
Valmo Trindade f2fe8b586c added documentation for convertClientLocation function 2025-05-16 00:23:34 -03:00
Valmo Trindade bcefc7670f removed padding on websocket router 2025-05-15 23:56:52 -03:00
Valmo Trindade 12c8781236 removed padding on macro call during socketrouter var handling 2025-05-15 23:56:35 -03:00
Valmo Trindade d81c8fa67b fixed convert location xeh call 2025-05-15 23:56:02 -03:00
Valmo Trindade 6de6a29a09 Added whole websocket handling to the client addon 2025-05-15 23:48:14 -03:00
Valmo Trindade ffcd4feb4e exploded main addon to divide componenets into addons for each feature 2025-05-15 17:53:25 -03:00
Valmo Trindade 39f4936bf7 added defines for main addon 2025-05-14 05:07:45 -03:00
Valmo Trindade 25549cda25 Added initial zeus core config module function 2025-05-14 05:07:29 -03:00
Valmo Trindade 5231dae17a added CfgMods to main config 2025-05-14 05:07:05 -03:00
Valmo Trindade f669cc1cc0 added CBA and ACE Macros for better coding xp 2025-05-13 22:36:20 -03:00
Valmo Trindade 43f1cd3bb2 added JSRS to launch mods for cool shootings 2025-05-13 01:11:13 -03:00
Valmo Trindade ec9d3693bf added initial GUI interface for zeus core module config window 2025-05-13 01:10:56 -03:00
Valmo Trindade 01efe4e01d removed private identifier from global variables 2025-05-13 01:09:51 -03:00
Valmo Trindade a997c54170 added initial zeus core module functions 2025-05-13 01:09:12 -03:00
Valmo Trindade 68b0fd1e38 added handleCallbacks function for DRY 2025-05-13 01:08:58 -03:00
Valmo Trindade 9c82832a54 updated callsign function calls i cot router loop 2025-05-10 06:18:48 -03:00
Valmo Trindade d9e7dfe497 changed extract role to handle attribute provided 2025-05-10 05:51:06 -03:00
Valmo Trindade 49afb54b80 removed old callsign function 2025-05-10 05:39:30 -03:00
Valmo Trindade 5d6846c5fa dismantled callsign function from units and markers 2025-05-10 05:38:53 -03:00
Valmo Trindade 9bb4a8feaa added 3den attributes for callsign, group color, roles, and marker types 2025-05-10 05:23:28 -03:00
Valmo Trindade 50b118cbfe called 3den config on main addon config 2025-05-09 18:46:51 -03:00
Valmo Trindade d11050fcc8 added initial Cfg3den config with callsign and role handlers 2025-05-09 18:46:36 -03:00
Valmo Trindade 3d8baae344 updated tcp scoket handler on SQF functions 2025-05-09 18:29:17 -03:00
Valmo Trindade 1d7cce8409 added stop tcp socket function to check gvars and sto the socket 2025-05-09 18:27:12 -03:00
Valmo Trindade 3f4535cf17 switched cot router anme to tcp socket on extension caller 2025-05-09 18:26:51 -03:00
Valmo Trindade 4412b67d63 updated send_human_cot to send-eud_cot to match new cot generation flow 2025-04-17 06:37:50 -03:00
Valmo Trindade 3128ac0022 Improved code structure on Cursor Over Time generation 2025-04-17 06:37:29 -03:00
Valmo Trindade b230515675 moved rust util functions to use folder structure 2025-04-16 16:51:21 -03:00
Valmo Trindade ad2f529345 defined warning in armatak video callback EHs 2025-04-16 16:50:19 -03:00
Valmo Trindade 162f3c7e7a handled RTSP video stream requests without authentication 2025-04-16 05:34:27 -03:00
Valmo Trindade ca4231f669 improved video stream filepath generation 2025-04-11 02:35:16 -03:00
Valmo Trindade 8334ff4be5 added version 2025-04-10 22:15:12 -03:00
Valmo Trindade 19907184be improved precision on kunduz map 2025-04-10 19:16:49 -03:00
Valmo Trindade f2ba112ae4 linted PR template 2025-04-08 16:05:27 -03:00
Valmo Trindade b8bb01e985 improved video feed path generator to use player's name and role 2025-04-07 04:46:53 -03:00
Valmo Trindade 10d0b6f86c separed video stream oss in scopes 2025-04-07 01:28:10 -03:00
Valmo Trindade db16d94596 added scopes for windows and linux on video stream 2025-04-06 17:53:47 -03:00
Valmo Trindade 9fc7a0e1bd added windows target to video stop callback 2025-04-06 16:46:33 -03:00
Valmo Trindade f9b5860f9b Added handling for letting only windows calls work and throw a callback when called form a linux on video streams 2025-04-06 16:24:40 -03:00
Valmo Trindade 51b1a06e6c updated project version 2025-04-06 06:03:08 -03:00
Valmo Trindade 63c60bc81a made ffmpeg thread running with no window 2025-04-06 06:02:53 -03:00
Valmo Trindade 10683d9e2f Added function and editor module for handling the video stream paramethers 2025-04-06 05:42:30 -03:00
Valmo Trindade 871d6ec9d3 Added extension calls for starting and stopping a RTSP Video Stream for being used by OTS MEDIAMTX 2025-04-06 05:38:41 -03:00
Valmo Trindade 6eca9e92b6 added loop breaker for Disconnected TCP socket 2025-04-06 05:37:59 -03:00
Valmo Trindade a8f6b04221 Improved TCP Socket Callbacks 2025-04-06 04:20:25 -03:00
Valmo Trindade 7831b25062 linted tcp socket error callback messages 2025-04-06 04:01:13 -03:00
Valmo Trindade c490483abb added more extension callback EH for handling error msgs in game 2025-04-06 04:00:26 -03:00
Valmo Trindade 1719a16894 fixed Kunduz map size on convert function 2025-04-03 12:26:35 -03:00
Valmo Trindade 8e4b967f7d improved error callback messages 2025-04-03 12:26:07 -03:00
Valmo Trindade 91eeee9989 Added Kunduz map integration 2025-03-30 23:20:22 -03:00
Valmo Trindade 48512f587b Fixed Southen sahrani convertion call 2025-03-30 23:20:04 -03:00
Valmo Trindade ddf60c439c switched to v1 2025-03-21 18:52:02 -03:00
Valmo Trindade 8e1fc2170a Changed default port to TCP 8088 2025-03-21 18:51:48 -03:00
Valmo Trindade 25628016ee Merge branch 'short_name' 2025-03-21 18:46:33 -03:00
Valmo Trindade 2ac29f50a6 added function to handle names for vehicles 2025-02-19 17:48:05 -03:00
182 changed files with 4960 additions and 5179 deletions
+2
View File
@@ -1,3 +1,5 @@
*.rs linguist-language=Rust
*.paa filter=lfs diff=lfs merge=lfs -text *.paa filter=lfs diff=lfs merge=lfs -text
*.p3d filter=lfs diff=lfs merge=lfs -text *.p3d filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text *.jpeg filter=lfs diff=lfs merge=lfs -text
+1
View File
@@ -1,4 +1,5 @@
**When merged this pull request will:** **When merged this pull request will:**
- _Describe what this pull request will do_ - _Describe what this pull request will do_
- _Each change in a separate line_ - _Each change in a separate line_
+1 -32
View File
@@ -5,32 +5,6 @@ on:
branches: [ main ] branches: [ main ]
jobs: jobs:
package_application:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
lfs: true
- name: set up JDK 11
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'zulu'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew assembleDebug
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: simtak
path: app/build/outputs/apk/debug/app-debug.apk
if-no-files-found: error
retention-days: 1
build_extension: build_extension:
strategy: strategy:
matrix: matrix:
@@ -66,7 +40,7 @@ jobs:
retention-days: 1 retention-days: 1
package: package:
needs: [build_extension, package_application] needs: [build_extension]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repo - name: Checkout Repo
@@ -88,11 +62,6 @@ jobs:
with: with:
name: x86_64-unknown-linux-gnu name: x86_64-unknown-linux-gnu
- run: mv ./libarmatak.so ./armatak_x64.so - run: mv ./libarmatak.so ./armatak_x64.so
- name: Download Android Application Installer
uses: actions/download-artifact@v4
with:
name: simtak
- run: mv ./app-debug.apk ./simtak.apk
- name: Setup HEMTT - name: Setup HEMTT
uses: arma-actions/hemtt@v1 uses: arma-actions/hemtt@v1
- name: Build - name: Build
+1 -32
View File
@@ -5,32 +5,6 @@ on:
branches: [ main ] branches: [ main ]
jobs: jobs:
package_application:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
lfs: true
- name: set up JDK 11
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'zulu'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew assembleDebug
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: simtak
path: app/build/outputs/apk/debug/app-debug.apk
if-no-files-found: error
retention-days: 1
build_extension: build_extension:
strategy: strategy:
matrix: matrix:
@@ -66,7 +40,7 @@ jobs:
retention-days: 1 retention-days: 1
package: package:
needs: [build_extension, package_application] needs: [build_extension]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repo - name: Checkout Repo
@@ -88,11 +62,6 @@ jobs:
with: with:
name: x86_64-unknown-linux-gnu name: x86_64-unknown-linux-gnu
- run: mv ./libarmatak.so ./armatak_x64.so - run: mv ./libarmatak.so ./armatak_x64.so
- name: Download Android Application Installer
uses: actions/download-artifact@v4
with:
name: simtak
- run: mv ./app-debug.apk ./simtak.apk
- name: Setup HEMTT - name: Setup HEMTT
uses: arma-actions/hemtt@v1 uses: arma-actions/hemtt@v1
- name: Build - name: Build
+3 -33
View File
@@ -9,31 +9,6 @@ permissions:
contents: write contents: write
jobs: jobs:
package_application:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
lfs: true
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'zulu'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew assembleDebug
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: simtak
path: app/build/outputs/apk/debug/app-debug.apk
if-no-files-found: error
retention-days: 1
build_extension: build_extension:
strategy: strategy:
matrix: matrix:
@@ -69,7 +44,7 @@ jobs:
retention-days: 1 retention-days: 1
package: package:
needs: [build_extension, package_application] needs: [build_extension]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repo - name: Checkout Repo
@@ -91,11 +66,6 @@ jobs:
with: with:
name: x86_64-unknown-linux-gnu name: x86_64-unknown-linux-gnu
- run: mv ./libarmatak.so ./armatak_x64.so - run: mv ./libarmatak.so ./armatak_x64.so
- name: Download Android Application Installer
uses: actions/download-artifact@v4
with:
name: simtak
- run: mv ./app-debug.apk ./simtak.apk
- name: Setup HEMTT - name: Setup HEMTT
uses: arma-actions/hemtt@v1 uses: arma-actions/hemtt@v1
- name: Build - name: Build
@@ -121,8 +91,8 @@ jobs:
release_name: ${{ github.ref }} release_name: ${{ github.ref }}
body: | body: |
Changes in this release: Changes in this release:
${{ env.COMMIT_MESSAGES }} ${{ github.event.head_commit.message }}
draft: false draft: true
prerelease: false prerelease: false
- name: Upload Release Asset - name: Upload Release Asset
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
+79
View File
@@ -0,0 +1,79 @@
name: Publish Production
on:
release:
types: [published]
jobs:
build_extension:
strategy:
matrix:
os_target:
- { os: "windows-latest", target: "i686-pc-windows-msvc", artifact: "armatak.dll", name: "armatak.dll" }
- { os: "windows-latest", target: "x86_64-pc-windows-msvc", artifact: "armatak.dll", name: "armatak_x64.dll" }
- { os: "ubuntu-latest", target: "x86_64-unknown-linux-gnu", artifact: "libarmatak.so", name: "armatak.so" }
runs-on: ${{ matrix.os_target.os }}
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
lfs: true
- name: Install Rust Toolchain
uses: actions-rs/toolchain@v1
with:
target: ${{ matrix.os_target.target }}
toolchain: stable
default: true
- name: Install Dependencies (Linux only)
if: matrix.os_target.os == 'ubuntu-latest'
run: sudo apt-get update && sudo apt-get install -y build-essential
- name: Cargo Build
run: cargo build --release --target ${{ matrix.os_target.target }}
- name: check stuff
run: ls target/release
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.os_target.target }}
path: target/${{ matrix.os_target.target }}/release/${{ matrix.os_target.artifact }}
if-no-files-found: error
retention-days: 1
package:
needs: [build_extension]
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
lfs: true
- run: mkdir -p ./target/release
- name: Download Windows x64 Artifact
uses: actions/download-artifact@v4
with:
name: x86_64-pc-windows-msvc
- run: mv ./armatak.dll ./armatak_x64.dll
- name: Download Windows x86 Artifact
uses: actions/download-artifact@v4
with:
name: i686-pc-windows-msvc
- name: Download Linux x64 Artifact
uses: actions/download-artifact@v4
with:
name: x86_64-unknown-linux-gnu
- run: mv ./libarmatak.so ./armatak_x64.so
- name: Setup HEMTT
uses: arma-actions/hemtt@v1
- name: Build
run: hemtt release
- name: Extract Zipped Mod
run: unzip releases/armatak-latest.zip -d releases
- uses: arma-actions/workshop-upload@v1
with:
appId: '107410'
itemId: ${{ secrets.STEAM_WORKSHOP_PROD_ID }}
contentPath: releases/@armatak
changelog: 'Update'
env:
STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }}
STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }}
+25 -10
View File
@@ -5,8 +5,8 @@ prefix = "armatak"
[version] [version]
build = 0 build = 0
major = 0 major = 1
minor = 9 minor = 1
patch = 0 patch = 0
git_hash = 0 git_hash = 0
@@ -25,8 +25,7 @@ include = [
"LICENSE", "LICENSE",
"*.dll", "*.dll",
"*.so", "*.so",
"*.paa", "*.paa"
"simtak.apk"
] ]
[properties] [properties]
@@ -38,13 +37,29 @@ preset = "Hemtt"
[hemtt.launch.default] [hemtt.launch.default]
workshop = [ workshop = [
"450814997", # CBA "450814997", # CBA_A3
"463939057", # ACE "463939057", # ACE
"623475643", # 3den enhanced "751965892", # ACRE2
"1779063631", # Zeus enhanced "2522638637", # ACE Extended Arsenal
"1673595418", # User Input Menus "333310405", # Enhanced Movement
"1678581937", # Extended Function Viewer "2034363662", # Enhanced Movement Rework
"1231625987" #Debug Console "2941986336", # Hatchet Interaction Framework - Stable Version
"1745501605", # Hatchet H-60 pack - Stable Version
"843577117", # RHSUSAF
"843425103", # RHSAFRF
"843632231", # RHSSAF
"843593391", # RHSGREF
"1673456286", # 3CB Factions
"623475643", # 3den Enhanced
"2257686620", # Blastcore Murr Edition
"583496184", # CUP Terrains - Core
"3078351739", # Kunduz River
"1858075458", # LAMBS_Danger.fsm
"1808238502", # LAMBS_Suppression
"3425368881", # M4A1_URGI
"2268351256", # Tier One Weapons
"2560276469", # Restrict Markers
"3493557838" # Ballad of the Green Berets
] ]
parameters = [ parameters = [
Generated
+246 -1497
View File
File diff suppressed because it is too large Load Diff
+1 -11
View File
@@ -1,26 +1,16 @@
[package] [package]
name = "armatak" name = "armatak"
version = "0.9.0" version = "1.0.1"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
arma-rs = "1.10.4" arma-rs = "1.10.4"
chrono = "0.4.39" chrono = "0.4.39"
futures = "0.3.31"
futures-util = "0.3.31"
http = "1.1.0"
lazy_static = "1.5.0" lazy_static = "1.5.0"
log = "0.4.22" log = "0.4.22"
log4rs = "1.3.0" log4rs = "1.3.0"
once_cell = "1.19.0" once_cell = "1.19.0"
qrcode = "0.14.1"
regex = "1.10.6"
reqwest = { version = "0.12.7", features = ["blocking"] }
serde = { version = "1.0.210", features = ["derive"] } serde = { version = "1.0.210", features = ["derive"] }
serde_json = "1.0.128"
tokio = { version = "1.40", features = ["full"] }
tokio-tungstenite = "0.24.0"
ws = "0.9.2"
[dependencies.uuid] [dependencies.uuid]
version = "1.10.0" version = "1.10.0"
+1
View File
@@ -0,0 +1 @@
armatak\armatak\addons\client
+17
View 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));
};
};
+3
View File
@@ -0,0 +1,3 @@
PREP(convertClientLocation);
PREP(extractClientPosition);
PREP(startUDPSocket);
+8
View File
@@ -0,0 +1,8 @@
#include "script_component.hpp"
if (!hasInterface) exitWith {};
_local_address = "armatak" callExtension ["local_ip", []] select 0;
SETVAR(player,GVAR(localAddress),_local_address);
SETVAR(player,GVAR(eudConnected),false);
+9
View File
@@ -0,0 +1,9 @@
#include "script_component.hpp"
ADDON = false;
PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;
ADDON = true;
+3
View File
@@ -0,0 +1,3 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"
+35
View File
@@ -0,0 +1,35 @@
#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";
};
};
class CfgVehicles {
class Man;
class CAManBase: Man {
class ACE_SelfActions {
class danceParty {
displayName = "Connect to EUD";
condition = "!(player getVariable ['armatak_client_eudConnected', false])";
exceptions[] = {};
statement = "createDialog 'armatak_udp_socket_start_dialog'";
icon = "";
};
};
};
};
#include "CfgEventHandlers.hpp"
#include "dialog.hpp"
+73
View File
@@ -0,0 +1,73 @@
class RscText;
class RscBackground;
class RscButton;
class RscEdit;
class armatak_udp_socket_start_dialog {
idd = 999091;
movingEnable = 0;
class ControlsBackground {
class armatak_gui_module_udp_socket_dialog_main_frame: RscBackground {
idc = 16960;
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_udp_socket_dialog_address_edit: RscEdit {
idc = 16961;
text = "168.15.0.3";
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_udp_socket_dialog_address_port_edit: RscEdit {
idc = 16962;
text = "4349";
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_udp_socket_dialog_address_text: RscText {
idc = 16963;
text = "Phone's Socket Local Address";
x = "0.391719 * safezoneW + safezoneX";
y = "0.412 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.033 * safezoneH";
};
class armatak_gui_module_udp_socket_dialog_address_port_text: RscText {
idc = 16964;
text = "Phone's Socket Local Port";
x = "0.391719 * safezoneW + safezoneX";
y = "0.489 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.033 * safezoneH";
};
class armatak_gui_module_udp_socket_dialog_address_button_cancel: RscButton {
idc = 16965;
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_udp_socket_dialog_address_button_ok: RscButton {
idc = 16966;
text = "Ok";
action = QUOTE(call FUNC(startUDPSocket));
x = "0.5 * safezoneW + safezoneX";
y = "0.577 * safezoneH + safezoneY";
w = "0.0464063 * safezoneW";
h = "0.055 * safezoneH";
};
};
};
@@ -1,3 +1,24 @@
#include "..\script_component.hpp"
/*
* Author: Valmo Trindade
* This function is used to convert the position of a unit to the world world location.
*
* Argument:
* 0: in game latitude <NUMBER> is the latitude of the unit.
* 1: in game longitude <NUMBER> is the longitude of the unit.
* 2: in game altitude <NUMBER> is the altitude of the unit.
* 3: in game bearing <NUMBER> is the bearing of the unit.
*
* Return Value:
* ARRAY -> [latitude, longitude, altitude, bearing]
*
* Example:
* [player] call armatak_client_fnc_convertClientLocation;
*
* Public: Yes
*/
params["_latitude", "_longitude", "_altitude"]; params["_latitude", "_longitude", "_altitude"];
_position = [_latitude, _longitude, _altitude]; _position = [_latitude, _longitude, _altitude];
@@ -42,11 +63,23 @@ switch (toLower worldName) do {
_realLocation = _position call armatak_fnc_convert_to_united_sahrani; _realLocation = _position call armatak_fnc_convert_to_united_sahrani;
}; };
case "saralite": { case "saralite": {
_realLocation = _position call armatak_fnc_convert_to_united_sahrani; _realLocation = _position call armatak_fnc_convert_to_southen_sahrani;
}; };
case "enoch": { case "enoch": {
_realLocation = _position call armatak_fnc_convert_to_livonia; _realLocation = _position call armatak_fnc_convert_to_livonia;
}; };
case "kunduz": {
_realLocation = _position call armatak_fnc_convert_to_kunduz;
};
case "kunduz_valley": {
_realLocation = _position call armatak_fnc_convert_to_kunduz_valley;
};
case "tanoa": {
_realLocation = _position call armatak_fnc_convert_to_tanoa;
};
case "zagor_zagorsk_reserved_forest": {
_realLocation = _position call armatak_fnc_convert_to_zagor_zagorsk_reserved_forest;
};
default { default {
_warning = format ["<t color='#FF8021'>ARMATAK</t><br/> %1", "Unsupported Map"]; _warning = format ["<t color='#FF8021'>ARMATAK</t><br/> %1", "Unsupported Map"];
[[_warning, 1.5]] call CBA_fnc_notify; [[_warning, 1.5]] call CBA_fnc_notify;
@@ -0,0 +1,29 @@
#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 _uuid = _unit call armatak_fnc_extract_uuid;
private _pos = (getPos _unit) call FUNC(convertClientLocation);
private _callsign = _unit call armatak_fnc_extract_unit_callsign;
private _bearing = parseNumber ((getDir _unit) toFixed 0);
private _speed = speed _unit / 3.6;
_payload = [_uuid, _pos select 0, _pos select 1, _pos select 2, _callsign, _bearing, _speed, _callsign];
_payload
@@ -0,0 +1,31 @@
#include "..\script_component.hpp"
params ["_logic"];
_socket_is_running = player getVariable [QGVAR(eudConnected), false];
if (_socket_is_running) exitWith {
["Socket is already running", "error", "UDP Socket"] call EFUNC(main,notify);
closeDialog 1;
};
disableSerialization;
_udp_socket_instance_address = ctrlText 16961;
_udp_socket_instance_port = ctrlText 16962;
_udp_socket_fulladdress = ((_udp_socket_instance_address) + ":" + (_udp_socket_instance_port));
player setVariable [QGVAR(udp_socket_address), _udp_socket_fulladdress];
player setVariable [QGVAR(eudConnected), true];
"armatak" callExtension ["udp_socket:start", [_udp_socket_fulladdress]];
[{
if (player getVariable [QGVAR(eudConnected), false]) then {
"armatak" callExtension ["udp_socket:send_gps_cot", [player call FUNC(extractClientPosition)]];
};
}, 0.5, []] call CBA_fnc_addPerFrameHandler;
deleteVehicle _logic;
closeDialog 1;
+17
View 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
View File
@@ -1 +1 @@
armatak\armatak\armatak_main armatak\armatak\addons\main
+160
View 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
View 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));
};
};
+42 -38
View File
@@ -1,89 +1,93 @@
class CfgFunctions { class CfgFunctions {
class armatak { class armatak {
class functions { 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 { class send_digital_pointer_cot {
file = "\armatak\armatak\armatak_main\functions\api\fn_send_digital_pointer_cot.sqf"; file = "\armatak\armatak\addons\main\functions\api\fn_send_digital_pointer_cot.sqf";
}; };
class send_drone_cot { class send_drone_cot {
file = "\armatak\armatak\armatak_main\functions\api\fn_send_drone_cot.sqf"; file = "\armatak\armatak\addons\main\functions\api\fn_send_drone_cot.sqf";
}; };
class send_group_cots { class send_group_cots {
file = "\armatak\armatak\armatak_main\functions\api\fn_send_group_cots.sqf"; file = "\armatak\armatak\addons\main\functions\api\fn_send_group_cots.sqf";
}; };
class send_human_cot { class send_eud_cot {
file = "\armatak\armatak\armatak_main\functions\api\fn_send_human_cot.sqf"; file = "\armatak\armatak\addons\main\functions\api\fn_send_eud_cot.sqf";
}; };
class send_marker_cot { class send_marker_cot {
file = "\armatak\armatak\armatak_main\functions\api\fn_send_marker_cot.sqf"; file = "\armatak\armatak\addons\main\functions\api\fn_send_marker_cot.sqf";
}; };
class send_message_cot { class stop_tcp_socket {
file = "\armatak\armatak\armatak_main\functions\api\fn_send_marker_cot.sqf"; file = "\armatak\armatak\addons\main\functions\api\fn_stop_tcp_socket.sqf";
};
class extract_callsign {
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_callsign.sqf";
}; };
class extract_group_color { class extract_group_color {
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_group_color.sqf"; file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_group_color.sqf";
}; };
class extract_group_role { class extract_group_role {
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_group_role.sqf"; file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_group_role.sqf";
};
class extract_marker_callsign {
file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_marker_callsign.sqf";
}; };
class extract_role { class extract_role {
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_role.sqf"; file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_role.sqf";
}; };
class extract_position { class extract_unit_callsign {
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_position.sqf"; file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_unit_callsign.sqf";
}; };
class extract_uuid { class extract_uuid {
file = "\armatak\armatak\armatak_main\functions\extract_data\fn_extract_uuid.sqf"; file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_uuid.sqf";
}; };
class convert_location { class shorten_name {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_location.sqf"; file = "\armatak\armatak\addons\main\functions\extract_data\fn_shorten_name.sqf";
}; };
class convert_to_altis { class convert_to_altis {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_altis.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_altis.sqf";
}; };
class convert_to_bukovina { class convert_to_bukovina {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_bukovina.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_bukovina.sqf";
}; };
class convert_to_bystrika { class convert_to_bystrika {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_bystrika.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_bystrika.sqf";
}; };
class convert_to_chernarus { class convert_to_chernarus {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_chernarus.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_chernarus.sqf";
}; };
class convert_to_cucui { class convert_to_cucui {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_cucui.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_cucui.sqf";
};
class convert_to_kunduz {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_kunduz.sqf";
};
class convert_to_kunduz_valley {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_kunduz_valley.sqf";
}; };
class convert_to_livonia { class convert_to_livonia {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_livonia.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_livonia.sqf";
}; };
class convert_to_malden { class convert_to_malden {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_malden.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_malden.sqf";
}; };
class convert_to_southen_sahrani { class convert_to_southen_sahrani {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_southen_sahrani.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_southen_sahrani.sqf";
}; };
class convert_to_stratis { class convert_to_stratis {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_stratis.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_stratis.sqf";
}; };
class convert_to_takistan_montains { class convert_to_takistan_montains {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_takistan_montains.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_takistan_montains.sqf";
}; };
class convert_to_tanoa { class convert_to_tanoa {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_tanoa.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_tanoa.sqf";
}; };
class convert_to_united_sahrani { class convert_to_united_sahrani {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_united_sahrani.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_united_sahrani.sqf";
}; };
class convert_to_vr { class convert_to_vr {
file = "\armatak\armatak\armatak_main\functions\map\fn_convert_to_vr.sqf"; file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_vr.sqf";
};
class convert_to_zagor_zagorsk_reserved_forest {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_zagor_zagorsk_reserved_forest.sqf";
}; };
}; };
}; };
-96
View File
@@ -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
View File
@@ -0,0 +1,2 @@
PREP(logMessage);
PREP(notify);
+56
View File
@@ -0,0 +1,56 @@
#include "script_component.hpp"
addMissionEventHandler ["ExtensionCallback", {
params ["_name", "_function", "_data"];
switch (_name) do {
case "UDP SOCKET": {
[_function, "success", _name] call FUNC(notify);
switch (_function) do {
case "EUD Connected": {
SETVAR(player,EGVAR(client,eudConnected),true);
};
case "EUD Disconnected": {
SETVAR(player,EGVAR(client,eudConnected),false);
};
default {};
};
};
case "UDP SOCKET WARNING": {
[_function, "warning", "UDP Socket"] call FUNC(notify);
};
case "UDP SOCKET ERROR": {
[_function, "error", _name] call FUNC(notify);
if (_function == "UDP Socket is not running") then {
SETVAR(player,EGVAR(client,eudConnected),false);
};
if (_function == "failed to bind UDP socket") then {
SETVAR(player,EGVAR(client,eudConnected),false);
};
};
case "TCP SOCKET": {
[_function, "success", _name] call FUNC(notify);
};
case "TCP SOCKET ERROR": {
[_function, "error", _name] call FUNC(notify);
};
case "VIDEO": {
[_function, "success", _name] call FUNC(notify);
};
case "VIDEO ERROR": {
[_function, "error", _name] call FUNC(notify);
SETVAR(player,EGVAR(video,isStreaming),false);
};
default {
"armatak" callExtension ["log",["error", (_name + _function + _data)]];
};
};
}];
GVAR(group_colors) = ["White", "Yellow", "Orange", "Magenta", "Red", "Maroon", "Purple", "DarkBlue", "Blue", "Cyan", "Teal", "Green", "DarkGreen", "Brown"];
missionNamespace setVariable [QGVAR(group_colors), GVAR(group_colors)];
+9
View File
@@ -0,0 +1,9 @@
#include "script_component.hpp"
ADDON = false;
PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;
ADDON = true;
+3
View File
@@ -0,0 +1,3 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"
+35 -15
View File
@@ -1,26 +1,46 @@
#include "script_component.hpp"
class CfgPatches { class CfgPatches {
class armatak_main { class ADDON {
units[] = { name = COMPONENT_NAME;
"armatak_module_core", units[] = {};
"armatak_module_callsign" weapons[] = {};
}; requiredAddons[] = {
weapons[] = {""};
author = "Valmo";
url = "https://github.com/valmojr/armatak";
requiredAddons[] =
{
"cba_main", "cba_main",
"ace_main" "ace_main"
}; };
requiredVersion = 2.06; requiredVersion = REQUIRED_VERSION;
author = PROJECT_AUTHOR;
url = "https://github.com/valmojr/armatak";
}; };
}; };
class Extended_PostInit_EventHandlers { class CfgMods {
class armatak_main { class PREFIX {
init = "call compileScript ['\armatak\armatak\armatak_main\initPlayerLocal.sqf']"; name = "Arma Team Awareness Kit";
author = PROJECT_AUTHOR;
logo = "logo_ca.paa";
logoOver = "logo_hover_ca.paa";
tooltip = "ARMATAK";
tooltipOwned = "ARMATAK";
picture = "picture.paa";
actionName = "GitHub";
action = "https://github.com/valmojr/armatak";
overview = "ARMATAK Addons allows Arma 3 sessions to be parsed to TAK Clients";
hideName = 0;
hidePicture = 0;
dlcColor[] = { 0.23, 0.39, 0.30, 1 };
logoSmall = "logo_small_ca.paa";
}; };
}; };
class CfgFactionClasses {
class NO_CATEGORY;
class GVAR(moduleCategory): NO_CATEGORY {
displayName = "Team Awareness Kit";
};
};
#include "CfgEventHandlers.hpp"
#include "CfgFunctions.hpp" #include "CfgFunctions.hpp"
#include "CfgVehicles.hpp" #include "Cfg3den.hpp"
@@ -3,12 +3,12 @@ params ["_unit"];
_digitalPointer = laserTarget _unit; _digitalPointer = laserTarget _unit;
if (!isNull _digitalPointer) then { if (!isNull _digitalPointer) then {
_digitalPointerPosition = _digitalPointer call armatak_fnc_extract_position; _digitalPointerPosition = _digitalPointer call armatak_client_fnc_extractClientPosition;
_link_uid = [_unit] call armatak_fnc_extract_uuid; _link_uid = [_unit] call armatak_fnc_extract_uuid;
_contact_callsign = ([player] call armatak_fnc_extract_callsign) + ".DP1"; _contact_callsign = ([player] call armatak_fnc_extract_unit_callsign) + ".DP1";
_dpCot = [_link_uid, _contact_callsign, _digitalPointerPosition select 0, _digitalPointerPosition select 1, _digitalPointerPosition select 2]; _dpCot = [_link_uid, _contact_callsign, _digitalPointerPosition select 1, _digitalPointerPosition select 2, _digitalPointerPosition select 3];
"armatak" callExtension ["cot_router:send_digital_pointer_cot", [_dpCot]]; "armatak" callExtension ["tcp_socket:send_digital_pointer_cot", [_dpCot]];
}; };
@@ -1,11 +1,11 @@
// function name: armatak_fnc_extract_drone // function name: armatak_fnc_send_drone_cot
// function author: Valmo // function author: Valmo
// function description: Gets the drone information for the CoT Router // function description: Gets the drone information for the CoT Router
params["_drone"]; params["_drone"];
private _atak_role = "a-f-A"; private _atak_role = "a-f-A";
private _atak_callsign = [_unit] call armatak_fnc_extract_callsign; private _atak_callsign = [_drone] call armatak_fnc_extract_marker_callsign;
switch (side _drone) do { switch (side _drone) do {
case "WEST": { case "WEST": {
@@ -25,4 +25,10 @@ switch (side _drone) do {
}; };
}; };
_pre_defined_role = _drone getVariable "_atak_group_role";
if (!isNil "_pre_defined_role") then {
_callsign = _pre_defined_role;
};
_cot = [_drone, _atak_role, _atak_callsign] call armatak_fnc_send_marker_cot; _cot = [_drone, _atak_role, _atak_callsign] call armatak_fnc_send_marker_cot;
@@ -0,0 +1,15 @@
// function name: armatak_fnc_send_eud_cot
// function author: Valmo
// function description: Gets the information necessary for generating the EUD Cursor Over Time
params ["_unit"];
_unit_position = _unit call armatak_client_fnc_extractClientPosition;
_uuid = _unit call armatak_fnc_extract_uuid;
_type = _unit call armatak_fnc_extract_role;
_callsign = _unit call armatak_fnc_extract_marker_callsign;
_marker_cot = [_uuid, _type, _unit_position select 1, _unit_position select 2, _unit_position select 3, _callsign, _unit_position select 5, _unit_position select 6];
"armatak" callExtension ["tcp_socket:send_marker_cot", [_marker_cot]];
@@ -0,0 +1,12 @@
// function name: armatak_fnc_send_eud_cot
// 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 1, _position select 2, _position select 3, _callsign, _group_name, _group_role, _position select 5, _position select 6];
"armatak" callExtension ["tcp_socket:send_eud_cot", [_eud_cot]];
@@ -5,9 +5,9 @@
params["_group"]; params["_group"];
{ {
_callsign = [_x] call armatak_fnc_extract_callsign; _callsign = [_x] call armatak_fnc_extract_unit_callsign;
_group_name = [_group] call armatak_fnc_extract_group_color; _group_name = [_group] call armatak_fnc_extract_group_color;
_group_role = [_x] call armatak_fnc_extract_group_role; _group_role = [_x] call armatak_fnc_extract_group_role;
[_x, _callsign, _group_name, _group_role] call armatak_fnc_send_human_cot; [_x, _callsign, _group_name, _group_role] call armatak_fnc_send_eud_cot;
} forEach (units _group); } forEach (units _group);
@@ -1,12 +0,0 @@
// function name: armatak_fnc_extract_human_cot_info
// function author: Valmo
// function description: Gets the information necessary for generating the Human Cursor Over Time
params ["_unit", "_callsign", "_group_name", "_group_role"];
_position = _unit call armatak_fnc_extract_position;
_uuid = _unit call armatak_fnc_extract_uuid;
_human_cot = [_uuid, _position select 0, _position select 1, _position select 2, _callsign, _group_name, _group_role, _position select 3, speed player / 3.6];
"armatak" callExtension ["cot_router:send_human_cot", [_human_cot]];
@@ -4,9 +4,10 @@
params ["_unit", "_type", "_callsign"]; params ["_unit", "_type", "_callsign"];
_unit_position = _unit call armatak_fnc_extract_position; _unit_position = _unit call armatak_client_fnc_extractClientPosition;
_uuid = _unit call armatak_fnc_extract_uuid; _uuid = _unit call armatak_fnc_extract_uuid;
_marker_cot = [_uuid, _type, _unit_position select 0, _unit_position select 1, _unit_position select 2, _callsign, _unit_position select 3, speed _unit / 3.6]; _marker_cot = [_uuid, _type, _unit_position select 1, _unit_position select 2, _unit_position select 3, _callsign, _unit_position select 5, _unit_position select 6];
"armatak" callExtension ["cot_router:send_marker_cot", [_marker_cot]]; "armatak" callExtension ["tcp_socket:send_marker_cot", [_marker_cot]];
@@ -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;
};
@@ -1,43 +0,0 @@
// function name: armatak_fnc_extract_callsign
// function author: Valmo
// function description: Gets the unit name or classname to be used as TAK callsign
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);
};
};
if (unitIsUAV _unit) then {
_callsign = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "displayName");
if (isUAVConnected _unit) then {
_callsign = (_callsign) + "[ON]";
} else {
_callsign = (_callsign) + "[OFF]";
}
};
_pre_defined_callsign = _unit getVariable "_atak_callsign";
if (!isNil "_pre_defined_callsign") then {
_callsign = _pre_defined_callsign;
};
_callsign
@@ -1,9 +1,11 @@
#include "..\..\script_component.hpp"
params["_group"]; params["_group"];
_group_name = _group getVariable "_atak_group_name"; _group_name = _group getVariable QGVAR(group_name);
if (isNil "_group_name") then { if (isNil "_group_name") then {
_group_colors = missionNamespace getVariable "_group_colors"; _group_colors = missionNamespace getVariable QGVAR(group_colors);
_group_name = selectRandom _group_colors; _group_name = selectRandom _group_colors;
if (count _group_colors > 0) then { if (count _group_colors > 0) then {
@@ -14,11 +16,11 @@ if (isNil "_group_name") then {
_group_colors deleteAt _randomIndex; _group_colors deleteAt _randomIndex;
_group_name = _selectedColor; _group_name = _selectedColor;
_group setVariable ["_atak_group_name", _group_name]; _group setVariable [QGVAR(group_name), _group_name];
missionNamespace setVariable ["_group_colors", _group_colors] missionNamespace setVariable [QGVAR(group_colors), _group_colors]
} else { } else {
_group_name = "Red"; _group_name = "Red";
_group setVariable ["_atak_group_name", _group_name]; _group setVariable [QGVAR(group_name), _group_name];
}; };
}; };
@@ -1,9 +1,10 @@
params["_unit"]; params["_unit"];
_group = group _unit;
_group_roles = ["Team Member", "Team Lead", "HQ", "Sniper", "Medic", "Forward Observer", "RTO", "K9"]; _group_roles = ["Team Member", "Team Lead", "HQ", "Sniper", "Medic", "Forward Observer", "RTO", "K9"];
_group_role = "Team Member"; _group_role = "Team Member";
if (["SpecialOperative", (configFile >> "CfgVehicles" >> typeOf _unit >> "role") call BIS_fnc_getCfgData, false] call BIS_fnc_inString) then { if (["SpecialOperative", (configOf _unit >> "role") call BIS_fnc_getCfgData, false] call BIS_fnc_inString) then {
_group_role = _group_roles select 5; _group_role = _group_roles select 5;
}; };
@@ -19,7 +20,7 @@ if (((backpack _unit) isKindOf "TFAR_Bag_Base") or (["radio", typeOf _unit, fals
_group_role = _group_roles select 6; _group_role = _group_roles select 6;
}; };
if ((["sniper", typeOf _unit, false] call BIS_fnc_inString) or (["marksman", (configFile >> "CfgVehicles" >> typeOf _unit >> "role") call BIS_fnc_getCfgData, false] call BIS_fnc_inString) or (["sharpshooter", typeOf _unit, false] call BIS_fnc_inString)) then { if ((["sniper", typeOf _unit, false] call BIS_fnc_inString) or (["marksman", (configOf _unit >> "role") call BIS_fnc_getCfgData, false] call BIS_fnc_inString) or (["sharpshooter", typeOf _unit, false] call BIS_fnc_inString)) then {
_group_role = _group_roles select 3; _group_role = _group_roles select 3;
}; };
@@ -34,7 +35,7 @@ if (["officer", typeOf _unit, false] call BIS_fnc_inString) then {
_pre_defined_role = _unit getVariable "_atak_group_role"; _pre_defined_role = _unit getVariable "_atak_group_role";
if (!isNil "_pre_defined_role") then { if (!isNil "_pre_defined_role") then {
_callsign = _pre_defined_callsign; _callsign = _pre_defined_role;
}; };
_group_role _group_role
@@ -0,0 +1,33 @@
// function name: armatak_fnc_extract_marker_callsign
// function author: Valmo
// function description: Gets the unit name or classname to be used as TAK callsign in a Marker
params["_unit"];
private _callsign = "";
if ((([_unit] call BIS_fnc_objectType) select 0) == "Vehicle") then {
_callsign = getText (configOf _unit >> "displayName");
if (!isNull driver _unit) then {
_callsign = getText (configOf _unit >> "displayName") + " | " + ([name (driver _unit)] call armatak_fnc_shorten_name);
};
};
if (unitIsUAV _unit) then {
_callsign = getText (configOf _unit >> "displayName");
if (isUAVConnected _unit) then {
_callsign = (_callsign) + "[ON]";
} else {
_callsign = (_callsign) + "[OFF]";
}
};
armatak_attribute_marker_callsign = _unit getVariable "armatak_attribute_marker_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; _role = "a-" + _affiliation + "-" + _type;
armatak_attribute_marker_type = _unit getVariable "armatak_attribute_marker_type";
if (!isNil "armatak_attribute_marker_type" or armatak_attribute_marker_type != '') then {
_role = armatak_attribute_marker_type;
};
_role _role
@@ -0,0 +1,25 @@
// function name: armatak_fnc_extract_unit_callsign
// function author: Valmo
// function description: Gets the unit name or classname to be used as TAK callsign from a unit
params["_unit"];
private _callsign = "";
if (roleDescription _unit != "") then {
_callsign = ([name _unit] call armatak_fnc_shorten_name) + " | " + roleDescription _unit;
} else {
_callsign = name _unit;
if (_callsign == "Error: No unit") then {
_callsign = getText (configOf _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
@@ -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]
};
};
-63
View File
@@ -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;
-3
View File
@@ -1,3 +0,0 @@
params[_type, _message];
"armatak" callExtension ["log", [_type, _message]]
+3
View File
@@ -0,0 +1,3 @@
params["_type", "_message"];
"armatak" callExtension ["log", [_type, _message]]
+21
View 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];
};
};
@@ -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]
@@ -0,0 +1,30 @@
params ["_longitudeInGame", "_latitudeInGame", "_altitude"];
private _mapWidth = 10240;
private _mapHeight = 10240;
// SW corner (used as origin)
private _SW_lat = 36.547662;
private _SW_lon = 68.802314;
// SE corner
private _SE_lat = 36.547662;
private _SE_lon = 68.916671;
// NW corner
private _NW_lat = 36.639935;
private _NW_lon = 68.802314;
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,19 +1,19 @@
params ["_longitudeInGame", "_latitudeInGame", "_altitude"]; params ["_longitudeInGame", "_latitudeInGame", "_altitude"];
private _mapWidth = 30720; private _mapWidth = 8192;
private _mapHeight = 30720; private _mapHeight = 8192;
// SW corner (used as origin) // SW corner (used as origin)
private _SW_lat = 39.456910; private _SW_lat = 39.458019;
private _SW_lon = 24.940792; private _SW_lon = 24.939314;
// SE corner // SE corner
private _SE_lat = 39.459151; private _SE_lat = 39.458019;
private _SE_lon = 25.083440; private _SE_lon = 25.081992;
// NW corner // NW corner
private _NW_lat = 39.567714; private _NW_lat = 39.568847;
private _NW_lon = 24.937866; private _NW_lon = 24.939314;
private _edgeSE_lat = _SE_lat - _SW_lat; private _edgeSE_lat = _SE_lat - _SW_lat;
private _edgeSE_lon = _SE_lon - _SW_lon; private _edgeSE_lon = _SE_lon - _SW_lon;
@@ -1,19 +1,19 @@
params ["_longitudeInGame", "_latitudeInGame", "_altitude"]; params ["_longitudeInGame", "_latitudeInGame", "_altitude"];
private _mapWidth = 30720; private _mapWidth = 15360;
private _mapHeight = 30720; private _mapHeight = 15360;
// SW corner (used as origin) // SW corner (used as origin)
private _SW_lat = -19.086825; private _SW_lat = -19.086803;
private _SW_lon = 176.812772; private _SW_lon = 176.812619;
// SE corner // SE corner
private _SE_lat = -19.086825; private _SE_lat = -19.086803;
private _SE_lon = 178.687920; private _SE_lon = 178.704583;
// NW corner // NW corner
private _NW_lat = -17.196898; private _NW_lat = -17.196900;
private _NW_lon = 176.812622; private _NW_lon = 176.812619;
private _edgeSE_lat = _SE_lat - _SW_lat; private _edgeSE_lat = _SE_lat - _SW_lat;
private _edgeSE_lon = _SE_lon - _SW_lon; private _edgeSE_lon = _SE_lon - _SW_lon;
@@ -0,0 +1,23 @@
params["_latitude", "_longitude", "_altitude"];
_playerPosition = [_latitude, _longitude, _altitude];
_playerLatitude = _playerPosition select 0;
_playerLongitude = _playerPosition select 1;
_playerMaxLongitude = 20480;
_playerMaxLatitude = 20480;
_MapMaxLongitude = 48.351216;
_MapMinLongitude = 48.097496;
_MapMaxLatitude = 38.345389;
_MapMinLatitude = 37.956754;
_LongitudeDifference = _MapMaxLongitude - _MapMinLongitude;
_LatitudeDifference = _MapMaxLatitude - _MapMinLatitude;
_RealLongitude = (_playerLongitude / _playerMaxLongitude) * _LongitudeDifference + _MapMinLongitude;
_RealLatitude = (_playerLatitude / _playerMaxLatitude) * _LatitudeDifference + _MapMinLatitude;
[_RealLongitude, _RealLatitude, _playerPosition select 2]
-18
View File
@@ -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
View 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
View 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
+3 -3
View File
@@ -1,4 +1,4 @@
#define build 0 #define build 0
#define major 0 #define major 1
#define minor 7 #define minor 1
#define patch 5 #define patch 0
+1
View File
@@ -0,0 +1 @@
armatak\armatak\addons\server
+11
View 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
View 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
View File
@@ -0,0 +1,4 @@
PREP(3denCoreModuleConfig);
PREP(routerEntityAdd);
PREP(routerEntityRemove);
PREP(ZeusCoreModuleConfig);
+9
View File
@@ -0,0 +1,9 @@
#include "script_component.hpp"
ADDON = false;
PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;
ADDON = true;
+3
View File
@@ -0,0 +1,3 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"
+25
View 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"
+141
View File
@@ -0,0 +1,141 @@
class RscText;
class RscBackground;
class RscButton;
class RscEdit;
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: RscBackground
{
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";
};
};
};
@@ -0,0 +1,60 @@
#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];
"armatak" callExtension ["tcp_socket:start", [_tak_server_fulladdress]];
_syncUnits = synchronizedObjects _logic;
missionNamespace setVariable ["armatak_server_syncedUnits", _syncUnits];
GVAR(syncedUnits) = missionNamespace getVariable "armatak_server_syncedUnits";
[{
GVAR(syncedUnits) = missionNamespace getVariable "armatak_server_syncedUnits";
{
_objectType = _x call BIS_fnc_objectType;
switch (true) do {
case ((_objectType select 0) == "Soldier"): {
_callsign = [_x] call armatak_fnc_extract_unit_callsign;
_group_name = [group _x] call armatak_fnc_extract_group_color;
_group_role = [_x] call armatak_fnc_extract_group_role;
[_x, _callsign, _group_name, _group_role] call armatak_fnc_send_eud_cot;
[_x] call armatak_fnc_send_digital_pointer_cot;
};
case ((_objectType select 0) == "Vehicle"): {
_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;
};
case ((_objectType select 0) == "VehicleAutonomous"): {
_atak_type = [_x] call armatak_fnc_extract_role;
_callsign = [_x] call armatak_fnc_extract_marker_callsign;
[_x, _atak_type, _callsign] call armatak_fnc_send_drone_cot;
[_x] call armatak_fnc_send_digital_pointer_cot;
};
};
} forEach GVAR(syncedUnits);
}, 1, []] call CBA_fnc_addPerFrameHandler;
};
true;
@@ -0,0 +1,63 @@
#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];
"armatak" callExtension ["tcp_socket:start", [_tak_server_fulladdress]];
_syncUnits = [];
missionNamespace setVariable ["armatak_server_syncedUnits", _syncUnits];
GVAR(syncedUnits) = missionNamespace getVariable "armatak_server_syncedUnits";
[{
GVAR(syncedUnits) = missionNamespace getVariable "armatak_server_syncedUnits";
{
_objectType = _x call BIS_fnc_objectType;
switch (true) do {
case ((_objectType select 0) == "Soldier"): {
_callsign = [_x] call armatak_fnc_extract_unit_callsign;
_group_name = [group _x] call armatak_fnc_extract_group_color;
_group_role = [_x] call armatak_fnc_extract_group_role;
[_x, _callsign, _group_name, _group_role] call armatak_fnc_send_eud_cot;
[_x] call armatak_fnc_send_digital_pointer_cot;
};
case ((_objectType select 0) == "Vehicle"): {
_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;
};
case ((_objectType select 0) == "VehicleAutonomous"): {
_atak_type = [_x] call armatak_fnc_extract_role;
_callsign = [_x] call armatak_fnc_extract_marker_callsign;
[_x, _atak_type, _callsign] call armatak_fnc_send_drone_cot;
[_x] call armatak_fnc_send_digital_pointer_cot;
};
};
} forEach GVAR(syncedUnits);
}, 1, []] call CBA_fnc_addPerFrameHandler;
deleteVehicle _logic;
closeDialog 1;
@@ -0,0 +1,44 @@
#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;
switch (false) do {
case (!isNull _unit): {
["Nothing selected", "error", "TCP Socket"] call EFUNC(main,notify);
deleteVehicle _logic;
};
default {
if (_unit in (missionNamespace getVariable ["armatak_server_syncedUnits", []])) exitWith {
["Unit already marked", "warning", "TCP Socket"] call EFUNC(main,notify);
deleteVehicle _logic;
};
GVAR(syncedUnits) = missionNamespace getVariable "armatak_server_syncedUnits";
GVAR(syncedUnits) pushBack _unit;
missionNamespace setVariable ["armatak_server_syncedUnits", GVAR(syncedUnits)];
SETVAR(_unit,GVAR(isRouting),true);
deleteVehicle _logic;
};
};
@@ -0,0 +1,42 @@
#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_server_syncedUnits", GVAR(syncedUnits)];
SETVAR(_unit,GVAR(isRouting),false);
deleteVehicle _logic;
};
};
+17
View 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
View File
@@ -0,0 +1 @@
armatak\armatak\addons\video
+11
View 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));
};
};
+73
View File
@@ -0,0 +1,73 @@
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 = QGVAR(instancePort);
displayname = QUOTE(MediaMTX Provider Port);
tooltip = QUOTE(MediaMTX Provider Port for handling video streams);
typeName = "STRING";
defaultValue = "8554";
};
class GVAR(instanceAuthUser): Edit {
property = QGVAR(instanceAuthUser);
displayname = QUOTE(MediaMTX Provider Username);
tooltip = QUOTE(MediaMTX Provider Instance Username);
typeName = "STRING";
defaultValue = "administrator";
};
class GVAR(instanceAuthPassword): Edit {
property = QGVAR(instanceAuthPassword);
displayname = QUOTE(MediaMTX Provider Password);
tooltip = QUOTE(MediaMTX Provider Instance Password);
typeName = "STRING";
defaultValue = "password";
};
};
*/
};
};
+1
View File
@@ -0,0 +1 @@
PREP(videoParser);
+9
View File
@@ -0,0 +1,9 @@
#include "script_component.hpp"
ADDON = false;
PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;
ADDON = true;
+3
View File
@@ -0,0 +1,3 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"
+23
View File
@@ -0,0 +1,23 @@
#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";
};
};
#include "CfgEventHandlers.hpp"
//#include "CfgVehicles.hpp"
@@ -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
View 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
View File
@@ -1 +0,0 @@
/build
-55
View File
@@ -1,55 +0,0 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
}
android {
namespace = "com.armatak.simtak"
compileSdk = 34
defaultConfig {
applicationId = "com.armatak.simtak"
minSdk = 29
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
viewBinding {
enable = true
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
implementation(libs.okhttp)
//Vision - Qr/BarCodeScanner
implementation(libs.play.services.vision)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}
-21
View File
@@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
@@ -1,24 +0,0 @@
package com.armatak.simtak
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.armatak.simtak", appContext.packageName)
}
}
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"
tools:ignore="ProtectedPermissions" />
</manifest>
-66
View File
@@ -1,66 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<uses-feature android:name="android.hardware.camera.autofocus"
android:required="false"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@drawable/appicon_simtak"
android:usesCleartextTraffic="true"
android:label="@string/app_name"
android:roundIcon="@drawable/appicon_simtak"
android:supportsRtl="true"
android:theme="@style/Theme.SIMTAK"
tools:targetApi="31">
<activity
android:name=".trackerLog.TrackerLogActivity"
android:screenOrientation="portrait"
android:exported="false"
tools:ignore="LockedOrientationActivity" />
<activity
android:name=".ScannerActivity"
android:screenOrientation="portrait"
android:exported="false"
tools:ignore="LockedOrientationActivity" />
<activity
android:name=".HomeActivity"
android:screenOrientation="portrait"
tools:ignore="LockedOrientationActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".LocationSimulationService"
android:exported="true"
android:foregroundServiceType="location"
android:permission="android.permission.ACCESS_MOCK_LOCATION">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</service>
</application>
</manifest>
@@ -1,182 +0,0 @@
package com.armatak.simtak
import android.Manifest
import android.app.Dialog
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.Window
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.armatak.simtak.databinding.ActivityHomeBinding
import com.armatak.simtak.trackerLog.TrackerLogActivity
class HomeActivity : AppCompatActivity() {
private lateinit var binding: ActivityHomeBinding
private var requestCamera: ActivityResultLauncher<String>? = null
private var requestPermissionLauncher: ActivityResultLauncher<String>? = null
private var requested = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(binding.root)
enableEdgeToEdge()
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
requestCamera = registerForActivityResult(ActivityResultContracts.RequestPermission()) {
if (it) {
initScan()
} else {
Toast.makeText(
this,
"Sem permissão para acessar a camera. Permita o acesso para continuar",
Toast.LENGTH_LONG
).show()
}
}
requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission(),
) { isGranted: Boolean ->
if (isGranted) {
Toast.makeText(baseContext, "Notificações Habilitadas", Toast.LENGTH_SHORT).show()
requestCamera?.launch(Manifest.permission.CAMERA)
} else {
Toast.makeText(
baseContext,
"Por favor confirme a permissão",
Toast.LENGTH_SHORT
).show()
}
}
initUI()
}
private fun validateUrl() {
val etServerAddressLayout = binding.etServerAddressLayout
val etServerAddress = binding.etServerAddress
val serverAddress = etServerAddress.text.toString()
val regexPatterns = listOf(
"^ws://\\b(?:(?:2(?:[0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9])\\.){3}(?:(?:2([0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9]))\\b:[0-9]+\$",
"^ws://([A-Za-z0-9]+(\\.[A-Za-z0-9]+)+)\$"
)
val allowed = regexPatterns.any { patterns ->
Regex(patterns).matches(serverAddress)
}
if(allowed) {
requested = false
val intent = Intent(this, TrackerLogActivity::class.java)
intent.putExtra("webSocketUrl", serverAddress)
startActivity(intent)
} else {
requested = false
etServerAddressLayout.error = "Server Address need to be a valid URL"
}
}
private fun initScan() {
startActivity(Intent(this, ScannerActivity::class.java))
}
private fun initUI() {
binding.btnScanQrCode.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.POST_NOTIFICATIONS
) ==
PackageManager.PERMISSION_GRANTED
) {
requestCamera?.launch(Manifest.permission.CAMERA)
} else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
requestNotificationByDialog()
} else {
requestPermissionLauncher?.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}
}
binding.btnConnectToServer.setOnClickListener {
val serverAddress = binding.etServerAddress.text.toString()
if (!requested && serverAddress.isNotBlank()){
validateUrl()
} else {
binding.etServerAddressLayout.error = "This Input cannot be blank"
}
}
configureFooterLinks()
}
private fun requestNotificationByDialog() {
val dialog = Dialog(this)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setContentView(R.layout.dialog_alert)
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val tvTitle: TextView = dialog.findViewById(R.id.title)
val tvMessage: TextView = dialog.findViewById(R.id.message)
val btnCancel: Button = dialog.findViewById(R.id.btnCancel)
val btnAccept: Button = dialog.findViewById(R.id.btnAccept)
btnCancel.text = getString(R.string.cancel)
btnCancel.setOnClickListener {
dialog.dismiss()
}
tvTitle.text = getString(R.string.allowNotificationsPermission)
tvMessage.text = getString(R.string.needNotificationsPermissionMessage)
btnAccept.text = getString(R.string.goToSettings)
btnAccept.setOnClickListener {
val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, this.packageName)
startActivity(intent)
dialog.dismiss()
}
dialog.show()
}
private fun configureFooterLinks() {
binding.btnGithubProject.setOnClickListener {
openLink(getString(R.string.githubProjectUrl))
}
binding.btnWiki.setOnClickListener {
openLink(getString(R.string.wikiUrl))
}
binding.btnDiscord.setOnClickListener {
openLink(getString(R.string.discordUrl))
}
binding.btnSteamProject.setOnClickListener {
openLink(getString(R.string.steamUrl))
}
}
private fun openLink(url: String) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(intent)
}
}
@@ -1,237 +0,0 @@
package com.armatak.simtak
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.location.Location
import android.location.LocationManager
import android.location.provider.ProviderProperties
import android.os.Binder
import android.os.Build
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.os.SystemClock
import android.util.Log
import com.armatak.simtak.core.Util.createNotificationChannel
import com.armatak.simtak.core.Util.getActualTime
import com.armatak.simtak.core.Util.getMockLocationStoppedNotification
import com.armatak.simtak.core.Util.getNeedReconnectNotification
import com.armatak.simtak.core.Util.getRunningNotification
import com.armatak.simtak.core.Util.getServiceDestroyedNotification
import com.armatak.simtak.core.Util.getStartedServiceNotification
import com.armatak.simtak.trackerLog.data.models.ConnectionStatus
import com.armatak.simtak.trackerLog.data.models.LogModel
import com.armatak.simtak.trackerLog.data.models.LogTypes
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.json.JSONObject
private const val TAG = "LocationSimulationService"
class LocationSimulationService : Service() {
private val binder = LocationMockBinder()
private lateinit var webSocketClient: WebSocketClient
private var logTrackerMutableList = mutableListOf<LogModel>()
private var lastLineId = 0
private var connectionAttemps = 0
private val _connectionStatus = MutableStateFlow<ConnectionStatus>(ConnectionStatus.InitialValue)
private val connectionStatus : StateFlow<ConnectionStatus> = _connectionStatus
private val _logTracker = MutableStateFlow(emptyList<LogModel>())
private val logTracker : StateFlow<List<LogModel>> = _logTracker
init {
Log.d(TAG, "$TAG, initialized")
}
private val socketListener = object : WebSocketClient.SocketListener {
override fun onMessage(message: String) {
try {
if (message[0] == '{') {
val jsonObject = JSONObject(message)
val latitude = jsonObject.getDouble("latitude")
val longitude = jsonObject.getDouble("longitude")
val bearing = jsonObject.getDouble("bearing")
simulateLocation(latitude, longitude, bearing)
addEntryToLog(message, LogTypes.Normal)
} else {
Log.e(TAG, "Non an JsonObject, text: $message")
addEntryToLog("Non an JsonObject, text: $message", LogTypes.Warning)
}
} catch (e: Exception) {
Log.e(TAG, e.localizedMessage, e)
addEntryToLog(e.localizedMessage, LogTypes.Error)
}
}
}
fun addEntryToLog(message: String?, type: LogTypes) {
lastLineId += 1
logTrackerMutableList.add(
LogModel(
lastLineId,
getActualTime(),
message?:"null",
type
)
)
val newList = logTrackerMutableList.toList()
_logTracker.value = newList
}
fun getLog(): StateFlow<List<LogModel>> {
return logTracker
}
fun getConnectionStatus(): StateFlow<ConnectionStatus> {
return connectionStatus
}
fun connectToServer(url: String){
CoroutineScope(Dispatchers.IO).launch {
try {
connectionAttemps ++
webSocketClient = WebSocketClient.getInstance()
addEntryToLog("Server Address: $url", LogTypes.NetworkOperation)
webSocketClient.setSocketUrl(url)
webSocketClient.setListener(socketListener)
webSocketClient.connect()
_connectionStatus.value = ConnectionStatus.Connected
addEntryToLog("Connection Server Success", LogTypes.NetworkOperation)
} catch (e: Exception) {
Log.e(TAG, e.localizedMessage, e)
when (e.localizedMessage){
"Expected URL scheme 'http' or 'https' but no scheme was found for test u..." -> {
addEntryToLog("Expected ws:// or wss:// scheme, this is only for debug", LogTypes.Warning)
_connectionStatus.value = ConnectionStatus.Disconnected
}
else -> {
if (connectionAttemps < 6){
addEntryToLog("Attemp: $connectionAttemps \nError:${e.localizedMessage}", LogTypes.Warning)
_connectionStatus.value = ConnectionStatus.OnReconnect
Handler(Looper.getMainLooper()).postDelayed({
connectToServer(url)
}, 1500)
} else {
addEntryToLog("Exceed Connection Attemps", LogTypes.Error)
connectionAttemps = -1
_connectionStatus.value = ConnectionStatus.Awaiting
}
}
}
}
}
}
override fun onBind(intent: Intent): IBinder {
return binder
}
private fun simulateLocation(latitude: Double, longitude: Double, bearing: Double) {
val locationManager = baseContext.getSystemService(LOCATION_SERVICE) as LocationManager
// Create a Location Object
val location = Location(LocationManager.GPS_PROVIDER)
location.latitude = latitude
location.longitude = longitude
location.accuracy = 3f
location.altitude = 0.0
location.time = System.currentTimeMillis()
location.bearing = bearing.toFloat()
location.setBearingAccuracyDegrees(0.1F)
location.setVerticalAccuracyMeters(0.1F)
location.setSpeedAccuracyMetersPerSecond(0.01F)
location.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()
var powerUsage = 3
var accuracy = 5
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
powerUsage = ProviderProperties.POWER_USAGE_LOW
accuracy = ProviderProperties.ACCURACY_COARSE
}
//Create Test Provider
locationManager.addTestProvider(
LocationManager.GPS_PROVIDER,
false,
false,
false,
false,
false,
true,
true,
powerUsage,
accuracy
)
// Enable Mock Provider
locationManager.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true)
// Mock Location on System
locationManager.setTestProviderLocation(LocationManager.GPS_PROVIDER, location)
}
fun stopByActivity() {
webSocketClient.disconnect()
_connectionStatus.value = ConnectionStatus.Disconnected
addEntryToLog("Connection Stopped", LogTypes.NetworkOperation)
val locationManager = baseContext.getSystemService(LOCATION_SERVICE) as LocationManager
locationManager.removeTestProvider(LocationManager.GPS_PROVIDER)
addEntryToLog("MockLocation Stopped", LogTypes.Warning)
this.stopSelf()
}
override fun onCreate() {
super.onCreate()
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
createNotificationChannel(manager)
CoroutineScope(Dispatchers.Default).launch{
notifyStatusByPushNotification()
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = getStartedServiceNotification(this)
startForeground(5142, notification)
return START_STICKY
}
private suspend fun notifyStatusByPushNotification(){
getConnectionStatus().collectLatest { status ->
when(status){
ConnectionStatus.Awaiting -> {
val notification = getNeedReconnectNotification(this)
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
manager.notify(5142, notification)
}
ConnectionStatus.Connected -> {
val notification = getRunningNotification(this)
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
manager.notify(5142, notification)
}
ConnectionStatus.Disconnected -> {
val notification = getMockLocationStoppedNotification(this)
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
manager.notify(5142, notification)
}
else -> {}
}
}
}
override fun onDestroy() {
super.onDestroy()
val notification = getServiceDestroyedNotification(this)
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
manager.notify(5142, notification)
Log.e(TAG, "Service destroyed")
}
inner class LocationMockBinder: Binder(){
fun getService() = this@LocationSimulationService
}
}
@@ -1,114 +0,0 @@
package com.armatak.simtak
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.SurfaceHolder
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.armatak.simtak.databinding.ActivityScannerBinding
import com.armatak.simtak.trackerLog.TrackerLogActivity
import com.google.android.gms.vision.CameraSource
import com.google.android.gms.vision.Detector
import com.google.android.gms.vision.barcode.Barcode
import com.google.android.gms.vision.barcode.BarcodeDetector
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.IOException
class ScannerActivity : AppCompatActivity() {
private lateinit var binding: ActivityScannerBinding
private var tentativa = false
private lateinit var barcodeDetector: BarcodeDetector
private lateinit var cameraSource: CameraSource
var intentData = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityScannerBinding.inflate(layoutInflater)
setContentView(binding.root)
initScanBarcode()
}
private fun initScanBarcode() {
barcodeDetector = BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.QR_CODE)
.build()
cameraSource = CameraSource.Builder(this, barcodeDetector)
.setRequestedPreviewSize(1080, 1080)
.setAutoFocusEnabled(true)
.setFacing(CameraSource.CAMERA_FACING_BACK)
.build()
binding.surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
@SuppressLint("MissingPermission")
override fun surfaceCreated(holder: SurfaceHolder) {
try {
cameraSource.start(binding.surfaceView.holder)
} catch (e: IOException) {
e.printStackTrace()
}
}
override fun surfaceChanged(
holder: SurfaceHolder,
format: Int,
width: Int,
height: Int
) {
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
cameraSource.stop()
}
})
barcodeDetector.setProcessor(object : Detector.Processor<Barcode> {
override fun release() {
Toast.makeText(applicationContext, "Scanner was stopped", Toast.LENGTH_SHORT).show()
}
override fun receiveDetections(detections: Detector.Detections<Barcode>) {
val barcodes = detections.detectedItems
if (barcodes.size() != 0) {
Thread.sleep(300)
intentData = barcodes.valueAt(0).displayValue
if (!tentativa) {
initTrackerActivity(intentData)
tentativa = true
}
}
}
})
}
private fun initTrackerActivity(url: String?) {
lifecycleScope.launch(Dispatchers.IO) {
if (url != null) {
val intent = Intent(this@ScannerActivity, TrackerLogActivity::class.java)
intent.putExtra("webSocketUrl", url)
startActivity(intent)
Handler(Looper.getMainLooper()).postDelayed(
{ tentativa = false },
2000
)
} else {
withContext(Dispatchers.Main) {
Toast.makeText(baseContext, "Try Again, Scan Error", Toast.LENGTH_SHORT).show()
}
Handler(Looper.getMainLooper()).postDelayed(
{ tentativa = false },
1500
)
}
}
}
}
@@ -1,121 +0,0 @@
package com.armatak.simtak
import android.util.Log
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.WebSocketListener
class WebSocketClient {
private lateinit var webSocket: okhttp3.WebSocket
private var socketListener: SocketListener? = null
private var socketUrl = ""
private var shouldReconnect = true
private var client: OkHttpClient? = null
companion object {
private lateinit var instance: WebSocketClient
@JvmStatic
@Synchronized
//This function gives singleton instance of WebSocket.
fun getInstance(): WebSocketClient {
synchronized(WebSocketClient::class) {
if (!::instance.isInitialized) {
instance = WebSocketClient()
}
}
return instance
}
}
fun setListener(listener: SocketListener) {
this.socketListener = listener
}
fun setSocketUrl(socketUrl: String) {
this.socketUrl = socketUrl
}
private fun initWebSocket() {
Log.e("socketCheck", "initWebSocket() socketurl = $socketUrl")
client = OkHttpClient()
val request = Request.Builder().url(url = socketUrl).build()
webSocket = client!!.newWebSocket(request, webSocketListener)
//this must me done else memory leak will be caused
client!!.dispatcher.executorService.shutdown()
}
fun connect() {
Log.e("socketCheck", "connect()")
shouldReconnect = true
initWebSocket()
}
fun reconnect() {
Log.e("socketCheck", "reconnect()")
initWebSocket()
}
//send
@Suppress("unused")
fun sendMessage(message: String) {
Log.e("socketCheck", "sendMessage($message)")
if (::webSocket.isInitialized) webSocket.send(message)
}
//We can close socket by two way:
//1. websocket.webSocket.close(1000, "Dont need connection")
//This attempts to initiate a graceful shutdown of this web socket.
//Any already-enqueued messages will be transmitted before the close message is sent but
//subsequent calls to send will return false and their messages will not be enqueued.
//2. websocket.cancel()
//This immediately and violently release resources held by this web socket,
//discarding any enqueued messages.
//Both does nothing if the web socket has already been closed or canceled.
fun disconnect() {
if (::webSocket.isInitialized) webSocket.close(1000, "Do not need connection anymore.")
shouldReconnect = false
}
interface SocketListener {
fun onMessage(message: String)
}
private val webSocketListener = object : WebSocketListener() {
//called when connection succeeded
//we are sending a message just after the socket is opened
override fun onOpen(webSocket: okhttp3.WebSocket, response: Response) {
Log.e("socketCheck", "onOpen()")
}
//called when text message received
override fun onMessage(webSocket: okhttp3.WebSocket, text: String) {
socketListener?.onMessage(text)
}
//called when binary message received
override fun onClosing(webSocket: okhttp3.WebSocket, code: Int, reason: String) {
Log.e("socketCheck", "onClosing()")
}
override fun onClosed(webSocket: okhttp3.WebSocket, code: Int, reason: String) {
//called when no more messages and the connection should be released
Log.e("socketCheck", "onClosed()")
if (shouldReconnect) reconnect()
}
override fun onFailure(
webSocket: okhttp3.WebSocket, t: Throwable, response: Response?
) {
Log.e("socketCheck", "onFailure()")
if (shouldReconnect) reconnect()
}
}
}
@@ -1,65 +0,0 @@
package com.armatak.simtak.core
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import androidx.core.app.NotificationCompat
import com.armatak.simtak.R
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
object Util {
const val CHANNEL_ID = "websocketChannel"
fun getActualTime(): String {
val now = LocalDateTime.now()
val formatter = DateTimeFormatter.ofPattern("HH:mm:ss:SSS")
return now.format(formatter)
}
fun createNotificationChannel(manager: NotificationManager) {
val websocketChannel = NotificationChannel(
CHANNEL_ID, "websocketChannelName",
NotificationManager.IMPORTANCE_HIGH
)
websocketChannel.description = "websocketChannelDescription"
websocketChannel.enableVibration(true)
manager.createNotificationChannel(websocketChannel)
}
fun getStartedServiceNotification(context: Context): Notification {
return NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("Service Started")
.setContentText("Service is ready to Start Tracking")
.setSmallIcon(R.drawable.appicon_simtak)
.build()
}
fun getRunningNotification(context: Context): Notification {
return NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("Mocking Location")
.setContentText("Service is running")
.setSmallIcon(R.drawable.appicon_simtak)
.build()
}
fun getNeedReconnectNotification(context: Context): Notification{
return NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("Need restart server connection")
.setContentText("Connection attempts failed. Check your network/server and try again")
.setSmallIcon(R.drawable.appicon_simtak)
.build()
}
fun getMockLocationStoppedNotification(context: Context): Notification{
return NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("Mock Location Stopped")
.setContentText("Disconnect from server")
.setSmallIcon(R.drawable.appicon_simtak)
.build()
}
fun getServiceDestroyedNotification(context: Context): Notification{
return NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle("Service Destroyed")
.setSmallIcon(R.drawable.appicon_simtak)
.build()
}
}
@@ -1,277 +0,0 @@
package com.armatak.simtak.trackerLog
import android.Manifest
import android.app.Dialog
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.view.Window
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.armatak.simtak.LocationSimulationService
import com.armatak.simtak.R
import com.armatak.simtak.databinding.ActivityTrackerLogBinding
import com.armatak.simtak.trackerLog.data.adapters.AdapterLogTracker
import com.armatak.simtak.trackerLog.data.models.ConnectionStatus
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
class TrackerLogActivity : AppCompatActivity() {
private var connectedToServer: Boolean = false
private lateinit var binding: ActivityTrackerLogBinding
private var url: String = ""
private lateinit var locationPermissionRequest : ActivityResultLauncher<Array<String>>
private var serviceStarted = false
private var rvAdapter = AdapterLogTracker()
private var lastThreeElementsAreVisible = false
private lateinit var mService: LocationSimulationService
private var mBound = false
private val mConnection = object : ServiceConnection{
override fun onServiceConnected(className: ComponentName?, binder : IBinder?) {
val service = binder as LocationSimulationService.LocationMockBinder
mService = service.getService()
mBound = true
initCollectors()
}
override fun onServiceDisconnected(name: ComponentName?) {
mBound = false
}
}
private fun initCollectors() {
lifecycleScope.launch {
if (mBound){
mService.getLog().collect { logModelList ->
rvAdapter.submitList(logModelList)
if (lastThreeElementsAreVisible){
binding.rvLogTracker.smoothScrollToPosition(rvAdapter.itemCount - 1)
}
}
}
}
lifecycleScope.launch {
if (mBound){
mService.getConnectionStatus().collectLatest {
when (it){
ConnectionStatus.Connected -> {
binding.txtServerConnectionStatus.text = getString(R.string.serverConnectionStatusPropertyFormat, "Connected")
}
ConnectionStatus.Disconnected -> {
binding.txtServerConnectionStatus.text = getString(R.string.serverConnectionStatusPropertyFormat, "Disconnected")
}
ConnectionStatus.OnReconnect -> {
binding.txtServerConnectionStatus.text = getString(R.string.serverConnectionStatusPropertyFormat, "OnReconnect")
}
ConnectionStatus.Awaiting -> {
binding.txtServerConnectionStatus.text = getString(R.string.serverConnectionStatusPropertyFormat, "Awaiting")
showConnectionErrorDialog()
}
ConnectionStatus.InitialValue -> {
binding.txtServerConnectionStatus.text = getString(R.string.serverConnectionStatusPropertyFormat, "Not Initialized")
}
}
}
}
}
}
private fun showConnectionErrorDialog() {
val dialog = Dialog(this)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setContentView(R.layout.dialog_alert)
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val tvTitle: TextView = dialog.findViewById(R.id.title)
val tvMessage: TextView = dialog.findViewById(R.id.message)
val btnCancel: Button = dialog.findViewById(R.id.btnCancel)
val btnAccept: Button = dialog.findViewById(R.id.btnAccept)
btnCancel.text = getString(R.string.cancel)
btnCancel.setOnClickListener {
dialog.dismiss()
}
tvTitle.text = getString(R.string.serverConnectionProblems)
tvMessage.text = getString(R.string.errorDescriptionFormat, "Connection attempts failed. Check your network/server and try again")
btnAccept.text = getString(R.string.tryAgain)
btnAccept.setOnClickListener {
if(mBound) mService.connectToServer(url)
dialog.dismiss()
}
dialog.show()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTrackerLogBinding.inflate(layoutInflater)
setContentView(binding.root)
enableEdgeToEdge()
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
url = intent.getStringExtra("webSocketUrl") ?: ""
locationPermissionRequest = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
when {
permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) -> {
if(!serviceStarted){
Intent(this, LocationSimulationService::class.java).also {
startService(it)
bindService(it, mConnection, Context.BIND_AUTO_CREATE)
}
serviceStarted = true
}
if(mBound && !connectedToServer){
mService.connectToServer(url)
connectedToServer = true
}
}
permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) -> {
if(!serviceStarted){
Intent(this, LocationSimulationService::class.java).also {
startService(it)
bindService(it, mConnection, Context.BIND_AUTO_CREATE)
}
serviceStarted = true
}
if(mBound && !connectedToServer){
mService.connectToServer(url)
connectedToServer = true
}
}
else -> {
Toast.makeText(baseContext, "Problems with permission", Toast.LENGTH_SHORT)
.show()
}
}
}
}
override fun onStart() {
super.onStart()
initUI()
}
private fun initUI() {
binding.txtServerAddress.text = getString(R.string.serverAddressPropertyFormat, url)
binding.btnBack.setOnClickListener {
if (!connectedToServer){
onBackPressedDispatcher.onBackPressed()
}
}
binding.startService.setOnClickListener {
val connectionStatus = if (mBound){
mService.getConnectionStatus().value
} else {
ConnectionStatus.InitialValue
}
when (connectionStatus){
ConnectionStatus.Awaiting -> requestLocationPermission()
ConnectionStatus.InitialValue -> requestLocationPermission()
ConnectionStatus.Disconnected -> requestLocationPermission()
else -> {
Toast.makeText(this, "SIMTAK Service is already running", Toast.LENGTH_SHORT).show()
}
}
}
if (!serviceStarted){
binding.startService.performClick()
}
binding.stopService.setOnClickListener {
val connectionStatus = if (mBound){
mService.getConnectionStatus().value
} else {
ConnectionStatus.InitialValue
}
when (connectionStatus){
ConnectionStatus.Awaiting -> secureStopService()
ConnectionStatus.Connected -> secureStopService()
ConnectionStatus.OnReconnect -> secureStopService()
else -> {
Toast.makeText(this, "SIMTAK Service is already stopped", Toast.LENGTH_SHORT).show()
}
}
}
setUpLogTrackerRV()
}
private fun setUpLogTrackerRV() {
val rv = binding.rvLogTracker
rv.adapter = rvAdapter
rv.layoutManager = LinearLayoutManager(this)
rv.addOnScrollListener(object : RecyclerView.OnScrollListener(){
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val layoutManager = recyclerView.layoutManager as LinearLayoutManager?
layoutManager?.let {
val totalItemCount = it.itemCount
val lastVisibleItemPosition = it.findLastVisibleItemPosition()
lastThreeElementsAreVisible = totalItemCount - lastVisibleItemPosition <= 3
}
}
})
}
private fun secureStopService(){
if (mBound){
mService.stopByActivity()
connectedToServer = false
}
}
override fun onResume() {
super.onResume()
if (rvAdapter.itemCount -1 > 0){
binding.rvLogTracker.smoothScrollToPosition(rvAdapter.itemCount - 1)
}
}
private fun requestLocationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
locationPermissionRequest.launch(
arrayOf(
Manifest.permission.FOREGROUND_SERVICE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
}
}
override fun onDestroy() {
super.onDestroy()
mService.stopByActivity()
unbindService(mConnection)
}
}
@@ -1,39 +0,0 @@
package com.armatak.simtak.trackerLog.data.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import com.armatak.simtak.R
import com.armatak.simtak.trackerLog.data.models.LogModel
import com.armatak.simtak.trackerLog.data.viewHolder.ViewHolderLogTracker
class AdapterLogTracker: ListAdapter<LogModel, ViewHolderLogTracker>(DIFF_CALLBACK) {
companion object{
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<LogModel>(){
override fun areItemsTheSame(oldItem: LogModel, newItem: LogModel): Boolean {
return oldItem.idLine == newItem.idLine
}
override fun areContentsTheSame(oldItem: LogModel, newItem: LogModel): Boolean {
return oldItem == newItem
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolderLogTracker {
val layoutInflater = LayoutInflater.from(parent.context)
return ViewHolderLogTracker(
layoutInflater.inflate(
R.layout.item_log_tracker,
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolderLogTracker, position: Int) {
val item = getItem(position)
holder.render(item)
}
}
@@ -1,9 +0,0 @@
package com.armatak.simtak.trackerLog.data.models
sealed interface ConnectionStatus {
data object Connected : ConnectionStatus
data object Disconnected : ConnectionStatus
data object OnReconnect : ConnectionStatus
data object Awaiting : ConnectionStatus
data object InitialValue : ConnectionStatus
}
@@ -1,15 +0,0 @@
package com.armatak.simtak.trackerLog.data.models
data class LogModel(
val idLine: Int,
val time: String,
val body: String,
val type: LogTypes
)
sealed interface LogTypes {
data object Error : LogTypes
data object Warning : LogTypes
data object Normal : LogTypes
data object NetworkOperation : LogTypes
}
@@ -1,45 +0,0 @@
package com.armatak.simtak.trackerLog.data.viewHolder
import android.view.View
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.armatak.simtak.R
import com.armatak.simtak.databinding.ItemLogTrackerBinding
import com.armatak.simtak.trackerLog.data.models.LogModel
import com.armatak.simtak.trackerLog.data.models.LogTypes
class ViewHolderLogTracker(view: View) : ViewHolder(view) {
private val binding = ItemLogTrackerBinding.bind(view)
fun render(item: LogModel) {
val tvLogBody = binding.tvLogBody
val tvLogType = binding.tvLogType
binding.tvLogTime.text = item.time
tvLogBody.text = item.body
tvLogType.apply {
when (item.type) {
LogTypes.Error -> {
tvLogBody.setTextColor(context.getColor(R.color.errorColor))
setTextColor(context.getColor(R.color.errorColor))
text = context.getString(R.string.error)
}
LogTypes.NetworkOperation -> {
tvLogBody.setTextColor(context.getColor(R.color.networkColor))
setTextColor(context.getColor(R.color.networkColor))
text = context.getString(R.string.networkOperation)
}
LogTypes.Normal -> {
tvLogBody.setTextColor(context.getColor(R.color.darkGrey))
setTextColor(context.getColor(R.color.darkGrey))
text = context.getString(R.string.normal)
}
LogTypes.Warning -> {
tvLogBody.setTextColor(context.getColor(R.color.warningColor))
setTextColor(context.getColor(R.color.warningColor))
text = context.getString(R.string.warning)
}
}
}
}
}
-19
View File
@@ -1,19 +0,0 @@
<vector android:height="500dp" android:viewportHeight="1000"
android:viewportWidth="1000" android:width="500dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#00000000"
android:pathData="M731.7,11.3H831A157.7,157.7 0,0 1,988.7 169v99.3"
android:strokeColor="#fff" android:strokeLineCap="round"
android:strokeLineJoin="round" android:strokeWidth="22"/>
<path android:fillColor="#00000000"
android:pathData="M988.7,731.7V831A157.7,157.7 0,0 1,831 988.7H731.7"
android:strokeColor="#fff" android:strokeLineCap="round"
android:strokeLineJoin="round" android:strokeWidth="22"/>
<path android:fillColor="#00000000"
android:pathData="M268.3,11.3H169A157.7,157.7 0,0 0,11.3 169v99.3"
android:strokeColor="#fff" android:strokeLineCap="round"
android:strokeLineJoin="round" android:strokeWidth="22"/>
<path android:fillColor="#00000000"
android:pathData="M11.3,731.7V831A157.7,157.7 0,0 0,169 988.7h99.3"
android:strokeColor="#fff" android:strokeLineCap="round"
android:strokeLineJoin="round" android:strokeWidth="22"/>
</vector>
@@ -1,46 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="680.31dp"
android:height="680.31dp"
android:viewportWidth="680.31"
android:viewportHeight="680.31">
<path
android:fillColor="#FF000000"
android:pathData="M92.18,340.15C76.15,278.43 66.36,217 66.03,153.9c8.93,-1.43 17.25,-2.64 25.52,-4.12c28.79,-5.15 55.83,-15.34 82.3,-27.6c33.51,-15.52 64.93,-34.45 94.7,-56.17c13.83,-10.09 27.44,-20.47 40.98,-30.94c8.11,-6.27 16.01,-12.83 23.75,-19.55c2.87,-2.49 4.5,-1.53 6.93,0.47c14.98,12.33 29.8,24.89 45.23,36.64c30.57,23.27 62.65,44.42 96.97,61.65c37.67,18.91 76.63,34.75 119.31,38.42c5.37,0.46 5.35,3.53 5.29,7.49c-0.66,42.46 -5.59,84.46 -13.93,126.06c-3.53,17.65 -7.63,35.19 -11.71,53.89c4.81,0 9.53,0.34 14.18,-0.08c6.02,-0.55 9.09,1.5 10.64,7.65c2.9,11.51 6.58,22.83 10.07,34.19c14.6,47.51 29.26,95 43.86,142.51c2.54,8.26 1.44,9.7 -7.23,9.71c-53.57,0.02 -107.13,0.08 -160.7,-0.11c-4.9,-0.02 -7.76,1.59 -10.74,5.4c-10.3,13.14 -20.27,26.68 -31.85,38.65c-27.19,28.11 -56.81,53.49 -89.62,74.97c-2.27,1.49 -4.82,2.55 -7.15,3.95c-20.68,12.4 -11.96,12.53 -33.08,-0.3c-32.98,-20.03 -62.8,-44.05 -89.1,-72.24c-13.67,-14.65 -26.52,-30.09 -39.33,-45.5c-2.98,-3.58 -5.78,-4.91 -10.29,-4.9c-53.11,0.14 -106.22,0.09 -159.33,0.09c-10.49,0 -11.18,-0.97 -8.17,-11.05c12.55,-42.04 24.96,-84.11 37.68,-126.09c5.27,-17.39 11.03,-34.65 17.05,-51.79c0.78,-2.21 4.33,-4.47 6.86,-4.81C80.52,339.64 86.07,340.15 92.18,340.15zM337.35,48.77c-23.64,17.52 -46.73,34.97 -70.17,51.93c-30.67,22.18 -63.72,40.19 -98.84,54.29c-23.84,9.58 -48.61,15.72 -75.45,18.38c2.69,56.69 11.2,112.1 25.9,166.46c2.04,0.11 2.94,0.2 3.85,0.2c141.92,0.01 283.83,-0.02 425.75,0.11c4.61,0 6.42,-1.57 7.32,-5.87c4.37,-20.81 9.38,-41.5 13.34,-62.39c2.77,-14.59 4.48,-29.4 6.22,-44.16c2.11,-18 3.76,-36.06 5.46,-52.67c-19.58,-4.51 -37.32,-7.87 -54.65,-12.73c-30.79,-8.63 -59.22,-23.05 -86.22,-39.75c-23.86,-14.75 -46.55,-31.42 -69.41,-47.73C358.77,66.51 347.87,57.1 337.35,48.77zM454.8,534.62c-79.39,0 -156.77,0 -234.15,0c-0.65,0.78 -1.29,1.56 -1.94,2.34c3.85,3.03 7.98,5.76 11.51,9.13c15.51,14.79 30,30.81 46.49,44.39c17.75,14.61 37.28,27.09 56.22,40.22c1.65,1.15 5.3,1.16 7.09,0.12c27.7,-16.2 53.45,-35.12 76.65,-57.29C429.35,561.41 441.26,548.49 454.8,534.62zM497.06,493.41"
tools:ignore="VectorPath" />
<path
android:pathData="M337.35,48.77c10.51,8.33 21.42,17.73 33.08,26.06c22.86,16.31 45.56,32.97 69.41,47.73c27.01,16.7 55.43,31.12 86.22,39.75c17.32,4.86 35.06,8.23 54.65,12.73c-1.7,16.61 -3.34,34.67 -5.46,52.67c-1.73,14.76 -3.45,29.57 -6.22,44.16c-3.97,20.89 -8.97,41.58 -13.34,62.39c-0.9,4.3 -2.71,5.87 -7.32,5.87c-141.92,-0.13 -283.83,-0.1 -425.75,-0.11c-0.9,0 -1.8,-0.09 -3.85,-0.2c-14.7,-54.36 -23.21,-109.76 -25.9,-166.46c26.84,-2.66 51.61,-8.8 75.45,-18.38c35.12,-14.1 68.17,-32.11 98.84,-54.29C290.63,83.75 313.72,66.29 337.35,48.77zM446.57,175.27c-0.65,0.6 -1.3,1.2 -1.95,1.8c0.35,1.84 0.1,4.33 1.2,5.35c1.1,1.02 4.11,1.35 5.27,0.54c1.04,-0.74 1.57,-3.92 0.84,-5.17c-3.67,-6.29 -7.99,-12.19 -11.76,-18.42c-12.65,-20.93 -30.07,-33.52 -55.54,-31.79c-16.32,1.11 -30.75,7.69 -44.08,16.75c-2.86,1.94 -4.63,2.3 -7.76,0.48c-7.81,-4.55 -15.72,-9.09 -24.04,-12.54c-24,-9.97 -49.16,-5.07 -65.28,12.91c-5.41,6.04 -9.3,13.45 -13.82,20.28c-2.43,3.67 -4.85,7.37 -6.99,11.21c-0.95,1.7 -1.2,3.79 -1.76,5.7c1.63,0.45 3.81,1.75 4.75,1.14c1.45,-0.94 2.22,-3.13 2.95,-4.92c0.5,-1.23 -0.02,-3.5 0.72,-3.93c11.14,-6.5 22.09,-13.47 33.78,-18.79c6.01,-2.74 13.36,-0.26 17.07,5.5c6.03,9.37 10.8,19.54 16.11,29.37c-3.63,0.36 -5.71,-0.68 -7.87,-0.92c-10.77,-1.19 -21.56,-2.15 -32.34,-3.22c-2.94,-0.29 -5.86,-0.93 -8.79,-0.93c-1.57,0 -3.42,0.7 -4.6,1.71c-0.57,0.49 -0.37,3.12 0.3,3.57c1.28,0.86 3.99,1.69 4.61,1.06c4.23,-4.34 8.12,-1.62 11.73,0.43c10.94,6.23 20.32,14.15 25.42,24.28c-15.25,10.24 -30.1,20.2 -44.93,30.18c-7.18,4.83 -11.6,13.51 -21.22,15.04c-0.92,0.15 -2.24,2.59 -2.03,3.71c0.23,1.21 1.97,2.86 3.17,2.97c1.16,0.1 2.64,-1.36 3.66,-2.44c1.5,-1.58 2.42,-4.56 4.09,-4.98c13.67,-3.42 27.38,-6.85 41.25,-9.32c9.19,-1.63 18.67,-1.69 29.36,-2.55c-11.44,20.96 -16.58,41.85 -20.49,63.17c-0.43,2.37 -3.12,4.34 -4.8,6.47c-1.01,1.28 -2.08,2.5 -3.12,3.74c1.59,1.09 3.18,3.04 4.75,3.01c1.26,-0.02 2.74,-2.27 3.65,-3.81c1.38,-2.32 1.78,-5.48 3.6,-7.25c15.41,-14.92 31.09,-29.56 46.57,-44.4c2.89,-2.77 5.27,-6.06 7.16,-8.27c15.93,15.32 31.53,30.34 47.17,45.31c2.31,2.21 4.79,4.25 7.22,6.34c2.68,2.31 6.17,3.98 4.98,8.74c-0.21,0.86 2.23,3.42 3.24,3.31c1.72,-0.18 3.28,-1.86 4.91,-2.91c-1.06,-1.23 -2.19,-2.4 -3.17,-3.69c-1.73,-2.27 -3.89,-4.4 -4.9,-6.98c-1.23,-3.14 -1.19,-6.75 -2.15,-10.02c-5.1,-17.35 -10.34,-34.66 -15.52,-51.98c0.58,-0.03 2.36,-0.19 4.14,-0.17c20.72,0.26 40.7,4.87 60.5,10.45c3.22,0.91 7.64,0.09 7.45,5.78c-0.03,0.81 2.62,2.15 4.16,2.39c0.77,0.12 2.71,-1.87 2.58,-2.65c-0.25,-1.53 -1.26,-3.36 -2.53,-4.21c-1.93,-1.3 -4.69,-1.43 -6.51,-2.82c-11.03,-8.45 -21.52,-17.65 -32.92,-25.55c-8.52,-5.91 -18.14,-10.23 -27.21,-15.23c6.11,-11.76 15.6,-19.73 26.74,-25.87c3.42,-1.89 7.11,-4.6 11.11,-0.32c0.65,0.7 3.51,0.15 4.67,-0.72c0.77,-0.58 0.98,-3.44 0.3,-4.07c-1.07,-1 -3.08,-1.35 -4.69,-1.33c-2.94,0.02 -5.87,0.72 -8.81,0.75c-4.75,0.06 -9.58,-0.78 -14.24,-0.19c-7.79,1 -15.48,2.84 -25.23,4.71c5.26,-10.08 9.38,-19.11 14.52,-27.5c4.76,-7.77 14.31,-11.22 24.69,-5.91C426.4,163.01 436.37,169.35 446.57,175.27z"
android:fillColor="#FFFFFF"
tools:ignore="VectorPath" />
<path
android:pathData="M454.8,534.62c-13.54,13.87 -25.45,26.79 -38.13,38.91c-23.2,22.18 -48.95,41.09 -76.65,57.29c-1.79,1.05 -5.43,1.03 -7.09,-0.12c-18.94,-13.13 -38.47,-25.61 -56.22,-40.22c-16.5,-13.58 -30.98,-29.6 -46.49,-44.39c-3.53,-3.37 -7.66,-6.1 -11.51,-9.13c0.65,-0.78 1.29,-1.56 1.94,-2.34C298.03,534.62 375.41,534.62 454.8,534.62z"
android:fillColor="#FFFFFF"/>
<path
android:fillColor="#FF000000"
android:pathData="M446.57,175.27c-10.19,-5.91 -20.16,-12.26 -30.64,-17.62c-10.39,-5.31 -19.93,-1.86 -24.69,5.91c-5.14,8.4 -9.26,17.42 -14.52,27.5c9.75,-1.87 17.43,-3.71 25.23,-4.71c4.66,-0.6 9.49,0.24 14.24,0.19c2.94,-0.03 5.87,-0.73 8.81,-0.75c1.61,-0.01 3.63,0.33 4.69,1.33c0.67,0.63 0.47,3.49 -0.3,4.07c-1.16,0.87 -4.02,1.42 -4.67,0.72c-4,-4.28 -7.69,-1.57 -11.11,0.32c-11.14,6.14 -20.63,14.11 -26.74,25.87c9.07,5 18.69,9.33 27.21,15.23c11.4,7.9 21.89,17.09 32.92,25.55c1.82,1.39 4.58,1.53 6.51,2.82c1.27,0.85 2.28,2.68 2.53,4.21c0.13,0.79 -1.81,2.77 -2.58,2.65c-1.54,-0.23 -4.19,-1.57 -4.16,-2.39c0.19,-5.69 -4.23,-4.87 -7.45,-5.78c-19.81,-5.58 -39.78,-10.19 -60.5,-10.45c-1.78,-0.02 -3.57,0.14 -4.14,0.17c5.19,17.32 10.43,34.63 15.52,51.98c0.96,3.27 0.92,6.88 2.15,10.02c1.01,2.57 3.17,4.71 4.9,6.98c0.98,1.29 2.11,2.47 3.17,3.69c-1.63,1.05 -3.19,2.73 -4.91,2.91c-1.02,0.11 -3.46,-2.45 -3.24,-3.31c1.19,-4.76 -2.3,-6.43 -4.98,-8.74c-2.43,-2.09 -4.91,-4.13 -7.22,-6.34c-15.64,-14.98 -31.24,-30 -47.17,-45.31c-1.89,2.21 -4.27,5.5 -7.16,8.27c-15.49,14.84 -31.17,29.48 -46.57,44.4c-1.82,1.76 -2.22,4.93 -3.6,7.25c-0.92,1.54 -2.4,3.79 -3.65,3.81c-1.57,0.03 -3.17,-1.92 -4.75,-3.01c1.04,-1.25 2.12,-2.47 3.12,-3.74c1.68,-2.13 4.36,-4.1 4.8,-6.47c3.91,-21.32 9.05,-42.22 20.49,-63.17c-10.69,0.87 -20.16,0.92 -29.36,2.55c-13.87,2.47 -27.57,5.9 -41.25,9.32c-1.66,0.42 -2.59,3.4 -4.09,4.98c-1.02,1.08 -2.5,2.54 -3.66,2.44c-1.2,-0.1 -2.94,-1.76 -3.17,-2.97c-0.21,-1.12 1.11,-3.56 2.03,-3.71c9.62,-1.53 14.05,-10.21 21.22,-15.04c14.83,-9.98 29.68,-19.94 44.93,-30.18c-5.09,-10.13 -14.48,-18.05 -25.42,-24.28c-3.6,-2.05 -7.49,-4.77 -11.73,-0.43c-0.61,0.63 -3.33,-0.2 -4.61,-1.06c-0.67,-0.45 -0.87,-3.08 -0.3,-3.57c1.18,-1.01 3.03,-1.71 4.6,-1.71c2.93,0 5.86,0.64 8.79,0.93c10.78,1.07 21.58,2.03 32.34,3.22c2.17,0.24 4.24,1.28 7.87,0.92c-5.31,-9.83 -10.08,-20 -16.11,-29.37c-3.71,-5.76 -11.06,-8.24 -17.07,-5.5c-11.69,5.33 -22.64,12.3 -33.78,18.79c-0.74,0.43 -0.22,2.7 -0.72,3.93c-0.73,1.79 -1.5,3.98 -2.95,4.92c-0.94,0.61 -3.12,-0.69 -4.75,-1.14c0.57,-1.91 0.82,-4 1.76,-5.7c2.14,-3.84 4.56,-7.54 6.99,-11.21c4.52,-6.83 8.41,-14.24 13.82,-20.28c16.12,-17.99 41.28,-22.88 65.28,-12.91c8.32,3.46 16.23,8 24.04,12.54c3.13,1.82 4.9,1.47 7.76,-0.48c13.33,-9.06 27.76,-15.64 44.08,-16.75c25.47,-1.74 42.89,10.86 55.54,31.79c3.77,6.23 8.1,12.13 11.76,18.42c0.72,1.24 0.2,4.43 -0.84,5.17c-1.15,0.81 -4.16,0.48 -5.27,-0.54c-1.11,-1.02 -0.86,-3.51 -1.2,-5.35C445.27,176.46 445.92,175.86 446.57,175.27zM311.8,199.86c4.96,1.46 9.92,2.93 15.7,4.63C325.69,193.56 320.47,191.78 311.8,199.86zM360.9,199.7c-0.23,-0.83 -0.45,-1.66 -0.68,-2.49c-8,-5.19 -12.73,-3.49 -14.83,7.19C351.17,202.65 356.03,201.17 360.9,199.7z"
tools:ignore="VectorPath" />
<path
android:pathData="M311.8,199.86c8.68,-8.08 13.9,-6.3 15.7,4.63C321.72,202.78 316.76,201.32 311.8,199.86z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M360.9,199.7c-4.87,1.48 -9.73,2.95 -15.51,4.71c2.1,-10.68 6.83,-12.39 14.83,-7.19C360.44,198.04 360.67,198.87 360.9,199.7z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M60.46,456.26l28.2,-1.85c0.61,4.81 1.85,8.47 3.73,10.99c3.05,4.08 7.42,6.11 13.09,6.11c4.23,0 7.49,-1.04 9.78,-3.13c2.29,-2.08 3.44,-4.5 3.44,-7.25c0,-2.61 -1.09,-4.95 -3.27,-7.01c-2.18,-2.06 -7.24,-4.01 -15.18,-5.84c-13,-3.07 -22.27,-7.15 -27.81,-12.23c-5.58,-5.08 -8.38,-11.56 -8.38,-19.44c0,-5.17 1.43,-10.06 4.29,-14.67c2.86,-4.6 7.15,-8.22 12.89,-10.86c5.74,-2.63 13.6,-3.95 23.59,-3.95c12.26,0 21.6,2.39 28.04,7.18c6.43,4.79 10.26,12.4 11.48,22.84l-27.94,1.72c-0.74,-4.53 -2.3,-7.83 -4.68,-9.89c-2.38,-2.06 -5.66,-3.09 -9.85,-3.09c-3.45,0 -6.04,0.77 -7.79,2.3c-1.75,1.54 -2.62,3.4 -2.62,5.6c0,1.6 0.72,3.05 2.16,4.33c1.4,1.33 4.71,2.57 9.95,3.71c12.96,2.93 22.23,5.9 27.84,8.9c5.6,3 9.68,6.72 12.24,11.16c2.55,4.44 3.83,9.41 3.83,14.91c0,6.46 -1.7,12.41 -5.1,17.86c-3.4,5.45 -8.16,9.58 -14.26,12.4c-6.11,2.82 -13.81,4.23 -23.1,4.23c-16.31,0 -27.61,-3.3 -33.89,-9.89C64.84,474.81 61.28,466.42 60.46,456.26z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M158.08,388.86h29.71v100.72h-29.71V388.86z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M203.23,388.86h38.98l15.03,61.28l14.93,-61.28h38.96v100.72h-24.27v-76.81l-18.7,76.81h-21.97l-18.67,-76.81v76.81h-24.27V388.86z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M317.8,388.86h90.1v24.87h-30.23v75.85h-29.64v-75.85H317.8V388.86z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M465.69,472.95h-33.65l-4.67,16.63H397.1l36.05,-100.72h32.33l36.04,100.72h-31.04L465.69,472.95zM459.54,451.17l-10.59,-36.21l-10.48,36.21H459.54z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M505.58,388.86h29.64v38.06l31.05,-38.06h39.42l-35,38.02l36.57,62.7h-36.5l-20.22,-41.42L535.22,465v24.58h-29.64V388.86z"
android:fillColor="#FFFFFF"/>
</vector>

Some files were not shown because too many files have changed in this diff Show More