100 Commits

Author SHA1 Message Date
0486f2a285 Added initial COT Sensor payloads to support UAV Tools integration for Arma Drones 2026-04-13 08:03:31 -03:00
753dcab26e Added hellanmaaw winter support 2026-03-31 07:23:48 -03:00
2f53488ba8 Added video url prop to 3den editor/zeus, allowing to parse __video prop to cots 2026-03-31 07:21:29 -03:00
323339e679 Removed video addon, too simple for a specific addon 2026-03-31 07:20:19 -03:00
3f14a75e81 Added video url parser to CoT types 2026-03-31 07:19:39 -03:00
469a54c141 Added Hellanmma map support 2026-03-31 07:18:23 -03:00
2ee9030c00 Updated media folder 2026-03-26 14:45:08 -03:00
5b29a40990 Improved mTLS description on readme 2026-03-26 03:47:54 -03:00
708fe5e670 Fixed CoT queue during armatak connection to the TAK Server, running soft as butter 2026-03-26 03:45:05 -03:00
e32aadda4e Splitted Connection Module 2026-03-26 01:05:54 -03:00
c35b7f0268 Updated project readme file 2026-03-24 16:56:26 -03:00
876cf900c3 Changed dialogs and module UI to get mTLS needed params 2026-03-24 16:56:19 -03:00
778ac0ac54 Added the mTLS connection calls to zeus and 3den modules 2026-03-24 16:55:53 -03:00
b816144fb0 Added transport layer and configured extension commands to call mTLS socket connection 2026-03-24 16:55:36 -03:00
61ba9f6d63 Added connector and enrollment for mTLS client certificate auto enrollment on game sessions, will MOCK a official tak client behavior when authenticating 2026-03-24 16:55:05 -03:00
f88c02a7aa formatted some rust files for linting porpuses 2026-03-24 16:44:22 -03:00
5ffc08e6f1 Readded reqwest dependency to cargo toml, will be used for TAK Server API interaction on authencated tak server connections 2026-03-24 16:41:38 -03:00
9392380c78 Added hemtt private key to git ignore 2026-03-24 16:40:58 -03:00
a18343b81d Commented video module 2026-03-24 14:03:28 -03:00
Valmo Trindade
13cd08c655 Added mandol map support 2026-01-03 02:55:39 -03:00
Valmo Trindade
8fe14dc18d Added Clafghan Map Support 2026-01-02 03:28:10 -03:00
Valmo Trindade
1bec26df8a Added UMP Colombia map support 2025-12-21 02:21:02 -03:00
Valmo Trindade
c5d5da636f added malvinas pradero ganso function call 2025-12-13 15:00:33 -03:00
Valmo Trindade
c2e137e67c Added lawn map 2025-12-13 14:59:05 -03:00
Valmo Trindade
de5ac9dbb5 Added Malvinas Maps 2025-12-12 19:12:04 -03:00
Valmo Trindade
ef3be1e768 fixed router entity remover function 2025-12-10 23:07:53 -03:00
Valmo Trindade
9bda92d389 Removed once cell dependency 2025-11-30 10:43:43 -03:00
Valmo Trindade
9763cb6697 reoganized command groups on extension call 2025-11-30 10:43:18 -03:00
Valmo Trindade
5ac49e12f8 customized sensor markers to dont cheat enemy info 2025-11-26 20:21:09 -03:00
Valmo Trindade
2108d20b01 changed default affiliation to be unkown 2025-11-26 20:20:51 -03:00
Valmo Trindade
524e7a0b3e Added vehicle sensor handler to get sensor input and throw it on ATAK 2025-11-22 12:15:15 -03:00
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
193 changed files with 4316 additions and 5077 deletions

2
.gitattributes vendored
View File

@@ -1,3 +1,5 @@
*.rs linguist-language=Rust
*.paa filter=lfs diff=lfs merge=lfs -text
*.p3d filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text

View File

@@ -5,32 +5,6 @@ on:
branches: [ main ]
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:
strategy:
matrix:
@@ -66,7 +40,7 @@ jobs:
retention-days: 1
package:
needs: [build_extension, package_application]
needs: [build_extension]
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
@@ -88,11 +62,6 @@ jobs:
with:
name: x86_64-unknown-linux-gnu
- 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
uses: arma-actions/hemtt@v1
- name: Build

View File

@@ -5,32 +5,6 @@ on:
branches: [ main ]
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:
strategy:
matrix:
@@ -66,7 +40,7 @@ jobs:
retention-days: 1
package:
needs: [build_extension, package_application]
needs: [build_extension]
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
@@ -88,11 +62,6 @@ jobs:
with:
name: x86_64-unknown-linux-gnu
- 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
uses: arma-actions/hemtt@v1
- name: Build

View File

@@ -9,31 +9,6 @@ permissions:
contents: write
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:
strategy:
matrix:
@@ -69,7 +44,7 @@ jobs:
retention-days: 1
package:
needs: [build_extension, package_application]
needs: [build_extension]
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
@@ -91,11 +66,6 @@ jobs:
with:
name: x86_64-unknown-linux-gnu
- 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
uses: arma-actions/hemtt@v1
- name: Build
@@ -121,7 +91,7 @@ jobs:
release_name: ${{ github.ref }}
body: |
Changes in this release:
${{ env.COMMIT_MESSAGES }}
${{ github.event.head_commit.message }}
draft: true
prerelease: false
- name: Upload Release Asset

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 }}

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@
hemtt
hemtt.exe
*.biprivatekey
.hemttprivatekey
source/
.vscode
releases/

View File

@@ -25,8 +25,7 @@ include = [
"LICENSE",
"*.dll",
"*.so",
"*.paa",
"simtak.apk"
"*.paa"
]
[properties]
@@ -38,30 +37,31 @@ preset = "Hemtt"
[hemtt.launch.default]
workshop = [
"450814997", # CBA
"450814997", # CBA_A3
"463939057", # ACE
"623475643", # 3den enhanced
"1779063631", # Zeus enhanced
"1673595418", # User Input Menus
"1678581937", # Extended Function Viewer
"1231625987", #Debug Console
"751965892", # ACRE2
"2522638637", # ACE Extended Arsenal
"333310405", # Enhanced Movement
"2034363662", # Enhanced Movement Rework
"2941986336", # Hatchet Interaction Framework - Stable Version
"1745501605", # Hatchet H-60 pack - Stable Version
"843577117", # RHSUSAF
"3030830594", # Western Dusk
"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
"583496184", # CUP Terrains
"583544987", # CUP Maps
"3015795970", # No zoom
"2941986336", # Hatchet Framework
"1745501605", # Hatchet H-60 Pack
"333310405", # Enhanced Moviments
"2034363662", # Enhanced Moviments Rework
"2257686620", # Blastcore Murr
"3407948300", # JSRS Sound Mod
"2560276469", # Restrict Markers
"3493557838" # Ballad of the Green Berets
]
mission = "armatak_jtac.Mountains_ACR"
parameters = [
"-skipIntro",
"-noSplash",

1895
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,21 +6,14 @@ edition = "2021"
[dependencies]
arma-rs = "1.10.4"
chrono = "0.4.39"
futures = "0.3.31"
futures-util = "0.3.31"
http = "1.1.0"
lazy_static = "1.5.0"
log = "0.4.22"
log4rs = "1.3.0"
once_cell = "1.19.0"
qrcode = "0.14.1"
regex = "1.10.6"
reqwest = { version = "0.12.7", features = ["blocking"] }
reqwest = { version = "0.12.15", default-features = false, features = ["blocking", "json", "rustls-tls"] }
rcgen = { version = "0.13.2", default-features = false, features = ["crypto", "pem", "aws_lc_rs"] }
rustls = "0.23.23"
rustls-pemfile = "2.2.0"
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]
version = "1.10.0"

View File

@@ -4,6 +4,10 @@
ARMATAK is a server side Arma 3 addons for streaming unit positions to TAK Clients in sessions on real locations maps. It can be runned both as a clientside mod or a serverside mod, when runned serverside, it will create a TCP Socket connection between Arma 3 and the TAK Server, sending the game session information into it. When used clientside, Arma 3 will host a websocket server that you can connect to your phone and mock the phone's location to the player's in game location.
The server-side CoT router supports two transports:
- Plain TCP, for legacy TAK ingress.
- Mutual TLS, using the TAK Server authentication API, so the Arma session can publish as an authenticated TAK device on port `8089`.
## Get in Touch
[Join the Discord Server for ARMATAK!](https://discord.gg/svK64PCycU)

View File

@@ -1,2 +1,3 @@
PREP(convertClientLocation);
PREP(extractClientPosition);
PREP(startUDPSocket);

View File

@@ -4,11 +4,5 @@ if (!hasInterface) exitWith {};
_local_address = "armatak" callExtension ["local_ip", []] select 0;
"armatak" callExtension ["websocket:start", []];
SETVAR(player,GVAR(localAddress),_local_address);
SETVAR(player,GVAR(eudConnected),false);
[{
"armatak" callExtension ["websocket:location", [player call armatak_client_fnc_extractClientPosition]];
}, 1, []] call CBA_fnc_addPerFrameHandler;

View File

@@ -16,4 +16,20 @@ class CfgPatches {
};
};
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
addons/client/dialog.hpp Normal file
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";
};
};
};

View File

@@ -1,23 +1,23 @@
#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
*/
* 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"];
@@ -38,6 +38,9 @@ switch (toLower worldName) do {
case "vr": {
_realLocation = _position call armatak_fnc_convert_to_vr;
};
case "lawn": {
_realLocation = _position call armatak_fnc_convert_to_lawn;
};
case "cucui": {
_realLocation = _position call armatak_fnc_convert_to_cucui;
};
@@ -71,6 +74,45 @@ switch (toLower worldName) do {
case "kunduz": {
_realLocation = _position call armatak_fnc_convert_to_kunduz;
};
case "kunduz_valley": {
_realLocation = _position call armatak_fnc_convert_to_kunduz_valley;
};
case "malvinasfalkands": {
_realLocation = _position call armatak_fnc_convert_to_malvinas_malvinasfalkands;
};
case "pebble_island_airfield": {
_realLocation = _position call armatak_fnc_convert_to_malvinas_pebble_island_airfield;
};
case "p_argentino_stanley": {
_realLocation = _position call armatak_fnc_convert_to_malvinas_p_argentino_stanley;
};
case "top_malo_house": {
_realLocation = _position call armatak_fnc_convert_to_malvinas_top_malo_house;
};
case "pradera_ganso": {
_realLocation = _position call armatak_fnc_convert_to_malvinas_pradera_ganso;
};
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;
};
case "umb_colombia": {
_realLocation = _position call armatak_fnc_convert_to_colombia;
};
case "clafghan": {
_realLocation = _position call armatak_fnc_convert_to_clafghan;
};
case "rut_mandol": {
_realLocation = _position call armatak_fnc_convert_to_rut_mandol;
};
case "hellanmaa": {
_realLocation = _position call armatak_fnc_convert_to_hellanmaa;
};
case "hellanmaaw": {
_realLocation = _position call armatak_fnc_convert_to_hellanmaa;
};
default {
_warning = format ["<t color='#FF8021'>ARMATAK</t><br/> %1", "Unsupported Map"];
[[_warning, 1.5]] call CBA_fnc_notify;

View File

@@ -18,13 +18,12 @@
params["_unit"];
private _location = (getPos _unit) call FUNC(convertClientLocation);
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;
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);
_payload = [_uuid, _pos select 0, _pos select 1, _pos select 2, _callsign, _bearing, _speed, _callsign];
_unit_info = [_atak_latitude,_atak_longitude,_atak_altitude,_atak_bearing];
_unit_info
_payload

View File

@@ -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;

View File

@@ -78,6 +78,16 @@ class Cfg3den {
condition = "objectVehicle";
typeName = "STRING";
};
class armatak_attribute_video_url {
displayName = "Video URL (RTSP)";
tooltip = "RTSP stream URL for UAS Tool integration. When set, the drone will appear in the ATAK UAS Tool with FOV cone and video feed. Format: rtsp://address:port/path (e.g. rtsp://192.168.1.10:8554/live/drone1). Leave empty to disable UAS Tool integration for this entity.";
property = "armatak_attribute_video_url";
control = "Edit";
expression = "_this setVariable ['armatak_attribute_video_url',_value]";
defaultValue = "''";
condition = "objectVehicle";
typeName = "STRING";
};
};
};
};

View File

@@ -10,12 +10,21 @@ class CfgFunctions {
class send_group_cots {
file = "\armatak\armatak\addons\main\functions\api\fn_send_group_cots.sqf";
};
class send_enemy_cot {
file = "\armatak\armatak\addons\main\functions\api\fn_send_enemy_cot.sqf";
};
class send_eud_cot {
file = "\armatak\armatak\addons\main\functions\api\fn_send_eud_cot.sqf";
};
class send_marker_cot {
file = "\armatak\armatak\addons\main\functions\api\fn_send_marker_cot.sqf";
};
class send_uas_video_cot {
file = "\armatak\armatak\addons\main\functions\api\fn_send_uas_video_cot.sqf";
};
class send_uas_sensor_cot {
file = "\armatak\armatak\addons\main\functions\api\fn_send_uas_sensor_cot.sqf";
};
class stop_tcp_socket {
file = "\armatak\armatak\addons\main\functions\api\fn_stop_tcp_socket.sqf";
};
@@ -31,6 +40,9 @@ class CfgFunctions {
class extract_role {
file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_role.sqf";
};
class extract_sensor_data {
file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_sensor_data.sqf";
};
class extract_unit_callsign {
file = "\armatak\armatak\addons\main\functions\extract_data\fn_extract_unit_callsign.sqf";
};
@@ -59,12 +71,33 @@ class CfgFunctions {
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_lawn {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_lawn.sqf";
};
class convert_to_livonia {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_livonia.sqf";
};
class convert_to_malden {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_malden.sqf";
};
class convert_to_malvinas_malvinasfalkands {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_malvinas_malvinasfalkands.sqf";
};
class convert_to_malvinas_p_argentino_stanley {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_malvinas_p_argentino_stanley.sqf";
};
class convert_to_malvinas_pebble_island_airfield {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_malvinas_pebble_island_airfield.sqf";
};
class convert_to_malvinas_pradera_ganso {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_malvinas_pradera_ganso.sqf";
};
class convert_to_malvinas_top_malo_house {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_malvinas_top_malo_house.sqf";
};
class convert_to_southen_sahrani {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_southen_sahrani.sqf";
};
@@ -83,6 +116,18 @@ class CfgFunctions {
class convert_to_vr {
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";
};
class convert_to_colombia {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_colombia.sqf";
};
class convert_to_clafghan {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_clafghan.sqf";
};
class convert_to_rut_mandol {
file = "\armatak\armatak\addons\main\functions\map\fn_convert_to_rut_mandol.sqf";
};
};
};
};

View File

@@ -3,41 +3,59 @@
addMissionEventHandler ["ExtensionCallback", {
params ["_name", "_function", "_data"];
if (_name == "WEBSOCKET") then {
[_function, "success", _name] call FUNC(notify);
switch (_name) do {
case "UDP SOCKET": {
[_function, "success", _name] call FUNC(notify);
switch (_function) do {
case "EUD connected": {
SETVAR(player,EGVAR(client,eudConnected),true);
switch (_function) do {
case "EUD Connected": {
SETVAR(player,EGVAR(client,eudConnected),true);
};
case "EUD Disconnected": {
SETVAR(player,EGVAR(client,eudConnected),false);
};
default {};
};
case "EUD disconnected": {
SETVAR(player,GVAR(eudConnected),false);
};
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);
};
default {};
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": {
_message = _function;
if (_data isNotEqualTo "") then {
_message = format ["%1: %2", _function, _data];
};
[_message, "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)]];
};
};
if (_name == "WEBSOCKET WARNING") then {
[_function, "warning", "WEBSOCKET"] call FUNC(notify);
};
if (_name == "WEBSOCKET ERROR") then {
[_function, "error", _name] call FUNC(notify);
};
if (_name == "TCP SOCKET") then {
[_function, "success", _name] call FUNC(notify);
};
if (_name == "TCP SOCKET ERROR") then {
[_function, "error", _name] call FUNC(notify);
};
if (_name == "VIDEO") then {
[_function, "success", _name] call FUNC(notify);
};
if (_name == "VIDEO ERROR") then {
[_function, "error", _name] call FUNC(notify);
};
}];
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)];

View File

@@ -3,12 +3,12 @@ params ["_unit"];
_digitalPointer = laserTarget _unit;
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;
_contact_callsign = ([player] call armatak_fnc_extract_callsign) + ".DP1";
_link_uid = [_unit] call armatak_fnc_extract_uuid;
_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 ["tcp_socket:send_digital_pointer_cot", [_dpCot]];
"armatak" callExtension ["tcp_socket:cot:digital_pointer", [_dpCot]];
};

View File

@@ -1,11 +1,11 @@
// function name: armatak_fnc_extract_drone
// function name: armatak_fnc_send_drone_cot
// function author: Valmo
// function description: Gets the drone information for the CoT Router
params["_drone"];
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 {
case "WEST": {
@@ -25,4 +25,13 @@ 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;
[_drone] call armatak_fnc_send_uas_video_cot;
[_drone] call armatak_fnc_send_uas_sensor_cot;

View File

@@ -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:cot:marker", [_marker_cot]];

View File

@@ -1,4 +1,4 @@
// function name: armatak_fnc_extract_eud_cot_info
// function name: armatak_fnc_send_eud_cot
// function author: Valmo
// function description: Gets the information necessary for generating the EUD Cursor Over Time
@@ -8,6 +8,5 @@ _position = _unit call armatak_client_fnc_extractClientPosition;
_uuid = _unit call armatak_fnc_extract_uuid;
_eud_cot = [_uuid, _position select 0, _position select 1, _position select 2, _callsign, _group_name, _group_role, _position select 3, speed player / 3.6];
"armatak" callExtension ["tcp_socket:send_eud_cot", [_eud_cot]];
_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:cot:eud", [_eud_cot]];

View File

@@ -5,7 +5,7 @@
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_role = [_x] call armatak_fnc_extract_group_role;

View File

@@ -5,9 +5,10 @@
params ["_unit", "_type", "_callsign"];
_unit_position = _unit call armatak_client_fnc_extractClientPosition;
_video_url = [_unit] call armatak_fnc_extract_marker_video_url;
_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, _video_url];
"armatak" callExtension ["tcp_socket:send_marker_cot", [_marker_cot]];
"armatak" callExtension ["tcp_socket:cot:marker", [_marker_cot]];

View File

@@ -0,0 +1,55 @@
// function name: armatak_fnc_send_uas_sensor_cot
// function author: Valmo / ArmaTAK contributors
// function description:
// Sends a b-m-p-s-p-loc CoT event every router tick (1 s) for a drone.
// This is the "sensor position" event consumed by the ATAK UAS Tool to:
// - Draw the FOV cone on the moving map.
// - Compute four-corners for AR marker overlay on the video feed.
// - Show the SPoI (Sensor Point of Interest) crosshair.
//
// The event references the drone's b-i-v video endpoint via the drone UUID,
// so armatak_fnc_send_uas_video_cot must also be called for the same drone.
//
// Exits silently when "armatak_attribute_video_url" is not set, which keeps
// the behavior identical to the old fn_send_drone_cot for drones without a
// configured video stream.
//
// Arguments:
// 0: _drone <OBJECT> The drone object.
//
// Return value: none
params ["_drone"];
private _video_url = _drone getVariable ["armatak_attribute_video_url", ""];
if (_video_url == "") exitWith {};
private _uuid = _drone call armatak_fnc_extract_uuid;
private _sensor_uid = _uuid + "-sensor";
private _callsign = [_drone] call armatak_fnc_extract_marker_callsign;
private _pos = (getPos _drone) call armatak_client_fnc_convertClientLocation;
private _lat = _pos select 0;
private _lon = _pos select 1;
private _hae = _pos select 2;
private _azimuth = parseNumber ((getDir _drone) toFixed 0);
private _allTurrets = [_drone, false] call BIS_fnc_allTurrets;
if (count _allTurrets > 0) then {
private _firstTurretPath = _allTurrets select 0;
private _turretWeapons = _drone weaponsTurret _firstTurretPath;
if (_turretWeapons isNotEqualTo []) then {
private _tDir = _drone weaponDirection (_turretWeapons select 0);
if (!((_tDir select 0) == 0 && (_tDir select 1) == 0)) then {
_azimuth = round (((_tDir select 0) atan2 (_tDir select 1) + 360) mod 360);
};
};
};
private _fov = _drone getVariable ["armatak_uas_fov", 60];
private _range = round (((getPosATL _drone) select 2) max 1);
private _payload = [_sensor_uid, _uuid, _callsign, _lat, _lon, _hae, _azimuth, _fov, _range];
"armatak" callExtension ["tcp_socket:cot:uas_sensor", [_payload]];

View File

@@ -0,0 +1,30 @@
// function name: armatak_fnc_send_uas_video_cot
// function author: Valmo / ArmaTAK contributors
// function description:
// Sends a b-i-v CoT event that declares the RTSP video endpoint for a drone.
// The ATAK UAS Tool picks this up and shows the drone in its UAS list with
// the associated video feed available for playback.
//
// The drone entity MUST have the variable "armatak_attribute_video_url" set
// to a valid RTSP URL, e.g.:
// _drone setVariable ["armatak_attribute_video_url", "rtsp://192.168.1.10:8554/live/drone1"];
// or via the 3DEN attribute "Video URL (RTSP)" in the ARMA Team Awareness Kit
// attribute category.
//
// If the variable is absent or empty the function exits silently.
//
// Arguments:
// 0: _drone <OBJECT> The drone object.
//
// Return value: none
params ["_drone"];
private _video_url = _drone getVariable ["armatak_attribute_video_url", ""];
if (_video_url == "") exitWith {};
private _uuid = _drone call armatak_fnc_extract_uuid;
private _callsign = [_drone] call armatak_fnc_extract_marker_callsign;
private _payload = [_uuid, _callsign, _video_url];
"armatak" callExtension ["tcp_socket:cot:uas_video", [_payload]];

View File

@@ -1,9 +1,11 @@
#include "..\..\script_component.hpp"
params["_group"];
_group_name = _group getVariable "_atak_group_name";
_group_name = _group getVariable QGVAR(group_name);
if (isNil "_group_name") then {
_group_colors = missionNamespace getVariable "armatak_group_colors";
_group_colors = missionNamespace getVariable QGVAR(group_colors);
_group_name = selectRandom _group_colors;
if (count _group_colors > 0) then {
@@ -14,11 +16,11 @@ if (isNil "_group_name") then {
_group_colors deleteAt _randomIndex;
_group_name = _selectedColor;
_group setVariable ["_atak_group_name", _group_name];
missionNamespace setVariable ["armatak_group_colors", _group_colors]
_group setVariable [QGVAR(group_name), _group_name];
missionNamespace setVariable [QGVAR(group_colors), _group_colors]
} else {
_group_name = "Red";
_group setVariable ["_atak_group_name", _group_name];
_group setVariable [QGVAR(group_name), _group_name];
};
};

View File

@@ -1,9 +1,10 @@
params["_unit"];
_group = group _unit;
_group_roles = ["Team Member", "Team Lead", "HQ", "Sniper", "Medic", "Forward Observer", "RTO", "K9"];
_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;
};
@@ -19,7 +20,7 @@ if (((backpack _unit) isKindOf "TFAR_Bag_Base") or (["radio", typeOf _unit, fals
_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;
};
@@ -34,7 +35,7 @@ if (["officer", typeOf _unit, false] call BIS_fnc_inString) then {
_pre_defined_role = _unit getVariable "_atak_group_role";
if (!isNil "_pre_defined_role") then {
_callsign = _pre_defined_callsign;
_callsign = _pre_defined_role;
};
_group_role

View File

@@ -7,15 +7,15 @@ params["_unit"];
private _callsign = "";
if ((([_unit] call BIS_fnc_objectType) select 0) == "Vehicle") then {
_callsign = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "displayName");
_callsign = getText (configOf _unit >> "displayName");
if (!isNull driver _unit) then {
_callsign = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "displayName") + " | " + ([name (driver _unit)] call armatak_fnc_shorten_name);
_callsign = getText (configOf _unit >> "displayName") + " | " + ([name (driver _unit)] call armatak_fnc_shorten_name);
};
};
if (unitIsUAV _unit) then {
_callsign = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "displayName");
_callsign = getText (configOf _unit >> "displayName");
if (isUAVConnected _unit) then {
_callsign = (_callsign) + "[ON]";

View File

@@ -0,0 +1,13 @@
// function name: armatak_fnc_extract_marker_video_url
// function author: Codex
// function description: Gets the marker video URL configured in 3DEN for a vehicle
params ["_unit"];
private _videoUrl = _unit getVariable ["armatak_attribute_marker_video_url", ""];
if (isNil "_videoUrl") exitWith {
""
};
_videoUrl

View File

@@ -7,8 +7,15 @@ params["_unit"];
private _affiliation = "f";
private _type = "G";
private _role = "a-f-G-U-C-I";
private _side = side _unit;
switch (str side _unit) do {
if (isNil {
_unit getVariable "armatak_current_side"
}) then {
_side = _unit getVariable "armatak_current_side";
};
switch (str _side) do {
case "WEST": {
_affiliation = "f";
};
@@ -22,7 +29,7 @@ switch (str side _unit) do {
_affiliation = "u";
};
default {
_affiliation = "f";
_affiliation = "u";
};
};
@@ -110,7 +117,6 @@ if ((typeOf (vehicle _unit) != typeOf _unit) or ((_unit_type select 0) == "Vehic
_role = "a-" + _affiliation + "-" + _type;
armatak_attribute_marker_type = _unit getVariable "armatak_attribute_marker_type";
if (!isNil "armatak_attribute_marker_type" or armatak_attribute_marker_type != '') then {

View File

@@ -0,0 +1,27 @@
params["_unit"];
_target = getSensorTargets (_unit);
{
_unit = _x select 0;
_position = _x select 1;
_status = _x select 2;
if (isNil {
_unit getVariable "armatak_current_side"
}) then {
_unit setVariable ["armatak_current_side", side _unit];
};
if (_status != "destroyed" && !(_unit in armatak_server_syncedUnits)) then {
_unit_position = _unit call armatak_client_fnc_extractClientPosition;
_uuid = _unit call armatak_fnc_extract_uuid;
_type = _unit call armatak_fnc_extract_role;
_callsign = getText (configOf _unit >> "displayName");
_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:cot:marker", [_marker_cot]];
};
} forEach _target;

View File

@@ -12,10 +12,14 @@ if (roleDescription _unit != "") then {
_callsign = name _unit;
if (_callsign == "Error: No unit") then {
_callsign = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "displayName");
_callsign = getText (configOf _unit >> "displayName");
};
};
if (side _unit == east) 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 {

View File

@@ -1,3 +1,3 @@
params[_type, _message];
params["_type", "_message"];
"armatak" callExtension ["log", [_type, _message]]

View File

@@ -0,0 +1,23 @@
params["_latitude", "_longitude", "_altitude"];
_playerPosition = [_latitude, _longitude, _altitude];
_playerLatitude = _playerPosition select 0;
_playerLongitude = _playerPosition select 1;
_playerMaxLatitude = 20480;
_playerMaxLongitude = 20480;
_MapMaxLongitude = 33.728772;
_MapMinLongitude = 33.542815;
_MapMaxLatitude = 63.169746;
_MapMinLatitude = 62.938820;
_LongitudeDifference = _MapMaxLongitude - _MapMinLongitude;
_LatitudeDifference = _MapMaxLatitude - _MapMinLatitude;
_RealLongitude = (_playerLongitude / _playerMaxLongitude) * _LongitudeDifference + _MapMinLongitude;
_RealLatitude = (_playerLatitude / _playerMaxLatitude) * _LatitudeDifference + _MapMinLatitude;
[_RealLongitude, _RealLatitude, _playerPosition select 2]

View File

@@ -0,0 +1,23 @@
params["_latitude", "_longitude", "_altitude"];
_playerPosition = [_latitude, _longitude, _altitude];
_playerLatitude = _playerPosition select 0;
_playerLongitude = _playerPosition select 1;
_playerMaxLatitude = 20480;
_playerMaxLongitude = 20480;
_MapMaxLatitude = -67.765153;
_MapMinLatitude = -68.223664;
_MapMaxLongitude = 10.593815;
_MapMinLongitude = 10.137466;
_LongitudeDifference = _MapMaxLongitude - _MapMinLongitude;
_LatitudeDifference = _MapMaxLatitude - _MapMinLatitude;
_RealLongitude = (_playerLongitude / _playerMaxLongitude) * _LongitudeDifference + _MapMinLongitude;
_RealLatitude = (_playerLatitude / _playerMaxLatitude) * _LatitudeDifference + _MapMinLatitude;
[_RealLongitude, _RealLatitude, _playerPosition select 2]

View File

@@ -0,0 +1,30 @@
params ["_longitudeInGame", "_latitudeInGame", "_altitude"];
private _mapWidth = 8192;
private _mapHeight = 8192;
// SW corner (used as origin)
private _SW_lat = 63.005389;
private _SW_lon = 22.638957;
// SE corner
private _SE_lat = 63.010092;
private _SE_lon = 22.800107;
// NW corner
private _NW_lat = 63.078713;
private _NW_lon = 22.628542;
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]

View File

@@ -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]

View File

@@ -0,0 +1,23 @@
params["_latitude", "_longitude", "_altitude"];
_playerPosition = [_latitude, _longitude, _altitude];
_playerLatitude = _playerPosition select 0;
_playerLongitude = _playerPosition select 1;
_playerMaxLongitude = 4992;
_playerMaxLatitude = 4992;
_MapMaxLongitude = -99.722665;
_MapMinLongitude = -99.775505;
_MapMaxLatitude = 32.159272;
_MapMinLatitude = 32.114011;
_LongitudeDifference = _MapMaxLongitude - _MapMinLongitude;
_LatitudeDifference = _MapMaxLatitude - _MapMinLatitude;
_RealLongitude = (_playerLongitude / _playerMaxLongitude) * _LongitudeDifference + _MapMinLongitude;
_RealLatitude = (_playerLatitude / _playerMaxLatitude) * _LatitudeDifference + _MapMinLatitude;
[_RealLongitude, _RealLatitude, _playerPosition select 2]

View File

@@ -0,0 +1,30 @@
params ["_longitudeInGame", "_latitudeInGame", "_altitude"];
private _mapWidth = 11264;
private _mapHeight = 11264;
// SW corner (used as origin)
private _SW_lat = -51.736078;
private _SW_lon = -57.915032;
// SE corner
private _SE_lat = -51.736078;
private _SE_lon = -58.077879;
// NW corner
private _NW_lat = -51.634750;
private _NW_lon = -58.077879;
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]

View File

@@ -0,0 +1,30 @@
params ["_longitudeInGame", "_latitudeInGame", "_altitude"];
private _mapWidth = 16384;
private _mapHeight = 16384;
// SW corner (used as origin)
private _SW_lat = -51.806546;
private _SW_lon = -57.939747;
// SE corner
private _SE_lat = -51.806546;
private _SE_lon = -57.701978;
// NW corner
private _NW_lat = -51.658913;
private _NW_lon = -57.939747;
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]

View File

@@ -0,0 +1,30 @@
params ["_longitudeInGame", "_latitudeInGame", "_altitude"];
private _mapWidth = 10240;
private _mapHeight = 10240;
// SW corner (used as origin)
private _SW_lat = -51.863358;
private _SW_lon = -59.054585;
// SE corner
private _SE_lat = -51.863358;
private _SE_lon = -58.906155;
// NW corner
private _NW_lat = -51.771493;
private _NW_lon = -59.054585;
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]

View File

@@ -0,0 +1,23 @@
params["_latitude", "_longitude", "_altitude"];
_playerPosition = [_latitude, _longitude, _altitude];
_playerLatitude = _playerPosition select 0;
_playerLongitude = _playerPosition select 1;
_playerMaxLongitude = 5120;
_playerMaxLatitude = 5120;
_MapMaxLatitude = -51.619725;
_MapMinLatitude = -51.664223;
_MapMaxLongitude = -58.394630;
_MapMinLongitude = -58.469580;
_LongitudeDifference = _MapMaxLongitude - _MapMinLongitude;
_LatitudeDifference = _MapMaxLatitude - _MapMinLatitude;
_RealLongitude = (_playerLongitude / _playerMaxLongitude) * _LongitudeDifference + _MapMinLongitude;
_RealLatitude = (_playerLatitude / _playerMaxLatitude) * _LatitudeDifference + _MapMinLatitude;
[_RealLongitude, _RealLatitude, _playerPosition select 2]

View File

@@ -0,0 +1,23 @@
params["_latitude", "_longitude", "_altitude"];
_playerPosition = [_latitude, _longitude, _altitude];
_playerLatitude = _playerPosition select 0;
_playerLongitude = _playerPosition select 1;
_playerMaxLatitude = 32768;
_playerMaxLongitude = 32768;
_MapMaxLongitude = 35.285485;
_MapMinLongitude = 34.927617;
_MapMaxLatitude = 70.445404;
_MapMinLatitude = 70.016783;
_LongitudeDifference = _MapMaxLongitude - _MapMinLongitude;
_LatitudeDifference = _MapMaxLatitude - _MapMinLatitude;
_RealLongitude = (_playerLongitude / _playerMaxLongitude) * _LongitudeDifference + _MapMinLongitude;
_RealLatitude = (_playerLatitude / _playerMaxLatitude) * _LatitudeDifference + _MapMinLatitude;
[_RealLongitude, _RealLatitude, _playerPosition select 2]

View File

@@ -1,19 +1,19 @@
params ["_longitudeInGame", "_latitudeInGame", "_altitude"];
private _mapWidth = 30720;
private _mapHeight = 30720;
private _mapWidth = 8192;
private _mapHeight = 8192;
// SW corner (used as origin)
private _SW_lat = 39.456910;
private _SW_lon = 24.940792;
private _SW_lat = 39.458019;
private _SW_lon = 24.939314;
// SE corner
private _SE_lat = 39.459151;
private _SE_lon = 25.083440;
private _SE_lat = 39.458019;
private _SE_lon = 25.081992;
// NW corner
private _NW_lat = 39.567714;
private _NW_lon = 24.937866;
private _NW_lat = 39.568847;
private _NW_lon = 24.939314;
private _edgeSE_lat = _SE_lat - _SW_lat;
private _edgeSE_lon = _SE_lon - _SW_lon;

View File

@@ -1,19 +1,19 @@
params ["_longitudeInGame", "_latitudeInGame", "_altitude"];
private _mapWidth = 30720;
private _mapHeight = 30720;
private _mapWidth = 15360;
private _mapHeight = 15360;
// SW corner (used as origin)
private _SW_lat = -19.086825;
private _SW_lon = 176.812772;
private _SW_lat = -19.086803;
private _SW_lon = 176.812619;
// SE corner
private _SE_lat = -19.086825;
private _SE_lon = 178.687920;
private _SE_lat = -19.086803;
private _SE_lon = 178.704583;
// NW corner
private _NW_lat = -17.196898;
private _NW_lon = 176.812622;
private _NW_lat = -17.196900;
private _NW_lon = 176.812619;
private _edgeSE_lat = _SE_lat - _SW_lat;
private _edgeSE_lon = _SE_lon - _SW_lon;

View File

@@ -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]

View File

@@ -1,42 +1,28 @@
class CfgVehicles {
class Logic;
class Module_F : Logic
{
class AttributesBase
{
class Default;
class Logic;
class Module_F : Logic {
class AttributesBase {
class Edit;
class Combo;
class Checkbox;
class CheckboxNumber;
class ModuleDescription;
class Units;
};
class ModuleDescription
{
class AnyBrain;
};
class ModuleDescription;
};
class GVAR(moduleBase): Module_F {
author = PROJECT_AUTHOR;
category = QEGVAR(main,moduleCategory);
function = QUOTE({});
functionPriority = 1;
isGlobal = 1;
isTriggerActivated = 0;
scope = 1;
scopeCurator = 2;
};
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;
class GVAR(connectionModuleBase): GVAR(moduleBase) {
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;
@@ -47,19 +33,25 @@ class CfgVehicles {
canSetArea = 0;
canSetAreaShape = 0;
canSetAreaHeight = 0;
};
class GVAR(tcpModule): GVAR(connectionModuleBase) {
scope = 2;
displayName = "CoT Router (TCP)";
function = QFUNC(3denTcpModuleConfig);
class Attributes: AttributesBase {
class GVAR(moduleInstanceAddress): Edit {
property = QGVAR(moduleInstanceAddress);
displayname = "TAK Server Address";
tooltip = "TAK Server Instance Address";
displayName = "TAK Server Address";
tooltip = "Hostname or IP address for the TAK or IronTAK server.";
typeName = "STRING";
defaultValue = "localhost";
defaultValue = "'localhost'";
};
class GVAR(moduleInstancePort): Edit {
property = QGVAR(moduleInstancePort);
displayname = "TAK Server TCP Port";
tooltip = "TAK Server instance Port for TCP connection";
displayName = "TAK Server TCP Port";
tooltip = "Port for the unauthenticated TCP socket.";
typeName = "NUMBER";
defaultValue = "8088";
};
@@ -67,24 +59,75 @@ class CfgVehicles {
};
class ModuleDescription: ModuleDescription {
description = "Generate the initial ARMATAK configuration, syncronizing all players to the TAK server instance";
description = "Connect ArmaTAK to a TAK server over plain TCP.";
sync[] = {"LocationArea_F"};
};
};
class GVAR(coreModuleCurator): GVAR(coreModule) {
class GVAR(enrollModule): GVAR(connectionModuleBase) {
scope = 2;
displayName = "CoT Router (Authenticated)";
function = QFUNC(3denEnrollModuleConfig);
class Attributes: AttributesBase {
class GVAR(moduleInstanceAddress): Edit {
property = QGVAR(moduleInstanceAddress);
displayname = "TAK Server Address";
tooltip = "Hostname or IP address used for enrollment and the final TLS connection.";
typeName = "STRING";
defaultValue = "'localhost'";
};
class GVAR(moduleEnrollmentPort): Edit {
property = QGVAR(moduleEnrollmentPort);
displayName = "Enrollment HTTPS Port";
tooltip = "Port used for GET /Marti/api/tls/config and POST /Marti/api/tls/signClient/v2.";
typeName = "NUMBER";
defaultValue = "8446";
};
class GVAR(moduleEnrollmentUsername): Edit {
property = QGVAR(moduleEnrollmentUsername);
displayName = "Enrollment Username";
tooltip = "Username used in Basic Auth for client certificate enrollment.";
typeName = "STRING";
defaultValue = "''";
};
class GVAR(moduleEnrollmentPassword): Edit {
property = QGVAR(moduleEnrollmentPassword);
displayName = "Enrollment Password";
tooltip = "Password used in Basic Auth for client certificate enrollment.";
typeName = "STRING";
defaultValue = "''";
};
class ModuleDescription: ModuleDescription {};
};
class ModuleDescription: ModuleDescription {
description = "Enroll a client certificate and connect ArmaTAK over mTLS.";
sync[] = {"LocationArea_F"};
};
};
class GVAR(tcpModuleCurator): GVAR(tcpModule) {
scope = 1;
scopeCurator = 2;
function = "";
displayName = "CoT Router (Zeus)";
curatorInfoType = "armatak_zeus_core_module_dialog";
displayName = "CoT Router (TCP, Zeus)";
curatorInfoType = "armatak_zeus_tcp_module_dialog";
};
class GVAR(enrollModuleCurator): GVAR(enrollModule) {
scope = 1;
scopeCurator = 2;
function = "";
displayName = "CoT Router (Authenticated, Zeus)";
curatorInfoType = "armatak_zeus_enroll_module_dialog";
};
class GVAR(markEntity): GVAR(moduleBase) {
curatorCanAttach = 1;
category = QEGVAR(main,moduleCategory);
curatorCanAttach = 1;
category = QEGVAR(main,moduleCategory);
displayname = "Mark Entity";
function = QFUNC(routerEntityAdd);
icon = "\a3\Modules_F_Curator\Data\iconRadio_ca.paa";
};
function = QFUNC(routerEntityAdd);
icon = "\a3\Modules_F_Curator\Data\iconRadio_ca.paa";
};
};

View File

@@ -1,4 +1,7 @@
PREP(3denCoreModuleConfig);
PREP(3denEnrollModuleConfig);
PREP(3denTcpModuleConfig);
PREP(routerEntityAdd);
PREP(routerEntityRemove);
PREP(ZeusCoreModuleConfig);
PREP(startCotRouter);
PREP(ZeusEnrollModuleConfig);
PREP(ZeusTcpModuleConfig);

View File

@@ -4,8 +4,10 @@ class CfgPatches {
class ADDON {
name = COMPONENT_NAME;
units[] = {
QGVAR(coreModule),
QGVAR(coreModuleCurator),
QGVAR(tcpModule),
QGVAR(tcpModuleCurator),
QGVAR(enrollModule),
QGVAR(enrollModuleCurator),
QGVAR(markEntity)
};
weapons[] = {};

View File

@@ -1,104 +1,174 @@
class RscObject;
class RscText;
class RscFrame;
class RscLine;
class RscProgress;
class RscPicture;
class RscBackground;
class RscPictureKeepAspect;
class RscVideo;
class RscHTML;
class RscButton;
class RscShortcutButton;
class RscEdit;
class RscCombo;
class RscListBox;
class RscListNBox;
class RscXListBox;
class RscTree;
class RscSlider;
class RscXSliderH;
class RscActiveText;
class RscActivePicture;
class RscActivePictureKeepAspect;
class RscStructuredText;
class RscToolbox;
class RscControlsGroup;
class RscControlsGroupNoScrollbars;
class RscControlsGroupNoHScrollbars;
class RscControlsGroupNoVScrollbars;
class RscButtonTextOnly;
class RscButtonMenu;
class RscButtonMenuOK;
class RscButtonMenuCancel;
class RscButtonMenuSteam;
class RscMapControl;
class RscMapControlEmpty;
class RscCheckBox;
class armatak_zeus_core_module_dialog {
class armatak_zeus_tcp_module_dialog {
idd = 999991;
movingEnable = 0;
class ControlsBackground {
class armatak_gui_module_zeus_core_dialog_main_frame: RscBackground {
class main_frame: RscBackground {
idc = 1800;
x = "0.386562 * safezoneW + safezoneX";
y = "0.401 * safezoneH + safezoneY";
y = "0.29 * safezoneH + safezoneY";
w = "0.216563 * safezoneW";
h = "0.242 * safezoneH";
colorBackground[]={0,0,0,0.45};
h = "0.32 * 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 {
class address_text: RscText {
idc = 1000;
text = "TAK Server Address";
x = "0.391719 * safezoneW + safezoneX";
y = "0.412 * safezoneH + safezoneY";
y = "0.332 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.033 * safezoneH";
};
class armatak_gui_module_zeus_core_dialog_address_port_text: RscText {
class address_edit: RscEdit {
idc = 14000;
text = "localhost";
x = "0.391719 * safezoneW + safezoneX";
y = "0.365 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.044 * safezoneH";
colorBackground[] = {0,0,0,0.5};
};
class port_text: RscText {
idc = 1001;
text = "TAK Server Port";
x = "0.391719 * safezoneW + safezoneX";
y = "0.489 * safezoneH + safezoneY";
y = "0.425 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.033 * safezoneH";
};
class armatak_gui_module_zeus_core_dialog_address_button_cancel: RscButton {
class port_edit: RscEdit {
idc = 14001;
text = "8088";
x = "0.391719 * safezoneW + safezoneX";
y = "0.458 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.044 * safezoneH";
colorBackground[] = {0,0,0,0.5};
};
class button_cancel: RscButton {
idc = 1601;
text = "Cancel";
action = "closeDialog 2;";
x = "0.551563 * safezoneW + safezoneX";
y = "0.577 * safezoneH + safezoneY";
y = "0.535 * safezoneH + safezoneY";
w = "0.0464063 * safezoneW";
h = "0.055 * safezoneH";
};
class armatak_gui_module_zeus_core_dialog_address_button_ok: RscButton {
class button_ok: RscButton {
idc = 1600;
text = "Ok";
action = QUOTE(call FUNC(zeusCoreModuleConfig));
action = QUOTE(call FUNC(ZeusTcpModuleConfig));
x = "0.5 * safezoneW + safezoneX";
y = "0.577 * safezoneH + safezoneY";
y = "0.535 * safezoneH + safezoneY";
w = "0.0464063 * safezoneW";
h = "0.055 * safezoneH";
};
};
};
class armatak_zeus_enroll_module_dialog {
idd = 999992;
movingEnable = 0;
class ControlsBackground {
class main_frame: RscBackground {
idc = 1810;
x = "0.386562 * safezoneW + safezoneX";
y = "0.2 * safezoneH + safezoneY";
w = "0.216563 * safezoneW";
h = "0.52 * safezoneH";
colorBackground[] = {0,0,0,0.45};
};
};
class Controls {
class address_text: RscText {
idc = 1010;
text = "TAK Server Address";
x = "0.391719 * safezoneW + safezoneX";
y = "0.242 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.033 * safezoneH";
};
class address_edit: RscEdit {
idc = 14100;
text = "localhost";
x = "0.391719 * safezoneW + safezoneX";
y = "0.275 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.044 * safezoneH";
colorBackground[] = {0,0,0,0.5};
};
class enroll_port_text: RscText {
idc = 1011;
text = "Enrollment HTTPS Port";
x = "0.391719 * safezoneW + safezoneX";
y = "0.335 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.033 * safezoneH";
};
class enroll_port_edit: RscEdit {
idc = 14101;
text = "8446";
x = "0.391719 * safezoneW + safezoneX";
y = "0.368 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.044 * safezoneH";
colorBackground[] = {0,0,0,0.5};
};
class username_text: RscText {
idc = 1012;
text = "Enrollment Username";
x = "0.391719 * safezoneW + safezoneX";
y = "0.428 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.033 * safezoneH";
};
class username_edit: RscEdit {
idc = 14102;
text = "";
x = "0.391719 * safezoneW + safezoneX";
y = "0.461 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.044 * safezoneH";
colorBackground[] = {0,0,0,0.5};
};
class password_text: RscText {
idc = 1013;
text = "Enrollment Password";
x = "0.391719 * safezoneW + safezoneX";
y = "0.521 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.033 * safezoneH";
};
class password_edit: RscEdit {
idc = 14103;
text = "";
x = "0.391719 * safezoneW + safezoneX";
y = "0.554 * safezoneH + safezoneY";
w = "0.20625 * safezoneW";
h = "0.044 * safezoneH";
colorBackground[] = {0,0,0,0.5};
};
class button_cancel: RscButton {
idc = 1611;
text = "Cancel";
action = "closeDialog 2;";
x = "0.551563 * safezoneW + safezoneX";
y = "0.645 * safezoneH + safezoneY";
w = "0.0464063 * safezoneW";
h = "0.055 * safezoneH";
};
class button_ok: RscButton {
idc = 1610;
text = "Ok";
action = QUOTE(call FUNC(ZeusEnrollModuleConfig));
x = "0.5 * safezoneW + safezoneX";
y = "0.645 * safezoneH + safezoneY";
w = "0.0464063 * safezoneW";
h = "0.055 * safezoneH";
};
@@ -110,7 +180,7 @@ class armatak_zeus_custom_marker_dialog {
movingEnable = 0;
class Controls {
class RscFrame_1800: RscFrame
class RscFrame_1800: RscBackground
{
idc = 1800;
x = "0.37625 * safezoneW + safezoneX";

View File

@@ -1,56 +0,0 @@
#include "..\script_component.hpp"
params [
["_logic", objNull, [objNull]],
["_units", [], [[]]],
["_activated", true, [true]]
];
if (isServer) exitWith {
["Connecting to TCP Socket", "success", "TCP Socket"] call EFUNC(main,notify);
_tak_server_instance_address = _logic getVariable QGVAR(moduleInstanceAddress);
_tak_server_instance_port = _logic getVariable QGVAR(moduleInstancePort);
_tak_server_fulladdress = _tak_server_instance_address + ":" + (str _tak_server_instance_port);
missionNamespace setVariable ["armatak_server_instance", _tak_server_fulladdress];
missionNamespace setVariable ["armatak_tcp_socket_is_running", true];
missionNamespace setVariable ["armatak_group_colors", ["White", "Yellow", "Orange", "Magenta", "Red", "Maroon", "Purple", "DarkBlue", "Blue", "Cyan", "Teal", "Green", "DarkGreen", "Brown"]];
"armatak" callExtension ["tcp_socket:start", [_tak_server_fulladdress]];
_syncUnits = synchronizedObjects _logic;
missionNamespace setVariable ["armatak_marked_units", _syncUnits];
GVAR(syncedUnits) = missionNamespace getVariable "armatak_marked_units";
[{
GVAR(syncedUnits) = missionNamespace getVariable "armatak_marked_units";
{
_objectType = _x call BIS_fnc_objectType;
if ((_objectType select 0) == "Soldier") then {
_callsign = [_x] call armatak_fnc_extract_unit_callsign;
_group_name = [group _x] call armatak_fnc_extract_group_color;
_group_role = [_x] call armatak_fnc_extract_group_role;
[_x, _callsign, _group_name, _group_role] call armatak_fnc_send_eud_cot;
[_x] call armatak_fnc_send_digital_pointer_cot;
};
if ((_objectType select 0) == "Vehicle") then {
_atak_type = [_x] call armatak_fnc_extract_role;
_callsign = [_x] call armatak_fnc_extract_marker_callsign;
[_x, _atak_type, _callsign] call armatak_fnc_send_marker_cot;
};
if (unitIsUAV _x) then {
[_x] call armatak_fnc_send_drone_cot;
[_x] call armatak_fnc_send_digital_pointer_cot;
};
} forEach GVAR(syncedUnits);
}, 2, []] call CBA_fnc_addPerFrameHandler;
};
true;

View File

@@ -0,0 +1,37 @@
#include "..\script_component.hpp"
params [
["_logic", objNull, [objNull]],
["_units", [], [[]]],
["_activated", true, [true]]
];
if (isServer) exitWith {
if (missionNamespace getVariable ["armatak_tcp_socket_is_running", false]) exitWith {
["Socket was called twice", "error", "TCP Socket"] call EFUNC(main,notify);
};
["Connecting to authenticated TAK socket", "success", "TCP Socket"] call EFUNC(main,notify);
_tak_server_instance_address = _logic getVariable [QGVAR(moduleInstanceAddress), "localhost"];
_tak_server_enrollment_port = _logic getVariable [QGVAR(moduleEnrollmentPort), 8446];
_tak_server_enrollment_username = _logic getVariable [QGVAR(moduleEnrollmentUsername), ""];
_tak_server_enrollment_password = _logic getVariable [QGVAR(moduleEnrollmentPassword), ""];
"armatak" callExtension [
"tcp_socket:start_enroll_mtls",
[
_tak_server_instance_address,
_tak_server_instance_address,
str _tak_server_enrollment_port,
_tak_server_enrollment_username,
_tak_server_enrollment_password,
""
]
];
missionNamespace setVariable ["armatak_server_syncedUnits", synchronizedObjects _logic];
_tak_server_instance_address call FUNC(startCotRouter);
};
true

View File

@@ -0,0 +1,26 @@
#include "..\script_component.hpp"
params [
["_logic", objNull, [objNull]],
["_units", [], [[]]],
["_activated", true, [true]]
];
if (isServer) exitWith {
if (missionNamespace getVariable ["armatak_tcp_socket_is_running", false]) exitWith {
["Socket was called twice", "error", "TCP Socket"] call EFUNC(main,notify);
};
["Connecting to TCP Socket", "success", "TCP Socket"] call EFUNC(main,notify);
_tak_server_instance_address = _logic getVariable [QGVAR(moduleInstanceAddress), "localhost"];
_tak_server_instance_port = _logic getVariable [QGVAR(moduleInstancePort), 8088];
_tak_server_fulladdress = _tak_server_instance_address + ":" + (str _tak_server_instance_port);
"armatak" callExtension ["tcp_socket:start", [_tak_server_fulladdress]];
missionNamespace setVariable ["armatak_server_syncedUnits", synchronizedObjects _logic];
_tak_server_fulladdress call FUNC(startCotRouter);
};
true

View File

@@ -1,60 +0,0 @@
#include "..\script_component.hpp"
params ["_logic"];
_socket_is_running = missionNamespace getVariable ["armatak_tcp_socket_is_running", false];
if (_socket_is_running) exitWith {
["Socket was called twice","error", "TCP Socket"] call EFUNC(main,notify);
closeDialog 1;
};
disableSerialization;
["Connecting to TCP Socket", "success", "TCP Socket"] call EFUNC(main,notify);
_tak_server_instance_address = ctrlText 14000;
_tak_server_instance_port = ctrlText 14001;
_tak_server_fulladdress = ((_tak_server_instance_address) + ":" + (_tak_server_instance_port));
missionNamespace setVariable ["armatak_server_instance", _tak_server_fulladdress];
missionNamespace setVariable ["armatak_tcp_socket_is_running", true];
missionNamespace setVariable ["armatak_group_colors", ["White", "Yellow", "Orange", "Magenta", "Red", "Maroon", "Purple", "DarkBlue", "Blue", "Cyan", "Teal", "Green", "DarkGreen", "Brown"]];
"armatak" callExtension ["tcp_socket:start", [_tak_server_fulladdress]];
_syncUnits = [];
missionNamespace setVariable ["armatak_marked_units", _syncUnits];
GVAR(syncedUnits) = missionNamespace getVariable "armatak_marked_units";
[{
GVAR(syncedUnits) = missionNamespace getVariable "armatak_marked_units";
{
_objectType = _x call BIS_fnc_objectType;
if ((_objectType select 0) == "Soldier") then {
_callsign = [_x] call armatak_fnc_extract_unit_callsign;
_group_name = [group _x] call armatak_fnc_extract_group_color;
_group_role = [_x] call armatak_fnc_extract_group_role;
[_x, _callsign, _group_name, _group_role] call armatak_fnc_send_eud_cot;
[_x] call armatak_fnc_send_digital_pointer_cot;
};
if ((_objectType select 0) == "Vehicle") then {
_atak_type = [_x] call armatak_fnc_extract_role;
_callsign = [_x] call armatak_fnc_extract_marker_callsign;
[_x, _atak_type, _callsign] call armatak_fnc_send_marker_cot;
};
if (unitIsUAV _x) then {
[_x] call armatak_fnc_send_drone_cot;
[_x] call armatak_fnc_send_digital_pointer_cot;
};
} forEach GVAR(syncedUnits);
}, 2, []] call CBA_fnc_addPerFrameHandler;
deleteVehicle _logic;
closeDialog 1;

View File

@@ -0,0 +1,33 @@
#include "..\script_component.hpp"
params ["_logic"];
if (missionNamespace getVariable ["armatak_tcp_socket_is_running", false]) exitWith {
["Socket was called twice", "error", "TCP Socket"] call EFUNC(main,notify);
closeDialog 1;
};
disableSerialization;
["Connecting to authenticated TAK socket", "success", "TCP Socket"] call EFUNC(main,notify);
_tak_server_instance_address = ctrlText 14100;
_tak_server_enrollment_port = ctrlText 14101;
_tak_server_enrollment_username = ctrlText 14102;
_tak_server_enrollment_password = ctrlText 14103;
"armatak" callExtension [
"tcp_socket:start_enroll_mtls",
[
_tak_server_instance_address,
_tak_server_instance_address,
_tak_server_enrollment_port,
_tak_server_enrollment_username,
_tak_server_enrollment_password,
""
]
];
_tak_server_instance_address call FUNC(startCotRouter);
deleteVehicle _logic;
closeDialog 1;

View File

@@ -0,0 +1,22 @@
#include "..\script_component.hpp"
params ["_logic"];
if (missionNamespace getVariable ["armatak_tcp_socket_is_running", false]) 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;
"armatak" callExtension ["tcp_socket:start", [_tak_server_fulladdress]];
_tak_server_fulladdress call FUNC(startCotRouter);
deleteVehicle _logic;
closeDialog 1;

View File

@@ -20,19 +20,24 @@ 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);
deleteVehicle _logic;
};
default {
GVAR(syncedUnits) = missionNamespace getVariable "armatak_marked_units";
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_marked_units", GVAR(syncedUnits)];
missionNamespace setVariable ["armatak_server_syncedUnits", GVAR(syncedUnits)];
SETVAR(_unit,GVAR(isRouting),true);
deleteVehicle _logic;
};

View File

@@ -34,7 +34,8 @@ switch (false) do {
};
} forEach GVAR(syncedUnits);
missionNmaespace setVariable ["armatak_marked_units", GVAR(syncedUnits)];
missionNamespace setVariable ["armatak_server_syncedUnits", GVAR(syncedUnits)];
SETVAR(_unit,GVAR(isRouting),false);
deleteVehicle _logic;
};

View File

@@ -0,0 +1,47 @@
#include "..\script_component.hpp"
params [["_server_instance", "", [""]]];
missionNamespace setVariable ["armatak_server_instance", _server_instance];
missionNamespace setVariable ["armatak_tcp_socket_is_running", true];
if (isNil { missionNamespace getVariable "armatak_server_syncedUnits" }) then {
missionNamespace setVariable ["armatak_server_syncedUnits", []];
};
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;
_x call armatak_fnc_extract_sensor_data;
};
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;
_x call armatak_fnc_extract_sensor_data;
};
};
} forEach GVAR(syncedUnits);
}, 1, []] call CBA_fnc_addPerFrameHandler;
true

View File

@@ -1 +0,0 @@
armatak\armatak\addons\video

View File

@@ -1,11 +0,0 @@
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));
};
};

View File

@@ -1,72 +0,0 @@
class CfgVehicles {
class Logic;
class Module_F : Logic
{
class AttributesBase
{
class Default;
class Edit;
class Combo;
class Checkbox;
class CheckboxNumber;
class ModuleDescription;
class Units;
};
class ModuleDescription
{
class AnyBrain;
};
};
class EGVAR(server,moduleBase);
class GVAR(videoModule): EGVAR(server,moduleBase) {
scope = 2;
scopeCurator = 0;
displayname = "Video Streaming Handler";
icon = "\a3\Modules_F_Curator\Data\iconRadio_ca.paa";
category = QEGVAR(main,moduleCategory);
function = QFUNC(videoParser);
functionPriority = 1;
isGlobal = 0;
isTriggerActivated = 1;
isDisposable = 1;
is3den = 0;
curatorCanAttach = 0;
curatorInfoType = "RscDisplayAttributeModuleNuke";
canSetArea = 0;
canSetAreaShape = 0;
canSetAreaHeight = 0;
class Attributes: AttributesBase {
class GVAR(instanceAddress): Edit {
property = QGVAR(instanceAddress);
displayname = "MediaMTX Provider Address";
tooltip = "MediaMTX Provider Instance Address";
typeName = "STRING";
defaultValue = "localhost";
};
class GVAR(instancePort): Edit {
property = "armatak_module_mediamtx_video_stream_instance_port";
displayname = "MediaMTX Provider Port";
tooltip = "MediaMTX Provider Port for handling video streams";
typeName = "STRING";
defaultValue = "8554";
};
class GVAR(instanceAuthUser): Edit {
property = QGVAR(instanceAuthUser);
displayname = "MediaMTX Provider Username";
tooltip = "MediaMTX Provider Instance Username";
typeName = "STRING";
defaultValue = "administrator";
};
class GVAR(instanceAuthPassword): Edit {
property = QGVAR(instanceAuthPassword);
displayname = "MediaMTX Provider Password";
tooltip = "MediaMTX Provider Instance Password";
typeName = "STRING";
defaultValue = "password";
};
};
};
};

View File

@@ -1 +0,0 @@
PREP(videoParser);

View File

@@ -1,9 +0,0 @@
#include "script_component.hpp"
ADDON = false;
PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;
ADDON = true;

View File

@@ -1,3 +0,0 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

View File

@@ -1,42 +0,0 @@
#include "script_component.hpp"
class CfgPatches {
class ADDON {
name = COMPONENT_NAME;
units[] = {
QGVAR(videoModule)
};
weapons[] = {};
requiredAddons[] = {
"cba_main",
"ace_main",
"armatak_main",
"armatak_server"
};
requiredVersion = REQUIRED_VERSION;
author = PROJECT_AUTHOR;
url = "https://github.com/valmojr/armatak";
};
};
class CfgMods {
class PREFIX {
name = "Arma Team Awareness Kit";
author = PROJECT_AUTHOR;
logo = "logo_ca.paa";
logoOver = "logo_hover_ca.paa";
tooltip = "ARMATAK";
tooltipOwned = "ARMATAK";
picture = "picture.paa";
actionName = "GitHub";
action = "https://github.com/valmojr/armatak";
overview = "ARMATAK Addons allows Arma 3 sessions to be parsed to TAK Clients";
hideName = 0;
hidePicture = 0;
dlcColor[] = { 0.23, 0.39, 0.30, 1 };
logoSmall = "logo_small_ca.paa";
};
};
#include "CfgEventHandlers.hpp"
#include "CfgVehicles.hpp"

View File

@@ -1,83 +0,0 @@
#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;

View File

@@ -1,17 +0,0 @@
#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
app/.gitignore vendored
View File

@@ -1 +0,0 @@
/build

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)
}

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

View File

@@ -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)
}
}

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>

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>

View File

@@ -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)
}
}

View File

@@ -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
}
}

View File

@@ -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
)
}
}
}
}

View File

@@ -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()
}
}
}

View File

@@ -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()
}
}

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}
}
}
}
}

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>

View File

@@ -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>

View File

@@ -1,5 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="60dp" android:tint="#6E3B23" android:viewportHeight="24" android:viewportWidth="24" android:width="60dp">
<path android:fillColor="@android:color/white" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

View File

@@ -1,5 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M16.01,7L16,3h-2v4h-4V3H8v4h-0.01C7,6.99 6,7.99 6,8.99v5.49L9.5,18v3h5v-3l3.5,-3.51v-5.5c0,-1 -1,-2 -1.99,-1.99z"/>
</vector>

View File

@@ -1,8 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:height="60dp" android:viewportHeight="32" android:viewportWidth="32" android:width="60dp">
<path android:fillColor="#000000" android:pathData="M20.992,20.163c-1.511,-0.099 -2.699,-1.349 -2.699,-2.877 0,-0.051 0.001,-0.102 0.004,-0.153l-0,0.007c-0.003,-0.048 -0.005,-0.104 -0.005,-0.161 0,-1.525 1.19,-2.771 2.692,-2.862l0.008,-0c1.509,0.082 2.701,1.325 2.701,2.847 0,0.062 -0.002,0.123 -0.006,0.184l0,-0.008c0.003,0.05 0.005,0.109 0.005,0.168 0,1.523 -1.191,2.768 -2.693,2.854l-0.008,0zM11.026,20.163c-1.511,-0.099 -2.699,-1.349 -2.699,-2.877 0,-0.051 0.001,-0.102 0.004,-0.153l-0,0.007c-0.003,-0.048 -0.005,-0.104 -0.005,-0.161 0,-1.525 1.19,-2.771 2.692,-2.862l0.008,-0c1.509,0.082 2.701,1.325 2.701,2.847 0,0.062 -0.002,0.123 -0.006,0.184l0,-0.008c0.003,0.048 0.005,0.104 0.005,0.161 0,1.525 -1.19,2.771 -2.692,2.862l-0.008,0zM26.393,6.465c-1.763,-0.832 -3.811,-1.49 -5.955,-1.871l-0.149,-0.022c-0.005,-0.001 -0.011,-0.002 -0.017,-0.002 -0.035,0 -0.065,0.019 -0.081,0.047l-0,0c-0.234,0.411 -0.488,0.924 -0.717,1.45l-0.043,0.111c-1.03,-0.165 -2.218,-0.259 -3.428,-0.259s-2.398,0.094 -3.557,0.275l0.129,-0.017c-0.27,-0.63 -0.528,-1.142 -0.813,-1.638l0.041,0.077c-0.017,-0.029 -0.048,-0.047 -0.083,-0.047 -0.005,0 -0.011,0 -0.016,0.001l0.001,-0c-2.293,0.403 -4.342,1.06 -6.256,1.957l0.151,-0.064c-0.017,0.007 -0.031,0.019 -0.04,0.034l-0,0c-2.854,4.041 -4.562,9.069 -4.562,14.496 0,0.907 0.048,1.802 0.141,2.684l-0.009,-0.11c0.003,0.029 0.018,0.053 0.039,0.07l0,0c2.14,1.601 4.628,2.891 7.313,3.738l0.176,0.048c0.008,0.003 0.018,0.004 0.028,0.004 0.032,0 0.06,-0.015 0.077,-0.038l0,-0c0.535,-0.72 1.044,-1.536 1.485,-2.392l0.047,-0.1c0.006,-0.012 0.01,-0.027 0.01,-0.043 0,-0.041 -0.026,-0.075 -0.062,-0.089l-0.001,-0c-0.912,-0.352 -1.683,-0.727 -2.417,-1.157l0.077,0.042c-0.029,-0.017 -0.048,-0.048 -0.048,-0.083 0,-0.031 0.015,-0.059 0.038,-0.076l0,-0c0.157,-0.118 0.315,-0.24 0.465,-0.364 0.016,-0.013 0.037,-0.021 0.059,-0.021 0.014,0 0.027,0.003 0.038,0.008l-0.001,-0c2.208,1.061 4.8,1.681 7.536,1.681s5.329,-0.62 7.643,-1.727l-0.107,0.046c0.012,-0.006 0.025,-0.009 0.04,-0.009 0.022,0 0.043,0.008 0.059,0.021l-0,-0c0.15,0.124 0.307,0.248 0.466,0.365 0.023,0.018 0.038,0.046 0.038,0.077 0,0.035 -0.019,0.065 -0.046,0.082l-0,0c-0.661,0.395 -1.432,0.769 -2.235,1.078l-0.105,0.036c-0.036,0.014 -0.062,0.049 -0.062,0.089 0,0.016 0.004,0.031 0.011,0.044l-0,-0.001c0.501,0.96 1.009,1.775 1.571,2.548l-0.04,-0.057c0.017,0.024 0.046,0.04 0.077,0.04 0.01,0 0.02,-0.002 0.029,-0.004l-0.001,0c2.865,-0.892 5.358,-2.182 7.566,-3.832l-0.065,0.047c0.022,-0.016 0.036,-0.041 0.039,-0.069l0,-0c0.087,-0.784 0.136,-1.694 0.136,-2.615 0,-5.415 -1.712,-10.43 -4.623,-14.534l0.052,0.078c-0.008,-0.016 -0.022,-0.029 -0.038,-0.036l-0,-0z"
tools:ignore="VectorPath" />
</vector>

View File

@@ -1,22 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:height="60dp" android:viewportHeight="24" android:viewportWidth="24" android:width="60dp">
<path android:fillColor="#FF000000" android:fillType="evenOdd" android:pathData="M12,0.296c-6.627,0 -12,5.372 -12,12c0,5.302 3.438,9.8 8.206,11.387c0.6,0.111 0.82,-0.26 0.82,-0.577c0,-0.286 -0.011,-1.231 -0.016,-2.234c-3.338,0.726 -4.043,-1.416 -4.043,-1.416C4.421,18.069 3.635,17.7 3.635,17.7c-1.089,-0.745 0.082,-0.729 0.082,-0.729c1.205,0.085 1.839,1.237 1.839,1.237c1.07,1.834 2.807,1.304 3.492,0.997C9.156,18.429 9.467,17.9 9.81,17.6c-2.665,-0.303 -5.467,-1.332 -5.467,-5.93c0,-1.31 0.469,-2.381 1.237,-3.221C5.455,8.146 5.044,6.926 5.696,5.273c0,0 1.008,-0.322 3.301,1.23C9.954,6.237 10.98,6.104 12,6.099c1.02,0.005 2.047,0.138 3.006,0.404c2.29,-1.553 3.297,-1.23 3.297,-1.23c0.653,1.653 0.242,2.873 0.118,3.176c0.769,0.84 1.235,1.911 1.235,3.221c0,4.609 -2.807,5.624 -5.479,5.921c0.43,0.372 0.814,1.103 0.814,2.222c0,1.606 -0.014,2.898 -0.014,3.293c0,0.319 0.216,0.694 0.824,0.576c4.766,-1.589 8.2,-6.085 8.2,-11.385C24,5.669 18.627,0.296 12,0.296z"
tools:ignore="VectorPath" />
<path android:fillColor="#FF000000" android:pathData="M4.545,17.526c-0.026,0.06 -0.12,0.078 -0.206,0.037c-0.087,-0.039 -0.136,-0.121 -0.108,-0.18c0.026,-0.061 0.12,-0.078 0.207,-0.037C4.525,17.384 4.575,17.466 4.545,17.526L4.545,17.526z"/>
<path android:fillColor="#FF000000" android:pathData="M5.031,18.068c-0.057,0.053 -0.169,0.028 -0.245,-0.055c-0.079,-0.084 -0.093,-0.196 -0.035,-0.249c0.059,-0.053 0.167,-0.028 0.246,0.056C5.076,17.903 5.091,18.014 5.031,18.068L5.031,18.068z"/>
<path android:fillColor="#FF000000" android:pathData="M5.504,18.759c-0.074,0.051 -0.194,0.003 -0.268,-0.103c-0.074,-0.107 -0.074,-0.235 0.002,-0.286c0.074,-0.051 0.193,-0.005 0.268,0.101C5.579,18.579 5.579,18.707 5.504,18.759L5.504,18.759z"/>
<path android:fillColor="#FF000000" android:pathData="M6.152,19.427c-0.066,0.073 -0.206,0.053 -0.308,-0.046c-0.105,-0.097 -0.134,-0.234 -0.068,-0.307c0.067,-0.073 0.208,-0.052 0.311,0.046C6.191,19.217 6.222,19.355 6.152,19.427L6.152,19.427z"/>
<path android:fillColor="#FF000000" android:pathData="M7.047,19.814c-0.029,0.094 -0.164,0.137 -0.3,0.097C6.611,19.87 6.522,19.76 6.55,19.665c0.028,-0.095 0.164,-0.139 0.301,-0.096C6.986,19.609 7.075,19.719 7.047,19.814L7.047,19.814z"/>
<path android:fillColor="#FF000000" android:pathData="M8.029,19.886c0.003,0.099 -0.112,0.181 -0.255,0.183c-0.143,0.003 -0.26,-0.077 -0.261,-0.174c0,-0.1 0.113,-0.181 0.256,-0.184C7.912,19.708 8.029,19.788 8.029,19.886L8.029,19.886z"/>
<path android:fillColor="#FF000000" android:pathData="M8.943,19.731c0.017,0.096 -0.082,0.196 -0.224,0.222c-0.139,0.026 -0.268,-0.034 -0.286,-0.13c-0.017,-0.099 0.084,-0.198 0.223,-0.224C8.797,19.574 8.925,19.632 8.943,19.731L8.943,19.731z"/>
</vector>

View File

@@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@@ -1,30 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@@ -1,8 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:height="30dp" android:viewportHeight="24" android:viewportWidth="24" android:width="30dp">
<path android:fillColor="#FF000000" android:pathData="m12.707,12.707l-2.293,2.293 -1.414,-1.414 2.293,-2.293c0.391,-0.391 0.391,-1.023 0,-1.414s-1.023,-0.391 -1.414,0l-2.293,2.293 -1.879,-1.879c-0.391,-0.391 -1.023,-0.391 -1.414,0s-0.391,1.023 0,1.414l0.352,0.352 -1.134,1.135c-1.77,1.769 -1.982,4.515 -0.638,6.519l-2.58,2.58c-0.391,0.391 -0.391,1.023 0,1.414 0.195,0.195 0.451,0.293 0.707,0.293s0.512,-0.098 0.707,-0.293l2.58,-2.58c0.865,0.58 1.868,0.871 2.871,0.871 1.321,0 2.642,-0.503 3.647,-1.509l1.135,-1.134 0.352,0.352c0.195,0.195 0.451,0.293 0.707,0.293s0.512,-0.098 0.707,-0.293c0.391,-0.391 0.391,-1.023 0,-1.414l-1.879,-1.879 2.293,-2.293c0.391,-0.391 0.391,-1.023 0,-1.414s-1.023,-0.391 -1.414,0ZM23.707,0.293c-0.391,-0.391 -1.023,-0.391 -1.414,0l-2.58,2.58c-2.004,-1.344 -4.749,-1.132 -6.519,0.638l-1.135,1.135 -0.353,-0.353c-0.391,-0.391 -1.023,-0.391 -1.414,0s-0.391,1.023 0,1.414l8,8c0.195,0.195 0.451,0.293 0.707,0.293s0.512,-0.098 0.707,-0.293c0.391,-0.391 0.391,-1.023 0,-1.414l-0.353,-0.353 1.135,-1.135c1.77,-1.769 1.982,-4.515 0.638,-6.519l2.58,-2.58c0.391,-0.391 0.391,-1.023 0,-1.414Z"
tools:ignore="VectorPath" />
</vector>

View File

@@ -1,8 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:height="60dp" android:viewportHeight="32" android:viewportWidth="32" android:width="60dp">
<path android:fillColor="#000000" android:pathData="M18.102,12.129c0,-0 0,-0 0,-0.001 0,-1.564 1.268,-2.831 2.831,-2.831s2.831,1.268 2.831,2.831c0,1.564 -1.267,2.831 -2.831,2.831 -0,0 -0,0 -0.001,0h0c-0,0 -0,0 -0.001,0 -1.563,0 -2.83,-1.267 -2.83,-2.83 0,-0 0,-0 0,-0.001v0zM24.691,12.135c0,-2.081 -1.687,-3.768 -3.768,-3.768s-3.768,1.687 -3.768,3.768c0,2.081 1.687,3.768 3.768,3.768v0c2.08,-0.003 3.765,-1.688 3.768,-3.767v-0zM10.427,23.76l-1.841,-0.762c0.524,1.078 1.611,1.808 2.868,1.808 1.317,0 2.448,-0.801 2.93,-1.943l0.008,-0.021c0.155,-0.362 0.246,-0.784 0.246,-1.226 0,-1.757 -1.424,-3.181 -3.181,-3.181 -0.405,0 -0.792,0.076 -1.148,0.213l0.022,-0.007 1.903,0.787c0.852,0.364 1.439,1.196 1.439,2.164 0,1.296 -1.051,2.347 -2.347,2.347 -0.324,0 -0.632,-0.066 -0.913,-0.184l0.015,0.006zM15.974,1.004c-7.857,0.001 -14.301,6.046 -14.938,13.738l-0.004,0.054 8.038,3.322c0.668,-0.462 1.495,-0.737 2.387,-0.737 0.001,0 0.002,0 0.002,0h-0c0.079,0 0.156,0.005 0.235,0.008l3.575,-5.176v-0.074c0.003,-3.12 2.533,-5.648 5.653,-5.648 3.122,0 5.653,2.531 5.653,5.653s-2.531,5.653 -5.653,5.653h-0.131l-5.094,3.638c0,0.065 0.005,0.131 0.005,0.199 0,0.001 0,0.002 0,0.003 0,2.342 -1.899,4.241 -4.241,4.241 -2.047,0 -3.756,-1.451 -4.153,-3.38l-0.005,-0.027 -5.755,-2.383c1.841,6.345 7.601,10.905 14.425,10.905 8.281,0 14.994,-6.713 14.994,-14.994s-6.713,-14.994 -14.994,-14.994c-0,0 -0.001,0 -0.001,0h0z"
tools:ignore="VectorPath" />
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M22.922,1.7a2.985,2.985 0,0 0,-2.458 -0.648l-6.18,1.123A3.993,3.993 0,0 0,12 3.461,3.993 3.993,0 0,0 9.716,2.172L3.536,1.049A3,3 0,0 0,0 4L0,20.834l12,2.183 12,-2.183L24,4A2.992,2.992 0,0 0,22.922 1.7ZM11,20.8 L2,19.166L2,4a1,1 0,0 1,1.179 -0.983L9.358,4.14A2,2 0,0 1,11 6.108ZM22,19.164L13,20.8L13,6.108A2,2 0,0 1,14.642 4.14l6.179,-1.123A1,1 0,0 1,22 4Z"/>
</vector>

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