mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Compare commits
1042 Commits
v0.4.6-alp
...
release-ca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b42280133c | ||
|
|
94d0b4d10e | ||
|
|
057603f926 | ||
|
|
bfd11c49af | ||
|
|
2a9723b932 | ||
|
|
f565b9ee6e | ||
|
|
504c0a0ed9 | ||
|
|
c77173f7c9 | ||
|
|
73af60d91b | ||
|
|
31d7fb6051 | ||
|
|
def15f5565 | ||
|
|
a257afca4b | ||
|
|
dca8f9189f | ||
|
|
3eef91fb24 | ||
|
|
73a7ea74f3 | ||
|
|
74b446d157 | ||
|
|
4e6701ff01 | ||
|
|
5fa1a26843 | ||
|
|
151196e5f2 | ||
|
|
716b0dc48d | ||
|
|
c66c9242b3 | ||
|
|
8404d4d956 | ||
|
|
37fa86dce8 | ||
|
|
4bcb5936b4 | ||
|
|
4fd9b7e6c2 | ||
|
|
e4af9b06d3 | ||
|
|
89bd39cea8 | ||
|
|
cd34eebcba | ||
|
|
07060112bc | ||
|
|
d6bcbaea7a | ||
|
|
42abb15aaf | ||
|
|
dcac0fd4f2 | ||
|
|
90d6acb7a4 | ||
|
|
2c6538663d | ||
|
|
280e6ecdd2 | ||
|
|
3ca78d4c7c | ||
|
|
e7845dd356 | ||
|
|
8ef86e75f0 | ||
|
|
de1f233848 | ||
|
|
fd72d4ae2d | ||
|
|
a112ef4aa2 | ||
|
|
71750c43bd | ||
|
|
36a80c8708 | ||
|
|
600b649449 | ||
|
|
5237dc688a | ||
|
|
2ebf30e23d | ||
|
|
dc01620b8c | ||
|
|
edc3529b67 | ||
|
|
13ec455d74 | ||
|
|
8da9249e52 | ||
|
|
228bb7767e | ||
|
|
e6630171cc | ||
|
|
22e37ceec5 | ||
|
|
0ce800d62a | ||
|
|
fa49e455c8 | ||
|
|
3964dafb9e | ||
|
|
24015686ea | ||
|
|
77ceae21e1 | ||
|
|
874e01b031 | ||
|
|
e6ef6cd05b | ||
|
|
ddab28f874 | ||
|
|
2d7db0bf5e | ||
|
|
5d274a3efb | ||
|
|
84b3e3dac4 | ||
|
|
78c655e2f7 | ||
|
|
de495cc71d | ||
|
|
c034c19176 | ||
|
|
7f8d240bed | ||
|
|
624b29ab84 | ||
|
|
e877d9f8e4 | ||
|
|
43284c46db | ||
|
|
cf7aa05ec0 | ||
|
|
fd2a63c530 | ||
|
|
266326c40c | ||
|
|
1bca2e5c26 | ||
|
|
64e4e7f301 | ||
|
|
2d0e10bc0b | ||
|
|
1248ffb60b | ||
|
|
825d60e754 | ||
|
|
f392b08392 | ||
|
|
aee1f21cd6 | ||
|
|
c1aadece29 | ||
|
|
fbc598e3aa | ||
|
|
b600b2503b | ||
|
|
011ccc0a99 | ||
|
|
3814052fd9 | ||
|
|
0558227ce6 | ||
|
|
0452a8081b | ||
|
|
bdf9c83053 | ||
|
|
3c02802807 | ||
|
|
ffddb9cd1e | ||
|
|
55f75ff149 | ||
|
|
c9b143b5e0 | ||
|
|
9cbfa2a8aa | ||
|
|
3635837495 | ||
|
|
3f1fde2398 | ||
|
|
c2489d638a | ||
|
|
0d246c7c25 | ||
|
|
1db8736391 | ||
|
|
3067100562 | ||
|
|
fca63fb103 | ||
|
|
1262c85802 | ||
|
|
d0f5be7269 | ||
|
|
4062e69661 | ||
|
|
bb0ded2b46 | ||
|
|
49990e01ee | ||
|
|
3d61b7e1a7 | ||
|
|
7ae15239b1 | ||
|
|
589479ba56 | ||
|
|
40aa6fcfdc | ||
|
|
41b4328eaf | ||
|
|
bc65bf546f | ||
|
|
f91daed25e | ||
|
|
a1f6a50a46 | ||
|
|
8a9c319e45 | ||
|
|
8e55051410 | ||
|
|
b20134f8f1 | ||
|
|
6af6545f09 | ||
|
|
9fc1519ef6 | ||
|
|
039c922649 | ||
|
|
70b6143fd9 | ||
|
|
8cce77c4d3 | ||
|
|
7573720398 | ||
|
|
2b5b428237 | ||
|
|
1622d663bb | ||
|
|
eff96ce0c2 | ||
|
|
0b8fb969b2 | ||
|
|
c66086d64f | ||
|
|
8eaebb5d22 | ||
|
|
c33afa5215 | ||
|
|
3e19c84c8e | ||
|
|
3b075ec276 | ||
|
|
2fd8752050 | ||
|
|
45f828c838 | ||
|
|
d35e6063e7 | ||
|
|
f7e9fc5cbc | ||
|
|
b7bf89ce2f | ||
|
|
a733c98259 | ||
|
|
efd7c3cec9 | ||
|
|
7155429dc7 | ||
|
|
326fbff982 | ||
|
|
3a44608e2b | ||
|
|
f1fcabe7f7 | ||
|
|
3ab10af98b | ||
|
|
2a00bab149 | ||
|
|
99e742498d | ||
|
|
b3e53d07dd | ||
|
|
69e8fed623 | ||
|
|
0765459cfd | ||
|
|
791b1fc4ab | ||
|
|
0ef5de51c4 | ||
|
|
2d26862b6c | ||
|
|
f058958c13 | ||
|
|
48d64078d8 | ||
|
|
18960ca51e | ||
|
|
4350cd93e5 | ||
|
|
3c33d3883e | ||
|
|
ee15106be1 | ||
|
|
50f3882b3e | ||
|
|
cf86c4ade9 | ||
|
|
ddf9883f89 | ||
|
|
8ffcbaa05b | ||
|
|
dd2856a993 | ||
|
|
c44caa9cea | ||
|
|
3aafa26c70 | ||
|
|
e2ac37ef18 | ||
|
|
3d33319a19 | ||
|
|
83e3c8b681 | ||
|
|
f0826bbdba | ||
|
|
6d5eb05f0b | ||
|
|
f77b008701 | ||
|
|
5acc0e8ac5 | ||
|
|
760fe18cc7 | ||
|
|
34f9a8bc40 | ||
|
|
23f9eee39f | ||
|
|
46f2ff4403 | ||
|
|
386d5298a2 | ||
|
|
9a7af84cd4 | ||
|
|
403280aa22 | ||
|
|
d90ef540f9 | ||
|
|
f1fb3073d2 | ||
|
|
be879e3660 | ||
|
|
e9112e5be6 | ||
|
|
42cfb36c04 | ||
|
|
6e7b5b1cc3 | ||
|
|
8e20499b92 | ||
|
|
16e77087f5 | ||
|
|
eed91e8486 | ||
|
|
016c2d45f6 | ||
|
|
0a5a507f70 | ||
|
|
8406619868 | ||
|
|
3142a438f7 | ||
|
|
94fe8488e4 | ||
|
|
8aac6b7d7e | ||
|
|
c7ff73f8a6 | ||
|
|
2ab072c929 | ||
|
|
d4a06e9edb | ||
|
|
b2477112b1 | ||
|
|
1a93ee68d0 | ||
|
|
1deeaacf1d | ||
|
|
52606b8d57 | ||
|
|
627c4b5584 | ||
|
|
a65a5a5bed | ||
|
|
4f927faeb4 | ||
|
|
9525982161 | ||
|
|
cc902aec04 | ||
|
|
74e2332b17 | ||
|
|
5a4a202805 | ||
|
|
79f9905413 | ||
|
|
c2ea746d48 | ||
|
|
96415fd087 | ||
|
|
d1d4116e66 | ||
|
|
6074367300 | ||
|
|
b711872d6c | ||
|
|
20db9647bd | ||
|
|
d31aa30da8 | ||
|
|
cde33fdd76 | ||
|
|
1374f270eb | ||
|
|
77a7397f1c | ||
|
|
e6a564ff61 | ||
|
|
6e5e1914ec | ||
|
|
5b6f58a38e | ||
|
|
9bd206a750 | ||
|
|
0c391df69f | ||
|
|
711f6094f0 | ||
|
|
0376d020e7 | ||
|
|
c9c34f013f | ||
|
|
5797b9d209 | ||
|
|
71e47bce0b | ||
|
|
1c86ba1d4c | ||
|
|
ffeecfbf9e | ||
|
|
416f0d3e36 | ||
|
|
2bbcbc5576 | ||
|
|
dbd87d5724 | ||
|
|
17cd42a1a0 | ||
|
|
182fe294de | ||
|
|
c2d5d4ea17 | ||
|
|
95db9b5d38 | ||
|
|
032b74b57b | ||
|
|
f84b560351 | ||
|
|
8006d639ae | ||
|
|
89abcb3330 | ||
|
|
8208316fb9 | ||
|
|
6250f760a9 | ||
|
|
d7edb00254 | ||
|
|
e6d2d906e1 | ||
|
|
76efe84be6 | ||
|
|
7fe9b0d19f | ||
|
|
e9896963ca | ||
|
|
da2152f0e3 | ||
|
|
dc7fd2c870 | ||
|
|
e41d3c93a6 | ||
|
|
7684461edb | ||
|
|
c618a36072 | ||
|
|
dd7e34178a | ||
|
|
95505ec9fa | ||
|
|
8d7aa5df65 | ||
|
|
8f00e8a9e2 | ||
|
|
ce129691a7 | ||
|
|
3d204af60f | ||
|
|
00d7b451ec | ||
|
|
96899121f7 | ||
|
|
a4452aee94 | ||
|
|
f80321a267 | ||
|
|
2391977082 | ||
|
|
7a0504227b | ||
|
|
4278c6fa9a | ||
|
|
db4e9870b0 | ||
|
|
be439be264 | ||
|
|
1f60f51898 | ||
|
|
a899c5ffca | ||
|
|
ffade5fb8e | ||
|
|
b57d6b305a | ||
|
|
786729c006 | ||
|
|
258d21672c | ||
|
|
c11a9728e8 | ||
|
|
c8da3e6da3 | ||
|
|
f17ee42d63 | ||
|
|
5e40d7abf1 | ||
|
|
42e62be0f5 | ||
|
|
dd641fc2aa | ||
|
|
8580c5c62b | ||
|
|
b4841872ca | ||
|
|
a92d4403d7 | ||
|
|
8cd18eb921 | ||
|
|
8bcf564f07 | ||
|
|
264c381bc3 | ||
|
|
7813f8335a | ||
|
|
a6e28e9064 | ||
|
|
1791eaa37d | ||
|
|
116d4fa894 | ||
|
|
8b5df691ec | ||
|
|
f00fce7fe7 | ||
|
|
897afb2fef | ||
|
|
5c3960868a | ||
|
|
376a63b363 | ||
|
|
402a1457aa | ||
|
|
6bb150a41c | ||
|
|
2cadebcabd | ||
|
|
b61289d996 | ||
|
|
73c8ce2fe7 | ||
|
|
38f6788fa8 | ||
|
|
89051c3e85 | ||
|
|
064c24e023 | ||
|
|
e273203629 | ||
|
|
430d8db15d | ||
|
|
f1eae9685f | ||
|
|
17c71eb4ed | ||
|
|
4bbe5eb2f8 | ||
|
|
c8e1f76b38 | ||
|
|
fa215142ad | ||
|
|
17b10bebd5 | ||
|
|
b97713f8cc | ||
|
|
53237c6197 | ||
|
|
9d225bfc1a | ||
|
|
5e5ee30b8f | ||
|
|
68980651dc | ||
|
|
5cd566c7ca | ||
|
|
62af0f74e7 | ||
|
|
fc8b0d9f7a | ||
|
|
95e18f6503 | ||
|
|
c2b0849fb6 | ||
|
|
a89861128c | ||
|
|
4e84a97367 | ||
|
|
644404c4e6 | ||
|
|
df939f1ac3 | ||
|
|
454c7ad2de | ||
|
|
bf7115288b | ||
|
|
2530d6dd78 | ||
|
|
6d551c51eb | ||
|
|
636803b2ac | ||
|
|
475b04eff7 | ||
|
|
7f5873b5b8 | ||
|
|
14c0a2f1e8 | ||
|
|
4946807d88 | ||
|
|
7fa39561e3 | ||
|
|
0c5139f5ee | ||
|
|
58f114bba0 | ||
|
|
065cdf3648 | ||
|
|
03bd14d3fe | ||
|
|
6cc1572b11 | ||
|
|
4947997a0c | ||
|
|
44bd054a3d | ||
|
|
b13689c09a | ||
|
|
e11f4a6c11 | ||
|
|
12b9337026 | ||
|
|
10a76c47ff | ||
|
|
b282e5d676 | ||
|
|
ef48147322 | ||
|
|
804743c051 | ||
|
|
84a1375663 | ||
|
|
88cf20a4d9 | ||
|
|
0003363d71 | ||
|
|
914d4a4a28 | ||
|
|
4078759310 | ||
|
|
e94d296de2 | ||
|
|
01897019b0 | ||
|
|
fc00a4eac4 | ||
|
|
abd561a60d | ||
|
|
d774977387 | ||
|
|
5726d6dee2 | ||
|
|
9c2ce526d3 | ||
|
|
9bbcdac704 | ||
|
|
a64ccab15f | ||
|
|
b352bc824c | ||
|
|
ba2c48dead | ||
|
|
ebfa7916c6 | ||
|
|
fd15406f5d | ||
|
|
19b0eeeffd | ||
|
|
6fdfb194a6 | ||
|
|
7cf77a63be | ||
|
|
2e77de95cc | ||
|
|
2476dac810 | ||
|
|
0b2ee1df9b | ||
|
|
224dc5a688 | ||
|
|
bc5049992a | ||
|
|
cc686e2320 | ||
|
|
040476107a | ||
|
|
57f3b84f20 | ||
|
|
b021ddaf11 | ||
|
|
e7418a8d6c | ||
|
|
9174353b09 | ||
|
|
e1a566d0d3 | ||
|
|
a3e92580c2 | ||
|
|
86e0e6b3a3 | ||
|
|
1e72f15876 | ||
|
|
2d90c359f7 | ||
|
|
b993786301 | ||
|
|
faccf48ecd | ||
|
|
c0b43c916e | ||
|
|
473f16dda0 | ||
|
|
03de0f9175 | ||
|
|
aa7db94750 | ||
|
|
bd3ac54ff8 | ||
|
|
287f634f74 | ||
|
|
119a6f620c | ||
|
|
3e22247f76 | ||
|
|
854bef15e0 | ||
|
|
aacf6d99bc | ||
|
|
a8595a97d8 | ||
|
|
c630fe3045 | ||
|
|
05c7d8166b | ||
|
|
1d3d8ca705 | ||
|
|
97a11d6873 | ||
|
|
15e23564c2 | ||
|
|
42782c60a4 | ||
|
|
62b2b13d75 | ||
|
|
8bf2048d4d | ||
|
|
0fee5c8e7f | ||
|
|
b5e47fdbe6 | ||
|
|
c85e923899 | ||
|
|
a897401975 | ||
|
|
2f43a84224 | ||
|
|
274c16851e | ||
|
|
e77356cb61 | ||
|
|
f4e77b1f5b | ||
|
|
95247062a3 | ||
|
|
959b083a60 | ||
|
|
395409ecae | ||
|
|
5a2b050104 | ||
|
|
732b837a46 | ||
|
|
d60d2e78ef | ||
|
|
81b1bf0335 | ||
|
|
867dff6945 | ||
|
|
98862d917c | ||
|
|
1dceb0b421 | ||
|
|
fbc22676c5 | ||
|
|
61e52efc07 | ||
|
|
fa48d1f905 | ||
|
|
5f3dbbf94e | ||
|
|
96b3e2f115 | ||
|
|
00e2da2aab | ||
|
|
1acb7d6762 | ||
|
|
b3f8eb96ad | ||
|
|
36478f26d5 | ||
|
|
e07bf98e62 | ||
|
|
cd38a2f053 | ||
|
|
329e9b86fd | ||
|
|
1e48df85a7 | ||
|
|
8cb8f7e108 | ||
|
|
222a296b4f | ||
|
|
fb96926d1e | ||
|
|
a15d2e2ec7 | ||
|
|
df1839cee0 | ||
|
|
1b4d3dd832 | ||
|
|
13e75e9dd1 | ||
|
|
0e414850bd | ||
|
|
40e984982b | ||
|
|
d7c278b034 | ||
|
|
79016d72e3 | ||
|
|
b089a8cfd8 | ||
|
|
a9f4353e4a | ||
|
|
4acbe375a7 | ||
|
|
a9a6b18943 | ||
|
|
9c53e0605b | ||
|
|
4e679344d0 | ||
|
|
b0ab0ae8cf | ||
|
|
6edcd8a5ce | ||
|
|
aa0cca67a1 | ||
|
|
c477dcd065 | ||
|
|
6db4455d5a | ||
|
|
54bf19d410 | ||
|
|
0c93b950c6 | ||
|
|
52833cadee | ||
|
|
6a45bc9e79 | ||
|
|
88d17d1cb3 | ||
|
|
8c27fdb53c | ||
|
|
e7777a2a48 | ||
|
|
fa4a0ccecb | ||
|
|
b54aa45377 | ||
|
|
eecdcad8e7 | ||
|
|
d68ac6cf2b | ||
|
|
e39b6b5eea | ||
|
|
53a43b5536 | ||
|
|
4eb1b3ef6d | ||
|
|
4204a4b150 | ||
|
|
b64d336922 | ||
|
|
3e465509e9 | ||
|
|
79c8e743d9 | ||
|
|
0f882c9c33 | ||
|
|
3ddafa4fff | ||
|
|
5c4b09735a | ||
|
|
f5aca98e49 | ||
|
|
2cb3287d1f | ||
|
|
b96254c9f2 | ||
|
|
f6fbd5c931 | ||
|
|
e622067230 | ||
|
|
c4e484706a | ||
|
|
37a89e4548 | ||
|
|
d0e0d851db | ||
|
|
9df0fb9425 | ||
|
|
c6300b3e6a | ||
|
|
6296bdc2d8 | ||
|
|
627c19e550 | ||
|
|
dcacf617d7 | ||
|
|
fceb27505d | ||
|
|
4b431a7f90 | ||
|
|
413285f03d | ||
|
|
8a3db4083f | ||
|
|
f847d4713b | ||
|
|
15bec68fc4 | ||
|
|
58b5eacdb7 | ||
|
|
95f8eb0976 | ||
|
|
c3fb3fa9c1 | ||
|
|
73bf1da061 | ||
|
|
e040ecfce2 | ||
|
|
32f5f01f5c | ||
|
|
b4e217548e | ||
|
|
dab1d4a97c | ||
|
|
8d21149db7 | ||
|
|
288df71970 | ||
|
|
40df2ebb7d | ||
|
|
c7ecd2422a | ||
|
|
f18212dac4 | ||
|
|
45e290d656 | ||
|
|
8e9e6749db | ||
|
|
19c1ae82a2 | ||
|
|
f056cc62a8 | ||
|
|
90ccf57f01 | ||
|
|
d72a00a005 | ||
|
|
5d5c650162 | ||
|
|
42c7a36da7 | ||
|
|
61dc9c8b31 | ||
|
|
d078105eb7 | ||
|
|
7ee9946f49 | ||
|
|
5507bca68d | ||
|
|
535b95242c | ||
|
|
e40b79d2c4 | ||
|
|
ecd0581942 | ||
|
|
4f7c3988a0 | ||
|
|
5b7e63b02d | ||
|
|
ef99c21380 | ||
|
|
e0ad679b57 | ||
|
|
61fb80d67f | ||
|
|
a9a0332465 | ||
|
|
4494a5ccbb | ||
|
|
f0c4b10084 | ||
|
|
0bdf362174 | ||
|
|
a53cca8dda | ||
|
|
9aad81588a | ||
|
|
5ba1498802 | ||
|
|
539b183da8 | ||
|
|
396c061a3e | ||
|
|
8c7f6abb1c | ||
|
|
5cc42dd9cf | ||
|
|
f52b5f419e | ||
|
|
3b38ca5920 | ||
|
|
86cfb4fb2f | ||
|
|
166631d618 | ||
|
|
013546a45b | ||
|
|
a2c8563adf | ||
|
|
0c8de2dcf3 | ||
|
|
4f3491062b | ||
|
|
cc8c25a283 | ||
|
|
70740233a9 | ||
|
|
f2d4f0b0ca | ||
|
|
153ca01b96 | ||
|
|
f667410a56 | ||
|
|
f13545eae9 | ||
|
|
7ee24b1c7c | ||
|
|
29784310fc | ||
|
|
3427fcea7e | ||
|
|
c99b5ed19f | ||
|
|
2118ded496 | ||
|
|
4401261446 | ||
|
|
a6ec3a8cd0 | ||
|
|
6e6da64c51 | ||
|
|
a84e190548 | ||
|
|
e0238c2680 | ||
|
|
a60f2e7b62 | ||
|
|
4782596e3c | ||
|
|
832568aa00 | ||
|
|
05e0cc393a | ||
|
|
c74258e3ad | ||
|
|
2e1c3ec4b9 | ||
|
|
9a571132c8 | ||
|
|
acb55044d1 | ||
|
|
14679bd7d8 | ||
|
|
3c9af59051 | ||
|
|
8390a25c50 | ||
|
|
97b277edda | ||
|
|
462fa53c80 | ||
|
|
945c45803b | ||
|
|
20917da437 | ||
|
|
cd25509d3d | ||
|
|
4c3f80d7d7 | ||
|
|
fac32476d4 | ||
|
|
3fa88f3cdf | ||
|
|
46135f7ae0 | ||
|
|
f6e9503045 | ||
|
|
39c28ffb04 | ||
|
|
6373fd300d | ||
|
|
04f281db56 | ||
|
|
5f2fb60e1f | ||
|
|
4efd48c4b9 | ||
|
|
fb6ac40af8 | ||
|
|
9daa683b42 | ||
|
|
baffc9af49 | ||
|
|
bc6c70928f | ||
|
|
9e1503c106 | ||
|
|
57a700d2d2 | ||
|
|
5ca6c97cbe | ||
|
|
55f3bd5adb | ||
|
|
bf7c4beccd | ||
|
|
14d44babe7 | ||
|
|
30a90a96d8 | ||
|
|
c621b5dd85 | ||
|
|
63bdf44e17 | ||
|
|
029decf969 | ||
|
|
b5c7eaf36e | ||
|
|
99de17a858 | ||
|
|
5765ade7f8 | ||
|
|
59a8fba14d | ||
|
|
965b67b8ab | ||
|
|
0ef3abbffa | ||
|
|
2124e9cd42 | ||
|
|
2f1a0ad7d3 | ||
|
|
24e6c219f5 | ||
|
|
daec6dab5b | ||
|
|
3708d4150c | ||
|
|
11518485de | ||
|
|
29118e1ea1 | ||
|
|
aa5b62c1d2 | ||
|
|
f320cb122c | ||
|
|
bb7738724f | ||
|
|
df7eebed39 | ||
|
|
21040da195 | ||
|
|
be625fdca9 | ||
|
|
7ee3fb883b | ||
|
|
c2f6edfd74 | ||
|
|
4f5023b45c | ||
|
|
f0ab43d320 | ||
|
|
d2e803ab82 | ||
|
|
ca45b8b906 | ||
|
|
ec020f7b5d | ||
|
|
f2161da162 | ||
|
|
613aed2d2b | ||
|
|
1d38bd6fea | ||
|
|
6f7b251094 | ||
|
|
a9d873a05f | ||
|
|
05f98b2738 | ||
|
|
1568c65492 | ||
|
|
4a5c4ed7d7 | ||
|
|
ff7385cf49 | ||
|
|
a0de159234 | ||
|
|
d56a95cfa3 | ||
|
|
497f718e4b | ||
|
|
9942ff476b | ||
|
|
c042d2b6f5 | ||
|
|
b9201d583c | ||
|
|
3f67125f20 | ||
|
|
4f72f10642 | ||
|
|
89fb0a9da1 | ||
|
|
0e9b249bba | ||
|
|
0f0ba4c725 | ||
|
|
5542109daf | ||
|
|
ec91b597c8 | ||
|
|
d0f85ae977 | ||
|
|
7d6930fba9 | ||
|
|
2232a114b7 | ||
|
|
33ce537993 | ||
|
|
1ab8e9a16f | ||
|
|
73b1714191 | ||
|
|
cb793e9d0f | ||
|
|
7686a60bfd | ||
|
|
38027b6ff3 | ||
|
|
a512b0e405 | ||
|
|
46fb6a98d5 | ||
|
|
1a8a19ae5c | ||
|
|
8865ded4bd | ||
|
|
7adfe9cce4 | ||
|
|
85e5a6a309 | ||
|
|
d681d3cee0 | ||
|
|
c5650ba29a | ||
|
|
ef0a2d2ddc | ||
|
|
f143e8d874 | ||
|
|
89c1660988 | ||
|
|
4e7c8ef856 | ||
|
|
8024db9579 | ||
|
|
a0634a7f99 | ||
|
|
7bf6c1bb23 | ||
|
|
a62ae4e21e | ||
|
|
6c466a8bb8 | ||
|
|
36f828acb1 | ||
|
|
046e096b9e | ||
|
|
82df3cb316 | ||
|
|
1ba16f82e7 | ||
|
|
72c6bb0086 | ||
|
|
8bb4334187 | ||
|
|
59a9069d4b | ||
|
|
ba534f1786 | ||
|
|
72bb54bde0 | ||
|
|
cb3f46303c | ||
|
|
57f021f995 | ||
|
|
bf4b2272e4 | ||
|
|
31999ec00c | ||
|
|
086b6736b0 | ||
|
|
bf93b8e90a | ||
|
|
4d6bd6c6e9 | ||
|
|
c9dc5eb2f5 | ||
|
|
5fdb704d68 | ||
|
|
6d18e25232 | ||
|
|
7391006a2f | ||
|
|
9207585f5b | ||
|
|
cb53da3a71 | ||
|
|
d2ac5aeff8 | ||
|
|
b646087026 | ||
|
|
82e60cd2cf | ||
|
|
9d46a1c73f | ||
|
|
955057183d | ||
|
|
0396d6bf9c | ||
|
|
ee1d89007c | ||
|
|
4245927a6c | ||
|
|
f585828936 | ||
|
|
7450c9e506 | ||
|
|
d957cd6655 | ||
|
|
ef91f840ae | ||
|
|
17c74fbe91 | ||
|
|
17a7a1889e | ||
|
|
24ed96b348 | ||
|
|
15e8c9e791 | ||
|
|
de14f6c738 | ||
|
|
92b1a46e8a | ||
|
|
cbaadb6fc9 | ||
|
|
44295673dc | ||
|
|
8bf0f403e2 | ||
|
|
917a0d10e5 | ||
|
|
9c65411733 | ||
|
|
6c315d89e1 | ||
|
|
b5f1a459c2 | ||
|
|
6b12000979 | ||
|
|
1aec7f8081 | ||
|
|
5f0e96e2e6 | ||
|
|
678a8585a9 | ||
|
|
e632e379b6 | ||
|
|
1a7d2b5028 | ||
|
|
ce28d49510 | ||
|
|
0ac632cc9b | ||
|
|
47e4757b6e | ||
|
|
d21ee2a7b6 | ||
|
|
0cec61afea | ||
|
|
ff04364178 | ||
|
|
0cf2733d55 | ||
|
|
f5319ed654 | ||
|
|
cfef9f4bc4 | ||
|
|
6abf7f059a | ||
|
|
c0c1ff6e17 | ||
|
|
856dba83a5 | ||
|
|
2f37916595 | ||
|
|
f36a29570b | ||
|
|
62a3719163 | ||
|
|
e9511e9233 | ||
|
|
51cf15b8cc | ||
|
|
278d0bdd3c | ||
|
|
0a07f85fcf | ||
|
|
7face05e12 | ||
|
|
22ad5d5972 | ||
|
|
2e194d557a | ||
|
|
1a76df2056 | ||
|
|
787bf13f3c | ||
|
|
10f1c6a862 | ||
|
|
0366cc38e2 | ||
|
|
603018d1ef | ||
|
|
66ae06056b | ||
|
|
17486ab40c | ||
|
|
6cae91b06f | ||
|
|
9c055e0d71 | ||
|
|
db4aeca47d | ||
|
|
c29a368e5a | ||
|
|
dbe2442bb7 | ||
|
|
2108fc4b26 | ||
|
|
48f962ca4b | ||
|
|
e80a5e8ca1 | ||
|
|
fb2ecc75eb | ||
|
|
ee95291418 | ||
|
|
46796fce13 | ||
|
|
ee08f57abe | ||
|
|
eb86d8dfca | ||
|
|
c75e20e58f | ||
|
|
2c403a9283 | ||
|
|
27c78d6a67 | ||
|
|
e0d33760e0 | ||
|
|
2d339d7161 | ||
|
|
243f58ecf3 | ||
|
|
378dbfc085 | ||
|
|
cee6839b5d | ||
|
|
f1a836c222 | ||
|
|
cbf4b56ecb | ||
|
|
e2e3da6a0f | ||
|
|
3a96808aa5 | ||
|
|
d1ccccae18 | ||
|
|
d31242124f | ||
|
|
8c4996f466 | ||
|
|
59b89dc638 | ||
|
|
f54ac5c3d8 | ||
|
|
666b3e0383 | ||
|
|
d8893e21a1 | ||
|
|
5391b567b9 | ||
|
|
ad7ea014f2 | ||
|
|
ceb00a239f | ||
|
|
81ab1aa05d | ||
|
|
7bf232f146 | ||
|
|
3f07271931 | ||
|
|
1c30bb006b | ||
|
|
34594ac836 | ||
|
|
cee58800e1 | ||
|
|
ab3b487024 | ||
|
|
91b393eb35 | ||
|
|
edb4ddc287 | ||
|
|
f9fd5caa9f | ||
|
|
d5653a9b1d | ||
|
|
ec5ff1bf0c | ||
|
|
41912d1057 | ||
|
|
228452fd17 | ||
|
|
484d3dd28f | ||
|
|
a52e7e7b1a | ||
|
|
92a08f6278 | ||
|
|
8e3da65433 | ||
|
|
3f625c03b9 | ||
|
|
4423d5f3d5 | ||
|
|
d0fc286c43 | ||
|
|
b5443ab0a8 | ||
|
|
e6c34306c9 | ||
|
|
532a83fe91 | ||
|
|
293b928764 | ||
|
|
38d62df75d | ||
|
|
fbd42ade6e | ||
|
|
9af1cffe08 | ||
|
|
b0d92906e5 | ||
|
|
0329e27713 | ||
|
|
2d39862b1b | ||
|
|
5c1782ec7f | ||
|
|
6c6117aee3 | ||
|
|
1798e62315 | ||
|
|
2b2ed76aa3 | ||
|
|
38d72a5cd0 | ||
|
|
14ec4a8610 | ||
|
|
bdc7a5bb46 | ||
|
|
131f30405c | ||
|
|
dbf21e0af9 | ||
|
|
9094f8fdc6 | ||
|
|
aa0b0a585c | ||
|
|
ad61037452 | ||
|
|
66ed1a99e0 | ||
|
|
d7dc5769a8 | ||
|
|
b0ee653bff | ||
|
|
5a950e22ce | ||
|
|
0459d5c625 | ||
|
|
43d28ebe19 | ||
|
|
187b9be57a | ||
|
|
564a650403 | ||
|
|
0e403e8b74 | ||
|
|
840cdd9049 | ||
|
|
e5e7e9be14 | ||
|
|
e677968ba7 | ||
|
|
d24b955d52 | ||
|
|
48860ff514 | ||
|
|
0e78b7559b | ||
|
|
25edfc45e5 | ||
|
|
885825e5cc | ||
|
|
344413ae74 | ||
|
|
fa0643987b | ||
|
|
dcff462b32 | ||
|
|
fa04e5f8bb | ||
|
|
c8d5f9ce0e | ||
|
|
55642a89b1 | ||
|
|
f305aa3929 | ||
|
|
47ee88c339 | ||
|
|
022e041f68 | ||
|
|
0cc53890c1 | ||
|
|
e37f7a4977 | ||
|
|
8d03c6a767 | ||
|
|
e29fdfd8c7 | ||
|
|
af619c3687 | ||
|
|
6afb6682ea | ||
|
|
9c2c7f45c6 | ||
|
|
7fbc19e90a | ||
|
|
8f2f73dc0e | ||
|
|
24a1681337 | ||
|
|
304e8ba3a0 | ||
|
|
45b840fa72 | ||
|
|
82704f042b | ||
|
|
87d71da55e | ||
|
|
71cf7c67f7 | ||
|
|
62142ed976 | ||
|
|
f56bd514dc | ||
|
|
e30f161d1d | ||
|
|
720bfb3118 | ||
|
|
4100a3cc67 | ||
|
|
942993ff6d | ||
|
|
fbf435c799 | ||
|
|
8fdb0d82e8 | ||
|
|
dcbebab61b | ||
|
|
7b10afae43 | ||
|
|
81d8a88abd | ||
|
|
cb14158a0f | ||
|
|
38fc60352a | ||
|
|
3748f0d6e3 | ||
|
|
edd626d5e5 | ||
|
|
f785e75686 | ||
|
|
9a46ed70b7 | ||
|
|
532c09a815 | ||
|
|
e430d38c63 | ||
|
|
289b36de6d | ||
|
|
7e01f40e5c | ||
|
|
cac4bb5f13 | ||
|
|
c8bb041887 | ||
|
|
9302c5c6d1 | ||
|
|
84a3313f2c | ||
|
|
1eb3beeb2e | ||
|
|
d0e6ef8c6c | ||
|
|
5da1df7e20 | ||
|
|
16fa6d9805 | ||
|
|
0ca7766689 | ||
|
|
4342575418 | ||
|
|
4cdb73a60d | ||
|
|
a23c53bcb8 | ||
|
|
19ac4f92e0 | ||
|
|
0b8f48b4fd | ||
|
|
d2fa94a6cb | ||
|
|
da1c674911 | ||
|
|
7184bc1eb2 | ||
|
|
37f30a0f1a | ||
|
|
04f4b3e78a | ||
|
|
dbdc162fae | ||
|
|
563f673fb3 | ||
|
|
423e799a82 | ||
|
|
4734b89414 | ||
|
|
6f708e7733 | ||
|
|
f0c3f95189 | ||
|
|
93ca0e3f22 | ||
|
|
d94432636f | ||
|
|
60fca35d80 | ||
|
|
db71462d1c | ||
|
|
86f522176a | ||
|
|
94ee71c48f | ||
|
|
fda0b21fb0 | ||
|
|
775148cec8 | ||
|
|
f2dc4a1a00 | ||
|
|
eda5723a3c | ||
|
|
b044d9a6c0 | ||
|
|
125d5396b9 | ||
|
|
17b8b35a43 | ||
|
|
4bd017e3c7 | ||
|
|
37447a7fd3 | ||
|
|
1ed1dec65e | ||
|
|
5e2e465813 | ||
|
|
335655406e | ||
|
|
bf12d6330c | ||
|
|
3cca3187ad | ||
|
|
f4388a2cff | ||
|
|
7cf5d324eb | ||
|
|
ec9ef2b0fb | ||
|
|
6c852d93a9 | ||
|
|
290067932e | ||
|
|
4aa3a43604 | ||
|
|
3c33696452 | ||
|
|
3ea1ab8f30 | ||
|
|
76801f773d | ||
|
|
de7eeec94a | ||
|
|
0723a3ab95 | ||
|
|
8ef48ad977 | ||
|
|
ed24d1af60 | ||
|
|
e3dffb8245 | ||
|
|
74310a5ad3 | ||
|
|
a2223165e8 | ||
|
|
a879761dc2 | ||
|
|
124b909aa4 | ||
|
|
858e9eb066 | ||
|
|
7415e0cb97 | ||
|
|
915020ddc3 | ||
|
|
95915489b2 | ||
|
|
3e39c3351a | ||
|
|
244d32e7d2 | ||
|
|
16a79827b7 | ||
|
|
bd6a36e9ea | ||
|
|
771695af59 | ||
|
|
e811c7bd46 | ||
|
|
20f99c287f | ||
|
|
f464c9ae76 | ||
|
|
15ccb3dc04 | ||
|
|
defe40d48f | ||
|
|
0f2622e821 | ||
|
|
b442d238cd | ||
|
|
00f2a3c19d | ||
|
|
dcbfdf8666 | ||
|
|
6e84423032 | ||
|
|
912ab75a96 | ||
|
|
1022fc2f0c | ||
|
|
65edce855b | ||
|
|
0ba05d5795 | ||
|
|
1b17e17290 | ||
|
|
87957df1fb | ||
|
|
d3f8d4eff7 | ||
|
|
3ffeed3b39 | ||
|
|
4197e4402c | ||
|
|
1cfe6f5583 | ||
|
|
ad5cb83abf | ||
|
|
f4a4882dbc | ||
|
|
ecb2cf182a | ||
|
|
6aea839e04 | ||
|
|
e20d2fa95a | ||
|
|
806d0cc52f | ||
|
|
2a2baaf324 | ||
|
|
74989ec015 | ||
|
|
31af3a53ce | ||
|
|
361d51b55d | ||
|
|
a12c09eba5 | ||
|
|
bcfe0653bd | ||
|
|
c43bc763f3 | ||
|
|
85325c17ac | ||
|
|
178706f8de | ||
|
|
51defbb8b2 | ||
|
|
84cf9aa27a | ||
|
|
a66098e080 | ||
|
|
283b9e682e | ||
|
|
8b5956e76b | ||
|
|
017a89b945 | ||
|
|
5bc685182b | ||
|
|
f47fc2fb19 | ||
|
|
11d6f25606 | ||
|
|
331692e3d3 | ||
|
|
7483225e0d | ||
|
|
f00df5ca3f | ||
|
|
22ae882032 | ||
|
|
fbab82e4de | ||
|
|
ca81d1c4ce | ||
|
|
a1884ab19f | ||
|
|
8905cd5e85 | ||
|
|
8d5ed33ad8 | ||
|
|
b747752b76 | ||
|
|
4e13daa270 | ||
|
|
c00096bd9a | ||
|
|
210c1fbecf | ||
|
|
4a54011aac | ||
|
|
b89c5142b6 | ||
|
|
0421f6b8fe | ||
|
|
9ef6efa3e0 | ||
|
|
b43afd4e9c | ||
|
|
7700aa2030 | ||
|
|
e68683acb7 | ||
|
|
8dc48c10c3 |
46
.github/workflows/build_package.yml
vendored
Normal file
46
.github/workflows/build_package.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
name: Build & package
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main", "release-candidate" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
|
||||
- name: Setup vcpkg
|
||||
run: |
|
||||
bootstrap-vcpkg
|
||||
vcpkg integrate install
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
|
||||
- name: Build
|
||||
working-directory: .
|
||||
run: "./build_package.bat"
|
||||
shell: cmd
|
||||
|
||||
- name: Upload a Build Artifact
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: development_build_not_a_release
|
||||
path: ./package
|
||||
|
||||
- name: Upload a Build Artifact
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: zip_only_package
|
||||
path: ./zip
|
||||
include-hidden-files: true
|
||||
|
||||
|
||||
33
.github/workflows/ci.yml
vendored
33
.github/workflows/ci.yml
vendored
@@ -1,33 +0,0 @@
|
||||
# ci.yml file for GitHub Actions
|
||||
name: CI
|
||||
|
||||
on: [push]
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: write
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build_docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
working-directory: ./client
|
||||
|
||||
- name: Create the docs directory locally in CI
|
||||
run: npx typedoc --out ../docs/client @types/*.d.ts src/**/*.ts
|
||||
working-directory: ./client
|
||||
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
folder: docs
|
||||
50
.gitignore
vendored
50
.gitignore
vendored
@@ -1,17 +1,45 @@
|
||||
bin
|
||||
/scripts/old
|
||||
.vs
|
||||
x64
|
||||
core.user
|
||||
core.vcxproj.user
|
||||
*.user
|
||||
Output
|
||||
node_modules
|
||||
/client/TODO.txt
|
||||
/client/public/javascripts/bundle.js
|
||||
!client/bin
|
||||
/client/public/plugins
|
||||
/client/plugins/controltips/index.js
|
||||
hgt
|
||||
/client/public/databases/units/old
|
||||
/client/plugins/databasemanager/index.js
|
||||
|
||||
/backend/vcpkg_installed
|
||||
|
||||
/frontend/server/TODO.txt
|
||||
/frontend/server/public/javascripts/bundle.js
|
||||
/frontend/server/public/plugins
|
||||
/frontend/server/plugins/controltips/index.js
|
||||
/frontend/server/public/databases/units/old
|
||||
/frontend/server/plugins/databasemanager/index.js
|
||||
|
||||
/src/html
|
||||
/src/latex
|
||||
|
||||
/package
|
||||
/build
|
||||
/DCS Olympus backups
|
||||
/zip
|
||||
|
||||
*.user
|
||||
*.aps
|
||||
|
||||
L.Path.Drag.js
|
||||
leaflet-gesture-handling.css
|
||||
leaflet.nauticscale.js
|
||||
leaflet.css
|
||||
package-lock.json
|
||||
|
||||
!frontend/server/bin
|
||||
/mock-dcs
|
||||
/frontend/setup
|
||||
frontend/server/public/plugins/controltipsplugin/index.js
|
||||
frontend/website/plugins/controltips/index.js
|
||||
/frontend/server/public/maps
|
||||
*.pyc
|
||||
/scripts/**/*.jpg
|
||||
manager/manager.log
|
||||
/frontend/server/public
|
||||
/frontend/server/build
|
||||
/frontend/react/.vite
|
||||
|
||||
BIN
DCS Olympus Manager.lnk
Normal file
BIN
DCS Olympus Manager.lnk
Normal file
Binary file not shown.
59
INSTRUCTIONS.txt
Normal file
59
INSTRUCTIONS.txt
Normal file
@@ -0,0 +1,59 @@
|
||||
_____ _____ _____ ____ _
|
||||
| __ \ / ____|/ ____| / __ \| |
|
||||
| | | | | | (___ | | | | |_ _ _ __ ___ _ __ _ _ ___
|
||||
| | | | | \___ \ | | | | | | | | '_ ` _ \| '_ \| | | / __|
|
||||
| |__| | |____ ____) | | |__| | | |_| | | | | | | |_) | |_| \__ \
|
||||
|_____/ \_____|_____/ \____/|_|\__, |_| |_| |_| .__/ \__,_|___/
|
||||
__/ | | |
|
||||
|___/ |_|
|
||||
|
||||
{{OLYMPUS_VERSION_NUMBER}}
|
||||
|
||||
==========================================
|
||||
INSTALLATION INSTRUCTIONS
|
||||
|
||||
1) Close any applications which may interfere with installation, including Digital Combat Simulator (DCS) and previous versions of Olympus.
|
||||
|
||||
2) If you DO NOT have Olympus already installed, SKIP THIS STEP. If you have already installed Olympus, do the following:
|
||||
NOTE: If you made any changes to your unit databases or mods.lua file (e.g. to support a third party mod) make a backup of the edited files before proceeding or changes will be lost;
|
||||
a) If you installed DCS Olympus v1.0.3 using the installer, simply remove it using Windows's "Add or remove programs" application.
|
||||
b) If you installed DCS Olympus v1.0.3 using the archived version, remove it by deleting the "...<DCS Saved Games folder>\Mods\Services\Olympus" folder. Do this for every DCS instance you installed Olympus in.
|
||||
Remember to delete any shortcuts you created. Don't worry, they will be created automatically again by the installation script provided in this package.
|
||||
|
||||
3) Create a folder named "DCS Olympus" in your "Saved Games" directory and extract all the contents of the downloaded package into it.
|
||||
NOTE:
|
||||
a) Do not extract the contents of the package directly in your Saved Games folder or in your DCS Saved Games folder.
|
||||
b) Unlike previous version of Olympus, it is no longer necessary to copy the packaged files into each DCS instance folder.
|
||||
|
||||
4) Execute the "installer.bat" script by double-clicking on it. It is located in the folder you created in step 3. Wait for the installation script to complete. Installation may take a couple of minutes, after which the Manager will start automatically.
|
||||
NOTE: depending on your Windows configuration, the script may be called "installer" (without .bat at the end).
|
||||
|
||||
5) The Olympus Manager will open. This will allow you to add/remove Olympus to individual DCS instances.
|
||||
Use the Olympus Manager and follow the instructions to install and setup Olympus.
|
||||
|
||||
6) Start DCS and run a mission. Make sure it is UNPAUSED.
|
||||
|
||||
7) Open Olympus via the shortcut and login using any username and the Game Master password set using the Manager. (NOTE: not your DCS server password).
|
||||
Local installation: run the client from the provided desktop shortcut or start it using the "View and manage instances" page of the Manager.
|
||||
Dedicated server: users must first start the Olympus server from the provided desktop shortcut or using the "View and manage instances" page of the Manager.
|
||||
Then log in using any browser and visiting "http:\\<server IP>:<frontend port>" (frontend port is 3000 by default, but can be edited using the Manager)
|
||||
|
||||
8) You can use the manager at any time to change the ports and/or passwords. If you do, REMEMBER TO RESTART OLYMPUS AND DCS.
|
||||
|
||||
|
||||
NOTES:
|
||||
a) when launching the Manager you will be prompted to allow Electron to create a firewall rule. This is optional and can be denied without effect on the operation of the Manager;
|
||||
b) if you are using Olympus on a dedicated server with a router, you must enable port forwarding on the frontend port (3000 by default);
|
||||
c) unlike Olympus v1.0.3, running the netsh command is no longer required. It is also no longer required to create firewall rules or port forwarding for the backend port. (Optional) If you already performed this steps in the past you can delete the firewall and netsh rules.
|
||||
|
||||
|
||||
==========================================
|
||||
UPDATING INSTRUCTIONS
|
||||
|
||||
IF YOU ARE UPDATING FROM DCS OLYMPUS v1.0.3, FOLLOW THE "INSTALLATION INSTRUCTIONS".
|
||||
|
||||
To update your Olympus installation you have two options:
|
||||
a) download the new package from the GitHub releases page, delete the old unpacked package folder, then follow the INSTALLATION INSTRUCTIONS;
|
||||
b) run the Olympus Manager. If an update is available you will be given the option to automatically update Olympus from there.
|
||||
|
||||
For either options a) or b), remember to close any applications which may interfere with installation, including Digital Combat Simulator (DCS) and previous versions of Olympus.
|
||||
@@ -2,13 +2,15 @@ DCS Olympus
|
||||
|
||||
A real-time AI unit control mod for DCS World
|
||||
|
||||
Copyright (C) 2023 Veltro & Gang
|
||||
Copyright (C) 2023 Veltro & Gang (the "DCS Olympus Team" or the
|
||||
"Rightsholders")
|
||||
|
||||
DCS Olympus (the "MATERIAL" or "Software") is provided completely free
|
||||
to users subject to the it under both the terms of version 3 of the GNU
|
||||
General Public License as published by the Free Software Foundation, and
|
||||
the additional terms set out below; except where such terms conflict with this
|
||||
disclaimer, in which case, the terms of this disclaimer shall prevail.
|
||||
General Public License ("GPLv3") as published by the Free Software Foundation,
|
||||
and the additional terms set out below (the "Additional Terms"). In the event
|
||||
that the terms of GPLv3 conflict with the Additional Terms, the
|
||||
Additional Terms shall prevail.
|
||||
|
||||
The authors and/or copyright holders of the Software have not received any
|
||||
financial benefit in connection with the Software. In any event, the
|
||||
@@ -17,15 +19,14 @@ implied, including but not limited to the warranties of merchantability,
|
||||
fitness for a particular purpose and non-infringement. In no event shall
|
||||
the authors and/or copyright holders be liable for any claim, damages or
|
||||
other liability, whether in an action of contract, tort or otherwise,
|
||||
arising from, out of or in connection with the Software or the use or o
|
||||
ther dealings in the Software.
|
||||
|
||||
Any party making use of the Software in any manner agrees to be
|
||||
bound by the terms set out in this disclaimer, version 3 of the GNU
|
||||
General Public Licence, and the Additional Terms below.
|
||||
arising from, out of or in connection with the Software or the use or
|
||||
other dealings in the Software.
|
||||
|
||||
THIS MATERIAL IS NOT MADE OR SUPPORTED BY EAGLE DYNAMICS SA.
|
||||
|
||||
Any party making use of the Software in any manner agrees to be bound by
|
||||
the entirety of this document.
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
@@ -657,4 +658,21 @@ copy of the Program in return for a fee.
|
||||
GNU General Public Licence Version 3 above shall be governed by and
|
||||
interpreted in accordance with English Law and the parties submit to the
|
||||
exclusive jurisdiction of the English Courts.
|
||||
|
||||
|
||||
2. Entire Agreement
|
||||
|
||||
The text of this document contains the entire understanding between
|
||||
you, the licensee, and the authors and/or copyright holders of the
|
||||
Software with respect to the subject matter to which it pertains.
|
||||
It supersedes all prior agreements and understandings (if applicable),
|
||||
oral or written, with respect to such matters.
|
||||
|
||||
3. Unilateral Modification
|
||||
|
||||
The parties agree that the DCS Olympus Team shall have the right to
|
||||
unilaterally modify these terms (i.e. the agreement between you and the
|
||||
DCS Olympus Team for the use of the Software), and that parties shall
|
||||
be bound by such terms as modified from time to time. The DCS Olympus Team
|
||||
shall not have an obligation to inform you of such modification, save that
|
||||
such changes will be published on the DCS Olympus Github Repository located at
|
||||
https://github.com/Pax1601/DCSOlympus.
|
||||
101
README.md
101
README.md
@@ -1,40 +1,83 @@
|
||||
# Important note: DCS Olympus is in alpha state. No official release has been produced yet. The first public version is planned for Q4 2023.
|
||||
<img align="left" width="30" src="https://github.com/Pax1601/DCSOlympus/assets/103559271/0ecff279-a87c-4e2d-a4c7-da98c74adf38">
|
||||
|
||||
[**Join our Discord**](https://discord.gg/kNAQkhUHnQ)
|
||||
|
||||
<img align="left" width="30" src="https://github.com/Pax1601/DCSOlympus/assets/103559271/1c0dd3fd-339c-4b03-94da-3e5215b0358a">
|
||||
|
||||
[**YouTube**](https://www.youtube.com/@DCSOlympus)
|
||||
|
||||
|
||||
# DCS Olympus
|
||||
*A real-time web interface to spawn and control units in DCS World*
|
||||
|
||||

|
||||
|
||||
### What is this?
|
||||
DCS Olympus is a mod for DCS World. It allows users to spawn, control, task, group, and remove units from a DCS World server using a real-time map interface, similarly to Real Time Strategy games. The user interface also provides useful informations units, like loadouts, fuel, tasking, and so on. In the future, more features for DCS World GCI and JTAC will be available.
|
||||
DCS: Olympus is a free and open-source mod for DCS that enables dynamic real-time control through a map interface. The user is able to spawn units/groups, deploy a variety of effects such as smoke, flares, or explosions, and waypoints/tasks can be given to AI units in real-time in a way similar to a classic RTS game.
|
||||
|
||||
### Features and how to use it
|
||||
- Spawn air and ground units, with preset loadouts
|
||||
- Double click on the map to spawn a blue and red units, both in the air and in the ground, with preset loadouts for air-to-air or air-to-ground tasks;
|
||||
- Control units
|
||||
- Select one ore more units to move them around. Hold down ctrl and click to create a route for the unit to follow;
|
||||
- Attack other units
|
||||
- After selecting one ore more units, double click on another unit and select "Attack" to attack it, depending on the available weapons.
|
||||
Additionally Olympus is able to run several effects and unit behaviours beyond the core DCS offerings. This includes such things as napalm and white phosphosous explosions, or setting up AA units to fire at players and miss, and more.
|
||||
|
||||
It even includes Red and Blue modes which limit your view and powers to just seeing what your coalition sees, with a spawning budget you could play against your friends even with no-one in the game piloting, or have a Red commander working against a squadron of blue pilots, and/or a blue commander working with them.
|
||||
|
||||
Even better it requires no client mods be installed if used on a server
|
||||
|
||||
The full feature list is simply too long to enumerate in a short summary but needless to say Olympus offers up a lot of unique gameplay that has previously not existed, and enhances many other elements of DCS in exciting ways
|
||||
|
||||
### Installing DCS Olympus
|
||||
A prebuilt installer will soon be released and available here
|
||||
Check the [Wiki](https://github.com/Pax1601/DCSOlympus/wiki) for installation instructions
|
||||
|
||||
### Building DCS Olympus
|
||||
DCS Olympus is comprised of two modules:
|
||||
# Frequently Asked Questions
|
||||
|
||||
A "core" c++ .dll module, which is run by DCS and exposes all the necessary data, and provides endpoints for commands from a REST server. A Visual Studio 2017/2019/2022 solution is provided, and requires no additional configuration. The core dll solution has two dependencies, both can be installed using vcpkg (https://vcpkg.io/en/getting-started.html):
|
||||
- cpprestsdk: `vcpkg install cpprestsdk:x64-windows`
|
||||
- geographiclib: `vcpkg install geographiclib:x64-windows`
|
||||
|
||||
|
||||
A "client" node.js typescript web app, which can be hosted on the server using express.js. A Visual Studio Code configuration is provided for debugging. The client requires node.js to be installed for building (https://nodejs.org/en/). After installing node.js, move in the client folder and run the following commands:
|
||||
- `npm install`
|
||||
- `npm -g install`
|
||||
|
||||
After installing all the necessary dependencies you can start a development server executing the *client/debug.bat* batch file, and visiting http:\\localhost:3000 with any modern browser (tested with updated Chrome, Firefox and Edge). However, it is highly suggested to simply run the `Launch Chrome against localhost` debug configuration in Visual Studio Code.
|
||||
|
||||
|
||||
|
||||
|
||||
### I need troubleshooting guidance, please help? ###
|
||||
Read through the [Installation Guide](https://github.com/Pax1601/DCSOlympus/wiki) to ensure you have setup Olympus correctly.
|
||||
|
||||
Read through [Setup Troubleshooting](https://github.com/Pax1601/DCSOlympus/wiki/3.-Setup-FAQ-and-Troubleshooting) for common issues and solutions.
|
||||
|
||||
If you're still having issues after trying the steps above, please post in the community-support channel with the following:
|
||||
|
||||
A detailed description of your issue
|
||||
Your Olympus log file \user home folder\AppData\Local\Temp\Olympus_log.txt for some it might be in \DCS Saved Games folder\Logs\Olympus_log.txt
|
||||
Your DCS log file \DCS Saved Games folder\Logs\dcs.log
|
||||
|
||||
Screenshots of any relevant screens or issues and any other pertinent information.
|
||||
|
||||
### Can I join up and help out with the project? ###
|
||||
Absolutely, join the discord and ping any of the developers to get briefed.
|
||||
|
||||
### Can I be a beta/alpha-tester? ###
|
||||
Same as above!
|
||||
|
||||
### Do you have a roadmap? ###
|
||||
We do not have a roadmap no, we have a laundry list of things we are hoping to do.
|
||||
|
||||
These include but are not limited to:
|
||||
1) Enhancements to helicopter play
|
||||
2) More features around use of ground units
|
||||
3) More unique effects and behaviours
|
||||
4) ATC/AIC features
|
||||
5) Usability features like unit painters etc
|
||||
|
||||
However we cannot commit to specific features, feature release order, or timelines, please remember this isn't our job and we work on it in our free time because we love DCS
|
||||
|
||||
### Does Olympus support mods? ###
|
||||
Generally OIympus will not have any issues with other mods, however you may need to tell olympus about modded units in order to be able to dynamically spawn them etc
|
||||
Keep in mind that any mods you do choose to spawn your players will need to have, some mod unit just appear as a su27 or leo2 etc. When a player is missing them, others can cause client crashes. So be smart about how you use them.
|
||||
|
||||
### Is Olympus compatible with mission scripts? ###
|
||||
We have tried hard to keep Olympus from interfering with other scripts, we have tested with a variety of new and old mission scripts and generally expect it will not be an issue.
|
||||
|
||||
However we cannot foresee everything people come up with so we suggest testing with what you have in mind once olympus releases
|
||||
|
||||
### How does it work? ###
|
||||
The quick answer is magic.
|
||||
The long answer is well all the code is there for you to read.
|
||||
The middle answer is a bit like SRS does. Olympus consists of two parts.
|
||||
|
||||
(A) Olympus back end: A dll, run by DCS, that sends data out and gets commands in via a REST API;
|
||||
(B) Webserver exe: The one you start when starting the server via the desktop shortcut.
|
||||
|
||||
A and B never communicate when you connect the client you download the web page and some other minor stuff from B, and you get the DCS data from and send commands to A.
|
||||
|
||||
### How much does Olympus impact performance? ###
|
||||
Olympus by itself should not have a noticeable impact on server performance, however the ability for the user to spawn arbitrary units and command engagements means Olympus can be used in such a way that brings the game to it's knees.
|
||||
|
||||
Be cognizant of how you play, whether it's done through Olympus or the mission editor 500 MLRS units firing at once is not going to go over well with most servers
|
||||
|
||||
|
||||
|
||||
12
backend/DCSOlympus.props
Normal file
12
backend/DCSOlympus.props
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnableManifest>true</VcpkgEnableManifest>
|
||||
<VcpkgAutoLink>true</VcpkgAutoLink>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup />
|
||||
<ItemGroup />
|
||||
</Project>
|
||||
110
backend/core/core.rc
Normal file
110
backend/core/core.rc
Normal file
@@ -0,0 +1,110 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Italian (Italy) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
|
||||
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // Italian (Italy) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United Kingdom) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,0,0,0
|
||||
PRODUCTVERSION 1,0,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "DCS Olympus"
|
||||
VALUE "FileDescription", "DCS Olympus"
|
||||
VALUE "FileVersion", "2.0.0.0"
|
||||
VALUE "InternalName", "core.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2023"
|
||||
VALUE "OriginalFilename", "core.dll"
|
||||
VALUE "ProductName", "DCS Olympus"
|
||||
VALUE "ProductVersion", "2.0.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (United Kingdom) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
<ClInclude Include="include\unitsmanager.h" />
|
||||
<ClInclude Include="include\weapon.h" />
|
||||
<ClInclude Include="include\weaponsmanager.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\aircraft.cpp" />
|
||||
@@ -65,6 +66,9 @@
|
||||
<ClCompile Include="src\weapon.cpp" />
|
||||
<ClCompile Include="src\weaponsmanager.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="core.rc" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
@@ -106,22 +110,26 @@
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>.\..\..\bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>.\..\..\bin\</OutDir>
|
||||
<OutDir>.\..\..\build\backend\bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
@@ -174,6 +182,7 @@
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>lua.lib; GeographicLib-i.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\third-party\lua</AdditionalLibraryDirectories>
|
||||
<Version>{{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}</Version>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -51,6 +51,7 @@
|
||||
<ClInclude Include="include\weaponsmanager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\aircraft.cpp">
|
||||
@@ -99,4 +100,7 @@
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="core.rc" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "airunit.h"
|
||||
|
||||
#define AIRCRAFT_DEST_DIST_THR 2000 // Meters
|
||||
|
||||
class Aircraft : public AirUnit
|
||||
{
|
||||
public:
|
||||
@@ -11,6 +13,8 @@ public:
|
||||
virtual void changeSpeed(string change);
|
||||
virtual void changeAltitude(string change);
|
||||
|
||||
virtual double getDestinationReachedThreshold() { return AIRCRAFT_DEST_DIST_THR; }
|
||||
|
||||
protected:
|
||||
static json::value database;
|
||||
};
|
||||
@@ -17,6 +17,13 @@ public:
|
||||
|
||||
virtual void changeSpeed(string change) = 0;
|
||||
virtual void changeAltitude(string change) = 0;
|
||||
virtual double getDestinationReachedThreshold() { return AIR_DEST_DIST_THR; }
|
||||
|
||||
virtual void setRacetrackLength(double newValue);
|
||||
virtual void setRacetrackAnchor(Coords newValue);
|
||||
virtual void setRacetrackBearing(double newValue);
|
||||
|
||||
virtual void setCargoWeight(double newValue);
|
||||
|
||||
protected:
|
||||
virtual void AIloop();
|
||||
@@ -5,6 +5,11 @@
|
||||
#include "logger.h"
|
||||
#include "datatypes.h"
|
||||
|
||||
struct CommandResult {
|
||||
string hash;
|
||||
string result;
|
||||
};
|
||||
|
||||
namespace CommandPriority {
|
||||
enum CommandPriorities { LOW, MEDIUM, HIGH, IMMEDIATE };
|
||||
};
|
||||
@@ -18,6 +23,7 @@ namespace SetCommandType {
|
||||
FORMATION = 5,
|
||||
RTB_ON_BINGO = 6,
|
||||
SILENCE = 7,
|
||||
ALARM_STATE = 9,
|
||||
RTB_ON_OUT_OF_AMMO = 10,
|
||||
ECM_USING = 13,
|
||||
PROHIBIT_AA = 14,
|
||||
@@ -45,6 +51,14 @@ namespace ROE {
|
||||
};
|
||||
}
|
||||
|
||||
namespace AlarmState {
|
||||
enum AlarmStates {
|
||||
AUTO = 0,
|
||||
GREEN = 1,
|
||||
RED = 2,
|
||||
};
|
||||
}
|
||||
|
||||
namespace ReactionToThreat {
|
||||
enum ReactionsToThreat {
|
||||
NO_REACTION = 0,
|
||||
@@ -113,7 +127,7 @@ class Move : public Command
|
||||
{
|
||||
public:
|
||||
Move(string groupName, Coords destination, double speed, string speedType, double altitude,
|
||||
string altitudeType, string taskOptions, string category, function<void(void)> callback = []() {}) :
|
||||
string altitudeType, string taskOptions, string category, bool onRoad, function<void(void)> callback = []() {}) :
|
||||
Command(callback),
|
||||
groupName(groupName),
|
||||
destination(destination),
|
||||
@@ -122,12 +136,13 @@ public:
|
||||
altitude(altitude),
|
||||
altitudeType(altitudeType),
|
||||
taskOptions(taskOptions),
|
||||
category(category)
|
||||
category(category),
|
||||
onRoad(onRoad)
|
||||
{
|
||||
priority = CommandPriority::HIGH;
|
||||
priority = CommandPriority::MEDIUM;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 2; }
|
||||
virtual unsigned int getLoad() { return onRoad? 45: 5; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -138,6 +153,7 @@ private:
|
||||
const string altitudeType;
|
||||
const string taskOptions;
|
||||
const string category;
|
||||
const bool onRoad;
|
||||
};
|
||||
|
||||
/* Smoke command */
|
||||
@@ -173,7 +189,7 @@ public:
|
||||
priority = immediate? CommandPriority::IMMEDIATE: CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return immediate? 1: 30; }
|
||||
virtual unsigned int getLoad() { return immediate? 5: 30; }
|
||||
|
||||
private:
|
||||
const string coalition;
|
||||
@@ -196,7 +212,7 @@ public:
|
||||
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return immediate ? 1 : 30; }
|
||||
virtual unsigned int getLoad() { return immediate ? 5 : 60; }
|
||||
|
||||
private:
|
||||
const string coalition;
|
||||
@@ -220,7 +236,7 @@ public:
|
||||
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return immediate ? 1 : 30; }
|
||||
virtual unsigned int getLoad() { return immediate ? 5 : 45; }
|
||||
|
||||
private:
|
||||
const string coalition;
|
||||
@@ -245,7 +261,7 @@ public:
|
||||
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return immediate ? 1 : 30; }
|
||||
virtual unsigned int getLoad() { return immediate ? 5 : 45; }
|
||||
|
||||
private:
|
||||
const string coalition;
|
||||
@@ -289,7 +305,7 @@ public:
|
||||
immediate = immediate;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return immediate? 1: 5; }
|
||||
virtual unsigned int getLoad() { return immediate? 1: 30; }
|
||||
|
||||
private:
|
||||
const unsigned int ID;
|
||||
@@ -310,7 +326,7 @@ public:
|
||||
priority = CommandPriority::MEDIUM;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -328,7 +344,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -346,7 +362,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -379,7 +395,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -401,7 +417,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -421,10 +437,145 @@ public:
|
||||
priority = CommandPriority::MEDIUM;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 4; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const Coords location;
|
||||
const unsigned int intensity;
|
||||
const string explosionType;
|
||||
};
|
||||
|
||||
/* Shine a laser with a specific code */
|
||||
class FireLaser : public Command
|
||||
{
|
||||
public:
|
||||
FireLaser(unsigned int ID, unsigned int code, Coords destination, function<void(void)> callback = []() {}) :
|
||||
Command(callback),
|
||||
ID(ID),
|
||||
destination(destination),
|
||||
code(code)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const unsigned int ID;
|
||||
const unsigned int code;
|
||||
const Coords destination;
|
||||
};
|
||||
|
||||
/* Shine a infrared light */
|
||||
class FireInfrared : public Command
|
||||
{
|
||||
public:
|
||||
FireInfrared(unsigned int ID, Coords destination, function<void(void)> callback = []() {}) :
|
||||
Command(callback),
|
||||
ID(ID),
|
||||
destination(destination)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const unsigned int ID;
|
||||
const Coords destination;
|
||||
};
|
||||
|
||||
/* Change a laser code */
|
||||
class SetLaserCode : public Command
|
||||
{
|
||||
public:
|
||||
SetLaserCode(unsigned int spotID, unsigned int code, function<void(void)> callback = []() {}) :
|
||||
Command(callback),
|
||||
spotID(spotID),
|
||||
code(code)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const unsigned int spotID;
|
||||
const unsigned int code;
|
||||
};
|
||||
|
||||
/* Delete a spot code */
|
||||
class DeleteSpot : public Command
|
||||
{
|
||||
public:
|
||||
DeleteSpot(unsigned int spotID, function<void(void)> callback = []() {}) :
|
||||
Command(callback),
|
||||
spotID(spotID)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const unsigned int spotID;
|
||||
};
|
||||
|
||||
/* Move spot to a new target */
|
||||
class MoveSpot : public Command
|
||||
{
|
||||
public:
|
||||
MoveSpot(unsigned int spotID, Coords destination, function<void(void)> callback = []() {}) :
|
||||
Command(callback),
|
||||
spotID(spotID),
|
||||
destination(destination)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const unsigned int spotID;
|
||||
const Coords destination;
|
||||
};
|
||||
|
||||
/* Set cargo weight */
|
||||
class SetCargoWeight : public Command
|
||||
{
|
||||
public:
|
||||
SetCargoWeight(unsigned int ID, double weight, function<void(void)> callback = []() {}) :
|
||||
Command(callback),
|
||||
ID(ID),
|
||||
weight(weight)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const unsigned int ID;
|
||||
const double weight;
|
||||
};
|
||||
|
||||
/* Register draw argument */
|
||||
class RegisterDrawArgument : public Command
|
||||
{
|
||||
public:
|
||||
RegisterDrawArgument(unsigned int ID, unsigned int argument, bool active, function<void(void)> callback = []() {}) :
|
||||
Command(callback),
|
||||
ID(ID),
|
||||
argument(argument),
|
||||
active(active)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const unsigned int ID;
|
||||
const unsigned int argument;
|
||||
const bool active;
|
||||
};
|
||||
@@ -7,12 +7,17 @@ namespace DataIndex {
|
||||
startOfData = 0,
|
||||
category,
|
||||
alive,
|
||||
alarmState,
|
||||
radarState,
|
||||
human,
|
||||
controlled,
|
||||
coalition,
|
||||
country,
|
||||
name,
|
||||
unitName,
|
||||
callsign,
|
||||
unitID,
|
||||
groupID,
|
||||
groupName,
|
||||
state,
|
||||
task,
|
||||
@@ -22,6 +27,7 @@ namespace DataIndex {
|
||||
horizontalVelocity,
|
||||
verticalVelocity,
|
||||
heading,
|
||||
track,
|
||||
isActiveTanker,
|
||||
isActiveAWACS,
|
||||
onOff,
|
||||
@@ -49,6 +55,25 @@ namespace DataIndex {
|
||||
shotsScatter,
|
||||
shotsIntensity,
|
||||
health,
|
||||
racetrackLength,
|
||||
racetrackAnchor,
|
||||
racetrackBearing,
|
||||
timeToNextTasking,
|
||||
barrelHeight,
|
||||
muzzleVelocity,
|
||||
aimTime,
|
||||
shotsToFire,
|
||||
shotsBaseInterval,
|
||||
shotsBaseScatter,
|
||||
engagementRange,
|
||||
targetingRange,
|
||||
aimMethodRange,
|
||||
acquisitionRange,
|
||||
airborne,
|
||||
cargoWeight,
|
||||
drawArguments,
|
||||
customString,
|
||||
customInteger,
|
||||
lastIndex,
|
||||
endOfData = 255
|
||||
};
|
||||
@@ -138,6 +163,11 @@ namespace DataTypes {
|
||||
unsigned int ID = 0;
|
||||
unsigned char detectionMethod = 0;
|
||||
};
|
||||
|
||||
struct DrawArgument {
|
||||
unsigned int argument = 0;
|
||||
double value = 0.0;
|
||||
};
|
||||
}
|
||||
#pragma pack(pop)
|
||||
|
||||
@@ -146,12 +176,16 @@ bool operator==(const DataTypes::Radio& lhs, const DataTypes::Radio& rhs);
|
||||
bool operator==(const DataTypes::GeneralSettings& lhs, const DataTypes::GeneralSettings& rhs);
|
||||
bool operator==(const DataTypes::Ammo& lhs, const DataTypes::Ammo& rhs);
|
||||
bool operator==(const DataTypes::Contact& lhs, const DataTypes::Contact& rhs);
|
||||
bool operator==(const DataTypes::DrawArgument& lhs, const DataTypes::DrawArgument& rhs);
|
||||
|
||||
struct SpawnOptions {
|
||||
string unitType;
|
||||
Coords location;
|
||||
string loadout;
|
||||
string skill;
|
||||
string liveryID;
|
||||
double heading;
|
||||
string payload;
|
||||
};
|
||||
|
||||
struct CloneOptions {
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "unit.h"
|
||||
|
||||
#define GROUND_DEST_DIST_THR 100
|
||||
#define GROUND_DEST_DIST_THR 10
|
||||
|
||||
class GroundUnit : public Unit
|
||||
{
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
virtual void setOnOff(bool newOnOff, bool force = false);
|
||||
virtual void setFollowRoads(bool newFollowRoads, bool force = false);
|
||||
|
||||
void aimAtPoint(Coords aimTarget, double horizontalScatterMultiplier = 1, double verticalScatterMultiplier = 1);
|
||||
string aimAtPoint(Coords aimTarget);
|
||||
|
||||
protected:
|
||||
virtual void AIloop();
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "airunit.h"
|
||||
|
||||
#define HELICOPTER_DEST_DIST_THR 500 // Meters
|
||||
|
||||
class Helicopter : public AirUnit
|
||||
{
|
||||
public:
|
||||
@@ -11,6 +13,8 @@ public:
|
||||
virtual void changeSpeed(string change);
|
||||
virtual void changeAltitude(string change);
|
||||
|
||||
virtual double getDestinationReachedThreshold() { return HELICOPTER_DEST_DIST_THR; }
|
||||
|
||||
protected:
|
||||
static json::value database;
|
||||
};
|
||||
@@ -13,7 +13,14 @@ public:
|
||||
void execute(lua_State* L);
|
||||
void handleRequest(string key, json::value value, string username, json::value& answer);
|
||||
bool checkSpawnPoints(int spawnPoints, string coalition);
|
||||
bool isCommandExecuted(string commandHash) { return (find(executedCommandsHashes.begin(), executedCommandsHashes.end(), commandHash) != executedCommandsHashes.end()); }
|
||||
bool isCommandExecuted(string commandHash) {
|
||||
for (auto& commandResult : executedCommandResults) {
|
||||
if (commandResult.hash == commandHash) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void setFrameRate(double newFrameRate) { frameRate = newFrameRate; }
|
||||
void setRestrictSpawns(bool newRestrictSpawns) { restrictSpawns = newRestrictSpawns; }
|
||||
@@ -24,7 +31,7 @@ public:
|
||||
void setEras(vector<string> newEras) { eras = newEras; }
|
||||
void setCommandModeOptions(json::value newOptions);
|
||||
|
||||
int getFrameRate() { return frameRate; };
|
||||
int getFrameRate() { return static_cast<int>(round(frameRate)); };
|
||||
int getLoad();
|
||||
bool getRestrictSpawns() { return restrictSpawns; }
|
||||
bool getRestrictToCoalition() { return restrictToCoalition; }
|
||||
@@ -36,7 +43,7 @@ public:
|
||||
|
||||
private:
|
||||
list<Command*> commands;
|
||||
list<string> executedCommandsHashes;
|
||||
list<CommandResult> executedCommandResults;
|
||||
unsigned int load = 0;
|
||||
double frameRate = 0;
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
function Olympus.protectedCall(...)\n\n \
|
||||
local status, retval = pcall(...)\n \
|
||||
if not status then\n \
|
||||
trigger.action.outText(\"ERROR: \" ..retval, 20)\n \
|
||||
if Olympus.log ~= nil then\n \
|
||||
Olympus.log:error(retval)\n \
|
||||
else\n \
|
||||
trigger.action.outText(\"Olympus critical error: \" ..retval, 20)\n \
|
||||
end\n \
|
||||
end\n \
|
||||
end\n \
|
||||
trigger.action.outText(\"Olympus.protectedCall registered successfully\", 10)\n"
|
||||
@@ -19,12 +19,12 @@ public:
|
||||
~Unit();
|
||||
|
||||
/********** Methods **********/
|
||||
void initialize(json::value json);
|
||||
virtual void initialize(json::value json) final;
|
||||
virtual void setDefaults(bool force = false);
|
||||
|
||||
void runAILoop();
|
||||
|
||||
void update(json::value json, double dt);
|
||||
virtual void update(json::value json, double dt) final;
|
||||
void refreshLeaderData(unsigned long long time);
|
||||
|
||||
unsigned int getID() { return ID; }
|
||||
@@ -62,15 +62,21 @@ public:
|
||||
bool hasFreshData(unsigned long long time);
|
||||
bool checkFreshness(unsigned char datumIndex, unsigned long long time);
|
||||
|
||||
unsigned int computeTotalAmmo();
|
||||
|
||||
/********** Setters **********/
|
||||
virtual void setCategory(string newValue) { updateValue(category, newValue, DataIndex::category); }
|
||||
virtual void setAlive(bool newValue) { updateValue(alive, newValue, DataIndex::alive); }
|
||||
virtual void setAlarmState(unsigned char newValue, bool force = false);
|
||||
virtual void setHuman(bool newValue) { updateValue(human, newValue, DataIndex::human); }
|
||||
virtual void setControlled(bool newValue) { updateValue(controlled, newValue, DataIndex::controlled); }
|
||||
virtual void setCoalition(unsigned char newValue) { updateValue(coalition, newValue, DataIndex::coalition); }
|
||||
virtual void setCountry(unsigned char newValue) { updateValue(country, newValue, DataIndex::country); }
|
||||
virtual void setName(string newValue) { updateValue(name, newValue, DataIndex::name); }
|
||||
virtual void setUnitName(string newValue) { updateValue(unitName, newValue, DataIndex::unitName); }
|
||||
virtual void setCallsign(string newValue) { updateValue(callsign, newValue, DataIndex::callsign); }
|
||||
virtual void setUnitID(unsigned int newValue) { updateValue(unitID, newValue, DataIndex::unitID); }
|
||||
virtual void setGroupID(unsigned int newValue) { updateValue(groupID, newValue, DataIndex::groupID); }
|
||||
virtual void setGroupName(string newValue) { updateValue(groupName, newValue, DataIndex::groupName); }
|
||||
virtual void setState(unsigned char newValue) { updateValue(state, newValue, DataIndex::state); };
|
||||
virtual void setTask(string newValue) { updateValue(task, newValue, DataIndex::task); }
|
||||
@@ -80,6 +86,7 @@ public:
|
||||
virtual void setHorizontalVelocity(double newValue) { updateValue(horizontalVelocity, newValue, DataIndex::horizontalVelocity); }
|
||||
virtual void setVerticalVelocity(double newValue) { updateValue(verticalVelocity, newValue, DataIndex::verticalVelocity); }
|
||||
virtual void setHeading(double newValue) { updateValue(heading, newValue, DataIndex::heading); }
|
||||
virtual void setTrack(double newValue) { updateValue(track, newValue, DataIndex::track); }
|
||||
virtual void setIsActiveTanker(bool newValue);
|
||||
virtual void setIsActiveAWACS(bool newValue);
|
||||
virtual void setOnOff(bool newValue, bool force = false) { updateValue(onOff, newValue, DataIndex::onOff); };
|
||||
@@ -107,17 +114,41 @@ public:
|
||||
virtual void setShotsScatter(unsigned char newValue) { updateValue(shotsScatter, newValue, DataIndex::shotsScatter); }
|
||||
virtual void setShotsIntensity(unsigned char newValue) { updateValue(shotsIntensity, newValue, DataIndex::shotsIntensity); }
|
||||
virtual void setHealth(unsigned char newValue) { updateValue(health, newValue, DataIndex::health); }
|
||||
virtual void setRacetrackLength(double newValue) { updateValue(racetrackLength, newValue, DataIndex::racetrackLength); }
|
||||
virtual void setRacetrackAnchor(Coords newValue) { updateValue(racetrackAnchor, newValue, DataIndex::racetrackAnchor); }
|
||||
virtual void setRacetrackBearing(double newValue) { updateValue(racetrackBearing, newValue, DataIndex::racetrackBearing); }
|
||||
virtual void setTimeToNextTasking(double newValue) { updateValue(timeToNextTasking, newValue, DataIndex::timeToNextTasking); }
|
||||
virtual void setBarrelHeight(double newValue) { updateValue(barrelHeight, newValue, DataIndex::barrelHeight); }
|
||||
virtual void setMuzzleVelocity(double newValue) { updateValue(muzzleVelocity, newValue, DataIndex::muzzleVelocity); }
|
||||
virtual void setAimTime(double newValue) { updateValue(aimTime, newValue, DataIndex::aimTime); }
|
||||
virtual void setShotsToFire(unsigned int newValue) { updateValue(shotsToFire, newValue, DataIndex::shotsToFire); }
|
||||
virtual void setShotsBaseInterval(double newValue) { updateValue(shotsBaseInterval, newValue, DataIndex::shotsBaseInterval); }
|
||||
virtual void setShotsBaseScatter(double newValue) { updateValue(shotsBaseScatter, newValue, DataIndex::shotsBaseScatter); }
|
||||
virtual void setEngagementRange(double newValue) { updateValue(engagementRange, newValue, DataIndex::engagementRange); }
|
||||
virtual void setTargetingRange(double newValue) { updateValue(targetingRange, newValue, DataIndex::targetingRange); }
|
||||
virtual void setAimMethodRange(double newValue) { updateValue(aimMethodRange, newValue, DataIndex::aimMethodRange); }
|
||||
virtual void setAcquisitionRange(double newValue) { updateValue(acquisitionRange, newValue, DataIndex::acquisitionRange); }
|
||||
virtual void setRadarState(bool newValue) { updateValue(radarState, newValue, DataIndex::radarState); }
|
||||
virtual void setAirborne(bool newValue) { updateValue(airborne, newValue, DataIndex::airborne); }
|
||||
virtual void setCargoWeight(double newValue) { updateValue(cargoWeight, newValue, DataIndex::cargoWeight); }
|
||||
virtual void setDrawArguments(vector<DataTypes::DrawArgument> newValue);
|
||||
virtual void setCustomString(string newValue) { updateValue(customString, newValue, DataIndex::customString); }
|
||||
virtual void setCustomInteger(unsigned long newValue) { updateValue(customInteger, newValue, DataIndex::customInteger); }
|
||||
|
||||
/********** Getters **********/
|
||||
virtual string getCategory() { return category; };
|
||||
virtual string getCategory() { return category; }
|
||||
virtual bool getAlive() { return alive; }
|
||||
virtual unsigned char getAlarmState() { return alarmState; }
|
||||
virtual bool getHuman() { return human; }
|
||||
virtual bool getControlled() { return controlled; }
|
||||
virtual unsigned char getCoalition() { return coalition; }
|
||||
virtual unsigned char getCountry() { return country; }
|
||||
virtual string getName() { return name; }
|
||||
virtual string getCallsign() { return callsign; }
|
||||
virtual string getUnitName() { return unitName; }
|
||||
virtual string getGroupName() { return groupName; }
|
||||
virtual unsigned int getUnitID() { return unitID; }
|
||||
virtual unsigned int getGroupID() { return groupID; }
|
||||
virtual unsigned char getState() { return state; }
|
||||
virtual string getTask() { return task; }
|
||||
virtual bool getHasTask() { return hasTask; }
|
||||
@@ -126,6 +157,7 @@ public:
|
||||
virtual double getHorizontalVelocity() { return horizontalVelocity; }
|
||||
virtual double getVerticalVelocity() { return verticalVelocity; }
|
||||
virtual double getHeading() { return heading; }
|
||||
virtual double getTrack() { return track; }
|
||||
virtual bool getIsActiveTanker() { return isActiveTanker; }
|
||||
virtual bool getIsActiveAWACS() { return isActiveAWACS; }
|
||||
virtual bool getOnOff() { return onOff; };
|
||||
@@ -146,13 +178,33 @@ public:
|
||||
virtual DataTypes::Radio getRadio() { return radio; }
|
||||
virtual DataTypes::GeneralSettings getGeneralSettings() { return generalSettings; }
|
||||
virtual vector<DataTypes::Ammo> getAmmo() { return ammo; }
|
||||
virtual vector<DataTypes::Contact> getTargets() { return contacts; }
|
||||
virtual vector<DataTypes::Contact> getContacts() { return contacts; }
|
||||
virtual list<Coords> getActivePath() { return activePath; }
|
||||
virtual bool getIsLeader() { return isLeader; }
|
||||
virtual unsigned char getOperateAs() { return operateAs; }
|
||||
virtual unsigned char getShotsScatter() { return shotsScatter; }
|
||||
virtual unsigned char getShotsIntensity() { return shotsIntensity; }
|
||||
virtual unsigned char getHealth() { return health; }
|
||||
virtual double getRacetrackLength() { return racetrackLength; }
|
||||
virtual Coords getRacetrackAnchor() { return racetrackAnchor; }
|
||||
virtual double getRacetrackBearing() { return racetrackBearing; }
|
||||
virtual double getTimeToNextTasking() { return timeToNextTasking; }
|
||||
virtual double getBarrelHeight() { return barrelHeight; }
|
||||
virtual double getMuzzleVelocity() { return muzzleVelocity; }
|
||||
virtual double getAimTime() { return aimTime; }
|
||||
virtual unsigned int getShotsToFire() { return shotsToFire; }
|
||||
virtual double getShotsBaseInterval() { return shotsBaseInterval; }
|
||||
virtual double getShotsBaseScatter() { return shotsBaseScatter; }
|
||||
virtual double getEngagementRange() { return engagementRange; }
|
||||
virtual double getTargetingRange() { return targetingRange; }
|
||||
virtual double getAimMethodRange() { return aimMethodRange; }
|
||||
virtual double getAcquisitionRange() { return acquisitionRange; }
|
||||
virtual bool getRadarState() { return radarState; }
|
||||
virtual bool getAirborne() { return airborne; }
|
||||
virtual double getCargoWeight() { return cargoWeight; }
|
||||
virtual vector<DataTypes::DrawArgument> getDrawArguments() { return drawArguments; }
|
||||
virtual string getCustomString() { return customString; }
|
||||
virtual unsigned long getCustomInteger() { return customInteger; }
|
||||
|
||||
protected:
|
||||
unsigned int ID;
|
||||
@@ -165,8 +217,13 @@ protected:
|
||||
unsigned char country = NULL;
|
||||
string name = "";
|
||||
string unitName = "";
|
||||
string callsign = "";
|
||||
unsigned int unitID = NULL;
|
||||
unsigned int groupID = NULL;
|
||||
string groupName = "";
|
||||
unsigned char state = State::NONE;
|
||||
unsigned char alarmState = AlarmState::AUTO;
|
||||
bool radarState = false;
|
||||
string task = "";
|
||||
bool hasTask = false;
|
||||
Coords position = Coords(NULL);
|
||||
@@ -174,6 +231,7 @@ protected:
|
||||
double horizontalVelocity = NULL;
|
||||
double verticalVelocity = NULL;
|
||||
double heading = NULL;
|
||||
double track = NULL;
|
||||
bool isActiveTanker = false;
|
||||
bool isActiveAWACS = false;
|
||||
bool onOff = true;
|
||||
@@ -184,10 +242,13 @@ protected:
|
||||
double desiredAltitude = 1;
|
||||
bool desiredAltitudeType = 0; /* ASL */
|
||||
unsigned int leaderID = NULL;
|
||||
double racetrackLength = NULL;
|
||||
Coords racetrackAnchor = Coords(NULL);
|
||||
double racetrackBearing = NULL;
|
||||
Offset formationOffset = Offset(NULL);
|
||||
unsigned int targetID = NULL;
|
||||
Coords targetPosition = Coords(NULL);
|
||||
unsigned char ROE = ROE::OPEN_FIRE_WEAPON_FREE;
|
||||
unsigned char ROE = ROE::OPEN_FIRE;
|
||||
unsigned char reactionToThreat = ReactionToThreat::EVADE_FIRE;
|
||||
unsigned char emissionsCountermeasures = EmissionCountermeasure::DEFEND;
|
||||
DataTypes::TACAN TACAN;
|
||||
@@ -202,22 +263,42 @@ protected:
|
||||
unsigned char shotsScatter = 2;
|
||||
unsigned char shotsIntensity = 2;
|
||||
unsigned char health = 100;
|
||||
double timeToNextTasking = 0;
|
||||
double barrelHeight = 0;
|
||||
double muzzleVelocity = 0;
|
||||
double aimTime = 0;
|
||||
unsigned int shotsToFire = 0;
|
||||
double shotsBaseInterval = 0;
|
||||
double shotsBaseScatter = 0;
|
||||
double engagementRange = 0;
|
||||
double targetingRange = 0;
|
||||
double aimMethodRange = 0;
|
||||
double acquisitionRange = 0;
|
||||
bool airborne = false;
|
||||
double cargoWeight = 0;
|
||||
vector<DataTypes::DrawArgument> drawArguments;
|
||||
|
||||
string customString = "";
|
||||
unsigned long customInteger = 0;
|
||||
|
||||
/********** Other **********/
|
||||
unsigned int taskCheckCounter = 0;
|
||||
unsigned int internalCounter = 0;
|
||||
Unit* missOnPurposeTarget = nullptr;
|
||||
bool hasTaskAssigned = false;
|
||||
double initialFuel = 0;
|
||||
map<unsigned char, unsigned long long> updateTimeMap;
|
||||
unsigned long long lastLoopTime = 0;
|
||||
bool enableTaskFailedCheck = false;
|
||||
unsigned long nextTaskingMilliseconds = 0;
|
||||
unsigned int totalShellsFired = 0;
|
||||
unsigned int shellsFiredAtTasking = 0;
|
||||
unsigned int oldAmmo = 0;
|
||||
|
||||
/********** Private methods **********/
|
||||
virtual void AIloop() = 0;
|
||||
|
||||
void appendString(stringstream& ss, const unsigned char& datumIndex, const string& datumValue) {
|
||||
const unsigned short size = datumValue.size();
|
||||
const unsigned short size = static_cast<unsigned short>(datumValue.size());
|
||||
ss.write((const char*)&datumIndex, sizeof(unsigned char));
|
||||
ss.write((const char*)&size, sizeof(unsigned short));
|
||||
ss << datumValue;
|
||||
@@ -242,7 +323,7 @@ protected:
|
||||
|
||||
template <typename T>
|
||||
void appendVector(stringstream& ss, const unsigned char& datumIndex, vector<T>& datumValue) {
|
||||
const unsigned short size = datumValue.size();
|
||||
const unsigned short size = static_cast<unsigned short>(datumValue.size());
|
||||
ss.write((const char*)&datumIndex, sizeof(unsigned char));
|
||||
ss.write((const char*)&size, sizeof(unsigned short));
|
||||
|
||||
@@ -252,7 +333,7 @@ protected:
|
||||
|
||||
template <typename T>
|
||||
void appendList(stringstream& ss, const unsigned char& datumIndex, list<T>& datumValue) {
|
||||
const unsigned short size = datumValue.size();
|
||||
const unsigned short size = static_cast<unsigned short>(datumValue.size());;
|
||||
ss.write((const char*)&datumIndex, sizeof(unsigned char));
|
||||
ss.write((const char*)&size, sizeof(unsigned short));
|
||||
|
||||
@@ -23,8 +23,8 @@ public:
|
||||
void deleteUnit(unsigned int ID, bool explosion, string explosionType, bool immediate);
|
||||
void acquireControl(unsigned int ID);
|
||||
void loadDatabases();
|
||||
Unit* getClosestUnit(Unit* unit, unsigned char coalition, vector<string> categories, double &distance);
|
||||
map<Unit*, double> getUnitsInRange(Unit* unit, unsigned char coalition, vector<string> categories, double range);
|
||||
Unit* getClosestUnit(Unit* unit, unsigned char coalition, vector<string> categories, double &distance, bool airborneOnly = true);
|
||||
map<Unit*, double> getUnitsInRange(Unit* unit, unsigned char coalition, vector<string> categories, double range, bool airborneOnly = true);
|
||||
|
||||
private:
|
||||
map<unsigned int, Unit*> units;
|
||||
@@ -59,7 +59,7 @@ protected:
|
||||
|
||||
/********** Private methods **********/
|
||||
void appendString(stringstream& ss, const unsigned char& datumIndex, const string& datumValue) {
|
||||
const unsigned short size = datumValue.size();
|
||||
const unsigned short size = static_cast<unsigned short>(datumValue.size());
|
||||
ss.write((const char*)&datumIndex, sizeof(unsigned char));
|
||||
ss.write((const char*)&size, sizeof(unsigned short));
|
||||
ss << datumValue;
|
||||
@@ -113,4 +113,10 @@ class Bomb : public Weapon
|
||||
{
|
||||
public:
|
||||
Bomb(json::value json, unsigned int ID);
|
||||
};
|
||||
|
||||
class Shell : public Weapon
|
||||
{
|
||||
public:
|
||||
Shell(json::value json, unsigned int ID);
|
||||
};
|
||||
14
backend/core/resource.h
Normal file
14
backend/core/resource.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by core.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -12,24 +12,18 @@ using namespace GeographicLib;
|
||||
extern Scheduler* scheduler;
|
||||
extern UnitsManager* unitsManager;
|
||||
json::value Aircraft::database = json::value();
|
||||
extern string instancePath;
|
||||
|
||||
void Aircraft::loadDatabase(string path) {
|
||||
char* buf = nullptr;
|
||||
size_t sz = 0;
|
||||
if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr)
|
||||
{
|
||||
std::ifstream ifstream(string(buf) + path);
|
||||
std::stringstream ss;
|
||||
ss << ifstream.rdbuf();
|
||||
std::error_code errorCode;
|
||||
database = json::value::parse(ss.str(), errorCode);
|
||||
if (database.is_object())
|
||||
log("Aircrafts database loaded correctly");
|
||||
else
|
||||
log("Error reading Aircrafts database file");
|
||||
|
||||
free(buf);
|
||||
}
|
||||
std::ifstream ifstream(instancePath + path);
|
||||
std::stringstream ss;
|
||||
ss << ifstream.rdbuf();
|
||||
std::error_code errorCode;
|
||||
database = json::value::parse(ss.str(), errorCode);
|
||||
if (database.is_object())
|
||||
log("Aircrafts database loaded correctly from " + instancePath + path);
|
||||
else
|
||||
log("Error reading Aircrafts database file");
|
||||
}
|
||||
|
||||
/* Aircraft */
|
||||
@@ -40,7 +34,6 @@ Aircraft::Aircraft(json::value json, unsigned int ID) : AirUnit(json, ID)
|
||||
setCategory("Aircraft");
|
||||
setDesiredSpeed(knotsToMs(300));
|
||||
setDesiredAltitude(ftToM(20000));
|
||||
|
||||
};
|
||||
|
||||
void Aircraft::changeSpeed(string change)
|
||||
@@ -54,11 +47,6 @@ void Aircraft::changeSpeed(string change)
|
||||
|
||||
if (getDesiredSpeed() < knotsToMs(50))
|
||||
setDesiredSpeed(knotsToMs(50));
|
||||
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
}
|
||||
|
||||
void Aircraft::changeAltitude(string change)
|
||||
@@ -75,14 +63,9 @@ void Aircraft::changeAltitude(string change)
|
||||
if (getDesiredAltitude() > 5000)
|
||||
setDesiredAltitude(getDesiredAltitude() + ftToM(2500));
|
||||
else if (getDesiredAltitude() >= 0)
|
||||
setDesiredAltitude(getDesiredAltitude() + ftToM(500));
|
||||
setDesiredAltitude(getDesiredAltitude() + ftToM(500));
|
||||
}
|
||||
|
||||
if (getDesiredAltitude() < 0)
|
||||
setDesiredAltitude(0);
|
||||
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
}
|
||||
@@ -40,6 +40,8 @@ void AirUnit::setDefaults(bool force)
|
||||
|
||||
void AirUnit::setState(unsigned char newState)
|
||||
{
|
||||
Coords currentTargetPosition = getTargetPosition();
|
||||
|
||||
/************ Perform any action required when LEAVING a state ************/
|
||||
if (newState != state) {
|
||||
switch (state) {
|
||||
@@ -119,19 +121,10 @@ void AirUnit::setState(unsigned char newState)
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::BOMB_POINT: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::CARPET_BOMB: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::BOMB_POINT:
|
||||
case State::CARPET_BOMB:
|
||||
case State::BOMB_BUILDING: {
|
||||
setTargetPosition(currentTargetPosition);
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
@@ -146,16 +139,28 @@ void AirUnit::setState(unsigned char newState)
|
||||
break;
|
||||
}
|
||||
|
||||
resetTask();
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
|
||||
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
|
||||
state = newState;
|
||||
|
||||
triggerUpdate(DataIndex::state);
|
||||
|
||||
AIloop();
|
||||
}
|
||||
|
||||
void AirUnit::AIloop()
|
||||
{
|
||||
srand(static_cast<unsigned int>(time(NULL)) + ID);
|
||||
|
||||
/* Reset the anchor */
|
||||
if (state != State::IDLE) {
|
||||
setRacetrackAnchor(Coords(NULL));
|
||||
setRacetrackBearing(NULL);
|
||||
setRacetrackLength(NULL);
|
||||
}
|
||||
|
||||
/* State machine */
|
||||
switch (state) {
|
||||
case State::IDLE: {
|
||||
@@ -168,21 +173,27 @@ void AirUnit::AIloop()
|
||||
|
||||
if (!getHasTask())
|
||||
{
|
||||
if (racetrackAnchor == Coords(NULL)) setRacetrackAnchor(position);
|
||||
if (racetrackBearing == NULL) setRacetrackBearing(heading);
|
||||
|
||||
std::ostringstream taskSS;
|
||||
if (isActiveTanker) {
|
||||
taskSS << "{ [1] = { id = 'Tanker' }, [2] = { id = 'Orbit', pattern = 'Race-Track', altitude = " <<
|
||||
desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" <<
|
||||
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "' }}";
|
||||
desiredAltitude << ", lat = " << racetrackAnchor.lat << ", lng = " << racetrackAnchor.lng << ", speed = " << desiredSpeed << ", altitudeType = '" <<
|
||||
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "', heading = " <<
|
||||
racetrackBearing << ", length = " << (racetrackLength != NULL ? racetrackLength : (50000 * 1.852)) << " }}";
|
||||
}
|
||||
else if (isActiveAWACS) {
|
||||
taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Circle', altitude = " <<
|
||||
desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" <<
|
||||
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "' }}";
|
||||
taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Race-Track', altitude = " <<
|
||||
desiredAltitude << ", lat = " << racetrackAnchor.lat << ", lng = " << racetrackAnchor.lng << ", speed = " << desiredSpeed << ", altitudeType = '" <<
|
||||
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "', heading = " <<
|
||||
racetrackBearing << ", length = " << (racetrackLength != NULL ? racetrackLength : (desiredSpeed * 30)) << " }}";
|
||||
}
|
||||
else {
|
||||
taskSS << "{ id = 'Orbit', pattern = 'Circle', altitude = " <<
|
||||
desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" <<
|
||||
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "'}";
|
||||
taskSS << "{ id = 'Orbit', pattern = 'Race-Track', altitude = " <<
|
||||
desiredAltitude << ", lat = " << racetrackAnchor.lat << ", lng = " << racetrackAnchor.lng << ", speed = " << desiredSpeed << ", altitudeType = '" <<
|
||||
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "', heading = " <<
|
||||
racetrackBearing << ", length = " << (racetrackLength != NULL ? racetrackLength: (desiredSpeed * 30)) << " }";
|
||||
}
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
@@ -218,7 +229,7 @@ void AirUnit::AIloop()
|
||||
goToDestination(enrouteTask);
|
||||
}
|
||||
else {
|
||||
if (isDestinationReached(AIR_DEST_DIST_THR)) {
|
||||
if (isDestinationReached(getDestinationReachedThreshold())) {
|
||||
if (updateActivePath(looping) && setActiveDestination())
|
||||
goToDestination(enrouteTask);
|
||||
else
|
||||
@@ -378,4 +389,53 @@ void AirUnit::AIloop()
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AirUnit::setRacetrackLength(double newRacetrackLength) {
|
||||
if (racetrackLength != newRacetrackLength) {
|
||||
racetrackLength = newRacetrackLength;
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::racetrackLength);
|
||||
}
|
||||
}
|
||||
|
||||
void AirUnit::setRacetrackAnchor(Coords newRacetrackAnchor) {
|
||||
if (racetrackAnchor != newRacetrackAnchor) {
|
||||
racetrackAnchor = newRacetrackAnchor;
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::racetrackAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
void AirUnit::setRacetrackBearing(double newRacetrackBearing) {
|
||||
if (racetrackBearing != newRacetrackBearing) {
|
||||
racetrackBearing = newRacetrackBearing;
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::racetrackBearing);
|
||||
}
|
||||
}
|
||||
|
||||
void AirUnit::setCargoWeight(double newCargoWeight) {
|
||||
if (cargoWeight != newCargoWeight) {
|
||||
cargoWeight = newCargoWeight;
|
||||
triggerUpdate(DataIndex::cargoWeight);
|
||||
|
||||
Command* command = dynamic_cast<Command*>(new SetCargoWeight(this->ID, cargoWeight));
|
||||
scheduler->appendCommand(command);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ extern UnitsManager* unitsManager;
|
||||
/* Move command */
|
||||
string Move::getString()
|
||||
{
|
||||
|
||||
std::ostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.move, "
|
||||
@@ -47,7 +46,9 @@ string SpawnGroundUnits::getString()
|
||||
<< "unitType = " << "\"" << spawnOptions[i].unitType << "\"" << ", "
|
||||
<< "lat = " << spawnOptions[i].location.lat << ", "
|
||||
<< "lng = " << spawnOptions[i].location.lng << ", "
|
||||
<< "liveryID = " << "\"" << spawnOptions[i].liveryID << "\"" << " }, ";
|
||||
<< "heading = " << spawnOptions[i].heading << ", "
|
||||
<< "liveryID = " << "\"" << spawnOptions[i].liveryID << "\"" << ", "
|
||||
<< "skill = \"" << spawnOptions[i].skill << "\"" << "}, ";
|
||||
}
|
||||
|
||||
std::ostringstream commandSS;
|
||||
@@ -57,6 +58,7 @@ string SpawnGroundUnits::getString()
|
||||
<< "coalition = " << "\"" << coalition << "\"" << ", "
|
||||
<< "country = \"" << country << "\", "
|
||||
<< "units = " << "{" << unitsSS.str() << "}" << "}";
|
||||
commandSS << ", \"" << this->getHash() << "\"";
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
@@ -71,7 +73,9 @@ string SpawnNavyUnits::getString()
|
||||
<< "unitType = " << "\"" << spawnOptions[i].unitType << "\"" << ", "
|
||||
<< "lat = " << spawnOptions[i].location.lat << ", "
|
||||
<< "lng = " << spawnOptions[i].location.lng << ", "
|
||||
<< "liveryID = " << "\"" << spawnOptions[i].liveryID << "\"" << " }, ";
|
||||
<< "heading = " << spawnOptions[i].heading << ", "
|
||||
<< "liveryID = " << "\"" << spawnOptions[i].liveryID << "\"" << ", "
|
||||
<< "skill = \"" << spawnOptions[i].skill << "\"" << "}, ";
|
||||
}
|
||||
|
||||
std::ostringstream commandSS;
|
||||
@@ -81,6 +85,7 @@ string SpawnNavyUnits::getString()
|
||||
<< "coalition = " << "\"" << coalition << "\"" << ", "
|
||||
<< "country = \"" << country << "\", "
|
||||
<< "units = " << "{" << unitsSS.str() << "}" << "}";
|
||||
commandSS << ", \"" << this->getHash() << "\"";
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
@@ -95,8 +100,11 @@ string SpawnAircrafts::getString()
|
||||
<< "lat = " << spawnOptions[i].location.lat << ", "
|
||||
<< "lng = " << spawnOptions[i].location.lng << ", "
|
||||
<< "alt = " << spawnOptions[i].location.alt << ", "
|
||||
<< "heading = " << spawnOptions[i].heading << ", "
|
||||
<< "loadout = \"" << spawnOptions[i].loadout << "\"" << ", "
|
||||
<< "liveryID = " << "\"" << spawnOptions[i].liveryID << "\"" << " }, ";
|
||||
<< "payload = " << spawnOptions[i].payload << ", "
|
||||
<< "liveryID = " << "\"" << spawnOptions[i].liveryID << "\"" << ", "
|
||||
<< "skill = \"" << spawnOptions[i].skill << "\"" << "}, ";
|
||||
}
|
||||
|
||||
std::ostringstream commandSS;
|
||||
@@ -107,6 +115,7 @@ string SpawnAircrafts::getString()
|
||||
<< "airbaseName = \"" << airbaseName << "\", "
|
||||
<< "country = \"" << country << "\", "
|
||||
<< "units = " << "{" << unitsSS.str() << "}" << "}";
|
||||
commandSS << ", \"" << this->getHash() << "\"";
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
@@ -122,8 +131,11 @@ string SpawnHelicopters::getString()
|
||||
<< "lat = " << spawnOptions[i].location.lat << ", "
|
||||
<< "lng = " << spawnOptions[i].location.lng << ", "
|
||||
<< "alt = " << spawnOptions[i].location.alt << ", "
|
||||
<< "heading = " << spawnOptions[i].heading << ", "
|
||||
<< "loadout = \"" << spawnOptions[i].loadout << "\"" << ", "
|
||||
<< "liveryID = " << "\"" << spawnOptions[i].liveryID << "\"" << " }, ";
|
||||
<< "payload = " << spawnOptions[i].payload << ", "
|
||||
<< "liveryID = " << "\"" << spawnOptions[i].liveryID << "\"" << ", "
|
||||
<< "skill = \"" << spawnOptions[i].skill << "\"" << "}, ";
|
||||
}
|
||||
|
||||
std::ostringstream commandSS;
|
||||
@@ -134,6 +146,7 @@ string SpawnHelicopters::getString()
|
||||
<< "airbaseName = \"" << airbaseName << "\", "
|
||||
<< "country = \"" << country << "\", "
|
||||
<< "units = " << "{" << unitsSS.str() << "}" << "}";
|
||||
commandSS << ", \"" << this->getHash() << "\"";
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
@@ -249,4 +262,85 @@ string Explosion::getString()
|
||||
<< location.lat << ", "
|
||||
<< location.lng;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* FireLaser command */
|
||||
string FireLaser::getString()
|
||||
{
|
||||
std::ostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.fireLaser, "
|
||||
<< ID << ", "
|
||||
<< code << ", "
|
||||
<< destination.lat << ", "
|
||||
<< destination.lng;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* FireInfrared command */
|
||||
string FireInfrared::getString()
|
||||
{
|
||||
std::ostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.fireInfrared, "
|
||||
<< ID << ", "
|
||||
<< destination.lat << ", "
|
||||
<< destination.lng;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* SetLaserCode command */
|
||||
string SetLaserCode::getString()
|
||||
{
|
||||
std::ostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.setLaserCode, "
|
||||
<< spotID << ", "
|
||||
<< code;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* MoveSpot command */
|
||||
string MoveSpot::getString()
|
||||
{
|
||||
std::ostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.moveSpot, "
|
||||
<< spotID << ", "
|
||||
<< destination.lat << ", "
|
||||
<< destination.lng;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* DeleteSpot command */
|
||||
string DeleteSpot::getString()
|
||||
{
|
||||
std::ostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.deleteSpot, "
|
||||
<< spotID;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* SetCargoWeight command */
|
||||
string SetCargoWeight::getString()
|
||||
{
|
||||
std::ostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.setCargoWeight, "
|
||||
<< ID << ", "
|
||||
<< weight;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* RegisterDrawArgument command */
|
||||
string RegisterDrawArgument::getString()
|
||||
{
|
||||
std::ostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.registerDrawArgument, "
|
||||
<< ID << ", "
|
||||
<< argument << ", "
|
||||
<< active;
|
||||
return commandSS.str();
|
||||
}
|
||||
@@ -22,9 +22,12 @@ Scheduler* scheduler = nullptr;
|
||||
|
||||
/* Data jsons */
|
||||
json::value missionData = json::value::object();
|
||||
json::value drawingsByLayer = json::value::object();
|
||||
json::value executionResults = json::value::object();
|
||||
|
||||
mutex mutexLock;
|
||||
string sessionHash;
|
||||
string instancePath;
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
@@ -51,9 +54,16 @@ extern "C" DllExport int coreDeinit(lua_State* L)
|
||||
}
|
||||
|
||||
/* Called when DCS simulation starts. All singletons are instantiated, and the custom Lua functions are registered in the Lua state. */
|
||||
extern "C" DllExport int coreInit(lua_State* L)
|
||||
extern "C" DllExport int coreInit(lua_State* L, const char* path)
|
||||
{
|
||||
instancePath = path;
|
||||
|
||||
log("Initializing core.dll with instance path " + instancePath);
|
||||
|
||||
sessionHash = random_string(16);
|
||||
|
||||
log("Random session hash " + sessionHash);
|
||||
|
||||
unitsManager = new UnitsManager(L);
|
||||
weaponsManager = new WeaponsManager(L);
|
||||
server = new Server(L);
|
||||
@@ -80,7 +90,7 @@ extern "C" DllExport int coreFrame(lua_State* L)
|
||||
frameCounter++;
|
||||
|
||||
const std::chrono::duration<double> executionDuration = std::chrono::system_clock::now() - lastExecution;
|
||||
if (executionDuration.count() > FRAMERATE_TIME_INTERVAL) {
|
||||
if (executionDuration.count() > (20 * FRAMERATE_TIME_INTERVAL)) {
|
||||
if (executionDuration.count() > 0) {
|
||||
scheduler->setFrameRate(frameCounter / executionDuration.count());
|
||||
frameCounter = 0;
|
||||
@@ -153,3 +163,28 @@ extern "C" DllExport int coreMissionData(lua_State * L)
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
extern "C" DllExport int coreDrawingsData(lua_State* L)
|
||||
{
|
||||
log("Olympus coreDrawingsData called successfully");
|
||||
|
||||
/* Lock for thread safety */
|
||||
lock_guard<mutex> guard(mutexLock);
|
||||
|
||||
lua_getglobal(L, "Olympus");
|
||||
lua_getfield(L, -1, "drawingsByLayer");
|
||||
luaTableToJSON(L, -1, drawingsByLayer);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
extern "C" DllExport int coreSetExecutionResults(lua_State* L)
|
||||
{
|
||||
/* Lock for thread safety */
|
||||
lock_guard<mutex> guard(mutexLock);
|
||||
|
||||
lua_getglobal(L, "Olympus");
|
||||
lua_getfield(L, -1, "executionResults");
|
||||
luaTableToJSON(L, -1, executionResults, true);
|
||||
return(0);
|
||||
}
|
||||
@@ -12,19 +12,24 @@ bool operator==(const DataTypes::Radio& lhs, const DataTypes::Radio& rhs)
|
||||
|
||||
bool operator==(const DataTypes::GeneralSettings& lhs, const DataTypes::GeneralSettings& rhs)
|
||||
{
|
||||
return lhs.prohibitAA == rhs.prohibitAA && lhs.prohibitAfterburner == rhs.prohibitAfterburner && lhs.prohibitAG == rhs.prohibitAG &&
|
||||
return lhs.prohibitAA == rhs.prohibitAA && lhs.prohibitAfterburner == rhs.prohibitAfterburner && lhs.prohibitAG == rhs.prohibitAG &&
|
||||
lhs.prohibitAirWpn == rhs.prohibitAirWpn && lhs.prohibitJettison == rhs.prohibitJettison;
|
||||
}
|
||||
|
||||
bool operator==(const DataTypes::Ammo& lhs, const DataTypes::Ammo& rhs)
|
||||
{
|
||||
return lhs.category == rhs.category && lhs.guidance == rhs.guidance && lhs.missileCategory == rhs.missileCategory &&
|
||||
return lhs.category == rhs.category && lhs.guidance == rhs.guidance && lhs.missileCategory == rhs.missileCategory &&
|
||||
lhs.quantity == rhs.quantity && strcmp(lhs.name, rhs.name) == 0;
|
||||
}
|
||||
|
||||
bool operator==(const DataTypes::DrawArgument& lhs, const DataTypes::DrawArgument& rhs)
|
||||
{
|
||||
return lhs.argument == rhs.argument && lhs.value == rhs.value;
|
||||
}
|
||||
|
||||
bool operator==(const DataTypes::Contact& lhs, const DataTypes::Contact& rhs)
|
||||
{
|
||||
return lhs.detectionMethod == rhs.detectionMethod && lhs.ID == rhs.ID;
|
||||
return lhs.detectionMethod == rhs.detectionMethod && lhs.ID == rhs.ID;
|
||||
}
|
||||
|
||||
|
||||
657
backend/core/src/groundunit.cpp
Normal file
657
backend/core/src/groundunit.cpp
Normal file
@@ -0,0 +1,657 @@
|
||||
#include "groundunit.h"
|
||||
#include "utils.h"
|
||||
#include "logger.h"
|
||||
#include "commands.h"
|
||||
#include "scheduler.h"
|
||||
#include "defines.h"
|
||||
#include "unitsmanager.h"
|
||||
|
||||
#include <GeographicLib/Geodesic.hpp>
|
||||
using namespace GeographicLib;
|
||||
|
||||
extern Scheduler* scheduler;
|
||||
extern UnitsManager* unitsManager;
|
||||
json::value GroundUnit::database = json::value();
|
||||
extern string instancePath;
|
||||
|
||||
#define RANDOM_ZERO_TO_ONE (double)(rand()) / (double)(RAND_MAX)
|
||||
#define RANDOM_MINUS_ONE_TO_ONE (((double)(rand()) / (double)(RAND_MAX) - 0.5) * 2)
|
||||
|
||||
void GroundUnit::loadDatabase(string path) {
|
||||
std::ifstream ifstream(instancePath + path);
|
||||
std::stringstream ss;
|
||||
ss << ifstream.rdbuf();
|
||||
std::error_code errorCode;
|
||||
database = json::value::parse(ss.str(), errorCode);
|
||||
if (database.is_object())
|
||||
log("GroundUnits database loaded correctly from " + instancePath + path);
|
||||
else
|
||||
log("Error reading GroundUnits database file");
|
||||
}
|
||||
|
||||
/* Ground unit */
|
||||
GroundUnit::GroundUnit(json::value json, unsigned int ID) : Unit(json, ID)
|
||||
{
|
||||
log("New Ground Unit created with ID: " + to_string(ID));
|
||||
|
||||
setCategory("GroundUnit");
|
||||
setDesiredSpeed(10);
|
||||
};
|
||||
|
||||
void GroundUnit::setDefaults(bool force)
|
||||
{
|
||||
/* Load gun values from database */
|
||||
if (database.has_object_field(to_wstring(name))) {
|
||||
json::value databaseEntry = database[to_wstring(name)];
|
||||
if (databaseEntry.has_number_field(L"barrelHeight"))
|
||||
setBarrelHeight(databaseEntry[L"barrelHeight"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"muzzleVelocity"))
|
||||
setMuzzleVelocity(databaseEntry[L"muzzleVelocity"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"aimTime"))
|
||||
setAimTime(databaseEntry[L"aimTime"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"shotsToFire"))
|
||||
setShotsToFire(databaseEntry[L"shotsToFire"].as_number().to_uint32());
|
||||
if (databaseEntry.has_number_field(L"engagementRange"))
|
||||
setEngagementRange(databaseEntry[L"engagementRange"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"shotsBaseInterval"))
|
||||
setShotsBaseInterval(databaseEntry[L"shotsBaseInterval"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"shotsBaseScatter"))
|
||||
setShotsBaseScatter(databaseEntry[L"shotsBaseScatter"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"targetingRange"))
|
||||
setTargetingRange(databaseEntry[L"targetingRange"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"aimMethodRange"))
|
||||
setAimMethodRange(databaseEntry[L"aimMethodRange"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"acquisitionRange"))
|
||||
setAcquisitionRange(databaseEntry[L"acquisitionRange"].as_number().to_double());
|
||||
}
|
||||
|
||||
if (!getAlive() || !getControlled() || getHuman() || !getIsLeader()) return;
|
||||
|
||||
/* Set the default IDLE state */
|
||||
setState(State::IDLE);
|
||||
|
||||
/* Set the default options */
|
||||
setROE(ROE::OPEN_FIRE_WEAPON_FREE, force);
|
||||
setOnOff(onOff, force);
|
||||
setFollowRoads(followRoads, force);
|
||||
}
|
||||
|
||||
void GroundUnit::setState(unsigned char newState)
|
||||
{
|
||||
Coords currentTargetPosition = getTargetPosition();
|
||||
|
||||
/************ Perform any action required when LEAVING a state ************/
|
||||
if (newState != state) {
|
||||
switch (state) {
|
||||
case State::IDLE: {
|
||||
break;
|
||||
}
|
||||
case State::REACH_DESTINATION: {
|
||||
break;
|
||||
}
|
||||
case State::ATTACK: {
|
||||
setTargetID(NULL);
|
||||
break;
|
||||
}
|
||||
case State::FIRE_AT_AREA:
|
||||
case State::SIMULATE_FIRE_FIGHT:
|
||||
case State::SCENIC_AAA:
|
||||
case State::MISS_ON_PURPOSE: {
|
||||
setTargetPosition(Coords(NULL));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/************ Perform any action required when ENTERING a state ************/
|
||||
switch (newState) {
|
||||
case State::IDLE: {
|
||||
setTask("Idle");
|
||||
setEnableTaskCheckFailed(false);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::REACH_DESTINATION: {
|
||||
setTask("Reaching destination");
|
||||
setEnableTaskCheckFailed(true);
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::ATTACK: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::FIRE_AT_AREA: {
|
||||
setTask("Firing at area");
|
||||
setTargetPosition(currentTargetPosition);
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
setTask("Simulating fire fight");
|
||||
setTargetPosition(currentTargetPosition);
|
||||
setEnableTaskCheckFailed(false);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::SCENIC_AAA: {
|
||||
setTask("Scenic AAA");
|
||||
setEnableTaskCheckFailed(false);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::MISS_ON_PURPOSE: {
|
||||
setTask("Miss on purpose");
|
||||
setEnableTaskCheckFailed(false);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
nextTaskingMilliseconds = 0;
|
||||
|
||||
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
|
||||
state = newState;
|
||||
|
||||
triggerUpdate(DataIndex::state);
|
||||
|
||||
AIloop();
|
||||
}
|
||||
|
||||
void GroundUnit::AIloop()
|
||||
{
|
||||
srand(static_cast<unsigned int>(time(NULL)) + ID);
|
||||
unsigned long timeNow = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
|
||||
|
||||
double currentAmmo = computeTotalAmmo();
|
||||
/* Out of ammo */
|
||||
if (shotsToFire > 0 && currentAmmo < shotsToFire && state != State::IDLE && state != State::REACH_DESTINATION)
|
||||
setState(State::IDLE);
|
||||
|
||||
/* Account for unit reloading */
|
||||
if (currentAmmo < oldAmmo)
|
||||
totalShellsFired += oldAmmo - currentAmmo;
|
||||
oldAmmo = currentAmmo;
|
||||
|
||||
switch (state) {
|
||||
case State::IDLE: {
|
||||
if (getHasTask())
|
||||
resetTask();
|
||||
|
||||
break;
|
||||
}
|
||||
case State::REACH_DESTINATION: {
|
||||
string enrouteTask = "";
|
||||
bool looping = false;
|
||||
|
||||
std::ostringstream taskSS;
|
||||
taskSS << "{ id = 'FollowRoads', value = " << (getFollowRoads() ? "true" : "false") << " }";
|
||||
enrouteTask = taskSS.str();
|
||||
|
||||
if (activeDestination == NULL || !getHasTask())
|
||||
{
|
||||
if (!setActiveDestination())
|
||||
setState(State::IDLE);
|
||||
else
|
||||
goToDestination(enrouteTask);
|
||||
}
|
||||
else {
|
||||
if (isDestinationReached(GROUND_DEST_DIST_THR)) {
|
||||
if (updateActivePath(looping) && setActiveDestination())
|
||||
goToDestination(enrouteTask);
|
||||
else
|
||||
setState(State::IDLE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case State::ATTACK: {
|
||||
Unit* target = unitsManager->getUnit(getTargetID());
|
||||
if (target != nullptr) {
|
||||
setTask("Attacking " + target->getUnitName());
|
||||
|
||||
if (!getHasTask()) {
|
||||
/* Send the command */
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
taskSS << "{id = 'AttackUnit', unitID = " << target->getID() << " }";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setState(State::IDLE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case State::FIRE_AT_AREA: {
|
||||
if (!getHasTask()) {
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
if (targetPosition.alt == NULL) {
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 100}";
|
||||
}
|
||||
else {
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", alt = " << targetPosition.alt << ", radius = 100}";
|
||||
}
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
string taskString = "";
|
||||
|
||||
if ((totalShellsFired - shellsFiredAtTasking >= shotsToFire || timeNow >= nextTaskingMilliseconds) && targetPosition != Coords(NULL)) {
|
||||
if (scheduler->getLoad() > 100) {
|
||||
taskString = "Excessive load, skipping tasking of unit";
|
||||
setTargetPosition(Coords(NULL));
|
||||
if (getHasTask())
|
||||
resetTask();
|
||||
}
|
||||
else {
|
||||
/* Get the distance and bearing to the target */
|
||||
Coords scatteredTargetPosition = targetPosition;
|
||||
double distance;
|
||||
double bearing1;
|
||||
double bearing2;
|
||||
Geodesic::WGS84().Inverse(getPosition().lat, getPosition().lng, scatteredTargetPosition.lat, scatteredTargetPosition.lng, distance, bearing1, bearing2);
|
||||
|
||||
/* Apply a scatter to the aim */
|
||||
bearing1 += RANDOM_MINUS_ONE_TO_ONE * (ShotsScatter::LOW - shotsScatter + 1) * 10;
|
||||
|
||||
/* Compute the scattered position applying a random scatter to the shot */
|
||||
double scatterDistance = distance * tan(10 /* degs */ * (ShotsScatter::LOW - shotsScatter) / 57.29577 + 2 / 57.29577 /* degs */) * RANDOM_MINUS_ONE_TO_ONE;
|
||||
Geodesic::WGS84().Direct(scatteredTargetPosition.lat, scatteredTargetPosition.lng, bearing1, scatterDistance, scatteredTargetPosition.lat, scatteredTargetPosition.lng);
|
||||
|
||||
/* Recover the data from the database */
|
||||
bool indirectFire = false;
|
||||
if (database.has_object_field(to_wstring(name))) {
|
||||
json::value databaseEntry = database[to_wstring(name)];
|
||||
if (databaseEntry.has_boolean_field(L"indirectFire"))
|
||||
indirectFire = databaseEntry[L"indirectFire"].as_bool();
|
||||
}
|
||||
|
||||
/* If the unit is of the indirect fire type, like a mortar, simply shoot at the target */
|
||||
if (indirectFire) {
|
||||
taskString += "Simulating fire fight with indirect fire";
|
||||
log(unitName + "(" + name + ")" + " simulating fire fight with indirect fire");
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << scatteredTargetPosition.lat << ", lng = " << scatteredTargetPosition.lng << ", radius = 0.01}";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
shellsFiredAtTasking = totalShellsFired;
|
||||
setHasTask(true);
|
||||
}
|
||||
/* Otherwise use the aim method */
|
||||
else {
|
||||
taskString += "Simulating fire fight with aim point method. ";
|
||||
log(unitName + "(" + name + ")" + " simulating fire fight with aim at point method");
|
||||
string aimTaskString = aimAtPoint(scatteredTargetPosition);
|
||||
taskString += aimTaskString;
|
||||
}
|
||||
|
||||
/* Wait an amout of time depending on the shots intensity */
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(2 * aimTime * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (targetPosition == Coords(NULL))
|
||||
setState(State::IDLE);
|
||||
|
||||
/* Fallback if something went wrong */
|
||||
if (timeNow >= nextTaskingMilliseconds)
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(3 * 1000);
|
||||
|
||||
setTimeToNextTasking(((nextTaskingMilliseconds - timeNow) / 1000.0));
|
||||
|
||||
if (taskString.length() > 0)
|
||||
setTask(taskString);
|
||||
|
||||
break;
|
||||
}
|
||||
case State::SCENIC_AAA: {
|
||||
string taskString = "";
|
||||
|
||||
/* Only perform scenic functions when the scheduler is "free" */
|
||||
if (totalShellsFired - shellsFiredAtTasking >= shotsToFire || timeNow >= nextTaskingMilliseconds) {
|
||||
if (scheduler->getLoad() > 100) {
|
||||
taskString = "Excessive load, skipping tasking of unit";
|
||||
setTargetPosition(Coords(NULL));
|
||||
if (getHasTask())
|
||||
resetTask();
|
||||
}
|
||||
else {
|
||||
double distance = 0;
|
||||
unsigned char unitCoalition = coalition == 0 ? getOperateAs() : coalition;
|
||||
unsigned char targetCoalition = unitCoalition == 2 ? 1 : 2;
|
||||
Unit* target = unitsManager->getClosestUnit(this, targetCoalition, { "Aircraft", "Helicopter" }, distance);
|
||||
|
||||
/* Recover the data from the database */
|
||||
bool flak = false;
|
||||
if (database.has_object_field(to_wstring(name))) {
|
||||
json::value databaseEntry = database[to_wstring(name)];
|
||||
if (databaseEntry.has_boolean_field(L"flak"))
|
||||
flak = databaseEntry[L"flak"].as_bool();
|
||||
}
|
||||
|
||||
/* Only run if an enemy air unit is closer than 20km to avoid useless load */
|
||||
double activationDistance = 20000;
|
||||
if (2 * engagementRange > activationDistance)
|
||||
activationDistance = 2 * engagementRange;
|
||||
|
||||
if (target != nullptr && distance < activationDistance /* m */) {
|
||||
double r = 15; /* m */
|
||||
double barrelElevation = position.alt + barrelHeight + r * tan(acos(((double)(rand()) / (double)(RAND_MAX))));
|
||||
|
||||
double lat = 0;
|
||||
double lng = 0;
|
||||
double randomBearing = ((double)(rand()) / (double)(RAND_MAX)) * 360;
|
||||
Geodesic::WGS84().Direct(position.lat, position.lng, randomBearing, r, lat, lng);
|
||||
|
||||
if (flak) {
|
||||
lat = position.lat + RANDOM_MINUS_ONE_TO_ONE * (1 + (ShotsScatter::LOW - shotsScatter)) * 0.01;
|
||||
lng = position.lng + RANDOM_MINUS_ONE_TO_ONE * (1 + (ShotsScatter::LOW - shotsScatter)) * 0.01;
|
||||
barrelElevation = target->getPosition().alt + RANDOM_MINUS_ONE_TO_ONE * (ShotsScatter::LOW - shotsScatter) * 1000;
|
||||
taskString += "Flak box mode";
|
||||
}
|
||||
else {
|
||||
taskString += "Scenic AAA. Bearing: " + to_string((int)round(randomBearing)) + "deg";
|
||||
}
|
||||
|
||||
taskString += ". Aim point elevation " + to_string((int)round(barrelElevation - position.alt)) + "m AGL";
|
||||
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << lat << ", lng = " << lng << ", alt = " << barrelElevation << ", radius = 0.001 }";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
shellsFiredAtTasking = totalShellsFired;
|
||||
setHasTask(true);
|
||||
|
||||
/* Wait an amout of time depending on the shots intensity */
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(2 * aimTime * 1000);
|
||||
}
|
||||
else {
|
||||
setTargetPosition(Coords(NULL));
|
||||
if (target == nullptr)
|
||||
taskString += "Scenic AAA. No valid target.";
|
||||
else
|
||||
taskString += "Scenic AAA. Target outside max range: " + to_string((int)round(distance)) + "m.";
|
||||
|
||||
if (getHasTask())
|
||||
resetTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (timeNow >= nextTaskingMilliseconds)
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(3 * 1000);
|
||||
|
||||
setTimeToNextTasking((nextTaskingMilliseconds - timeNow) / 1000.0);
|
||||
if (taskString.length() > 0)
|
||||
setTask(taskString);
|
||||
|
||||
break;
|
||||
}
|
||||
case State::MISS_ON_PURPOSE: {
|
||||
string taskString = "";
|
||||
|
||||
/* Check that the unit can perform AAA duties */
|
||||
bool canAAA = false;
|
||||
if (database.has_object_field(to_wstring(name))) {
|
||||
json::value databaseEntry = database[to_wstring(name)];
|
||||
if (databaseEntry.has_boolean_field(L"canAAA"))
|
||||
canAAA = databaseEntry[L"canAAA"].as_bool();
|
||||
}
|
||||
|
||||
/* Recover the data from the database */
|
||||
bool flak = false;
|
||||
if (database.has_object_field(to_wstring(name))) {
|
||||
json::value databaseEntry = database[to_wstring(name)];
|
||||
if (databaseEntry.has_boolean_field(L"flak"))
|
||||
flak = databaseEntry[L"flak"].as_bool();
|
||||
}
|
||||
|
||||
if (canAAA) {
|
||||
/* Only perform scenic functions when the scheduler is "free" */
|
||||
/* Only run this when the internal counter reaches 0 to avoid excessive computations when no nearby target */
|
||||
if (totalShellsFired - shellsFiredAtTasking >= shotsToFire || timeNow >= nextTaskingMilliseconds) {
|
||||
if (scheduler->getLoad() > 100) {
|
||||
taskString = "Excessive load, skipping tasking of unit";
|
||||
setTargetPosition(Coords(NULL));
|
||||
if (getHasTask())
|
||||
resetTask();
|
||||
}
|
||||
else {
|
||||
double distance = 0;
|
||||
unsigned char unitCoalition = coalition == 0 ? getOperateAs() : coalition;
|
||||
unsigned char targetCoalition = unitCoalition == 2 ? 1 : 2;
|
||||
|
||||
/* Get all the units in range and select one at random */
|
||||
double range = max(max(engagementRange, aimMethodRange), acquisitionRange);
|
||||
map<Unit*, double> targets = unitsManager->getUnitsInRange(this, targetCoalition, { "Aircraft", "Helicopter" }, range);
|
||||
|
||||
Unit* target = nullptr;
|
||||
unsigned int index = static_cast<unsigned int>((RANDOM_ZERO_TO_ONE * (targets.size() - 1)));
|
||||
for (auto const& p : targets) {
|
||||
if (index-- == 0) {
|
||||
target = p.first;
|
||||
distance = p.second;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only do if we have a valid target close enough for AAA */
|
||||
if (target != nullptr) {
|
||||
taskString += "Missing on purpose. Valid target at range: " + to_string((int)round(distance)) + "m";
|
||||
|
||||
// Very simplified algorithm ignoring drag
|
||||
double correctedAimTime = aimTime + distance / muzzleVelocity;
|
||||
|
||||
/* If the target is in targeting range and we are in highest precision mode, target it */
|
||||
if (distance < targetingRange && shotsScatter == ShotsScatter::LOW) {
|
||||
taskString += ". Range is less than targeting range (" + to_string((int)round(targetingRange)) + "m) and scatter is LOW, aiming at target.";
|
||||
|
||||
/* Send the command */
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
taskSS << "{id = 'AttackUnit', unitID = " << target->getID() << " }";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
shellsFiredAtTasking = totalShellsFired;
|
||||
setHasTask(true);
|
||||
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(2 * aimTime * 1000);
|
||||
}
|
||||
/* Else, do miss on purpose */
|
||||
else {
|
||||
/* Compute where the target will be in aimTime seconds. */
|
||||
double aimDistance = target->getHorizontalVelocity() * correctedAimTime;
|
||||
double aimLat = 0;
|
||||
double aimLng = 0;
|
||||
Geodesic::WGS84().Direct(target->getPosition().lat, target->getPosition().lng, target->getTrack() * 57.29577, aimDistance, aimLat, aimLng); /* TODO make util to convert degrees and radians function */
|
||||
double aimAlt = target->getPosition().alt + target->getVerticalVelocity();
|
||||
|
||||
if (flak) {
|
||||
aimLat += RANDOM_MINUS_ONE_TO_ONE * (1 + (ShotsScatter::LOW - shotsScatter)) * 0.01;
|
||||
aimLng += RANDOM_MINUS_ONE_TO_ONE * (1 + (ShotsScatter::LOW - shotsScatter)) * 0.01;
|
||||
aimAlt += RANDOM_MINUS_ONE_TO_ONE * (1 + (ShotsScatter::LOW - shotsScatter)) * 1000;
|
||||
}
|
||||
|
||||
/* Send the command */
|
||||
if (distance < engagementRange) {
|
||||
taskString += ". Range is less than engagement range (" + to_string((int)round(engagementRange)) + "m), using FIRE AT POINT method";
|
||||
|
||||
/* If the unit is closer than the engagement range, use the fire at point method */
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << aimLat << ", lng = " << aimLng << ", alt = " << aimAlt << ", radius = 0.001 }";
|
||||
|
||||
taskString += ". Aiming altitude " + to_string((int)round((aimAlt - position.alt) / 0.3048)) + "ft AGL";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
shellsFiredAtTasking = totalShellsFired;
|
||||
setHasTask(true);
|
||||
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(2 * aimTime * 1000);
|
||||
}
|
||||
else if (distance < aimMethodRange) {
|
||||
taskString += ". Range is less than aim method range (" + to_string((int)round(aimMethodRange / 0.3048)) + "ft), using AIM method.";
|
||||
|
||||
/* If the unit is closer than the aim method range, use the aim method range */
|
||||
string aimMethodTask = aimAtPoint(Coords(aimLat, aimLng, aimAlt));
|
||||
taskString += aimMethodTask;
|
||||
|
||||
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(2 * aimTime * 1000);
|
||||
}
|
||||
else {
|
||||
taskString += ". Target is not in range of weapon, waking up unit to get ready for tasking.";
|
||||
|
||||
/* Else just wake the unit up with an impossible command */
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << 0 << ", lng = " << 0 << ", alt = " << 0 << ", radius = 0.001, expendQty = " << 0 << " }";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
shellsFiredAtTasking = totalShellsFired;
|
||||
setHasTask(true);
|
||||
setTargetPosition(Coords(NULL));
|
||||
|
||||
/* Don't wait too long before checking again */
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>(5 * 1000);
|
||||
}
|
||||
}
|
||||
missOnPurposeTarget = target;
|
||||
}
|
||||
else {
|
||||
taskString += "Missing on purpose. No target in range.";
|
||||
setTargetPosition(Coords(NULL));
|
||||
if (getHasTask())
|
||||
resetTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If no valid target was detected */
|
||||
if (timeNow >= nextTaskingMilliseconds) {
|
||||
double alertnessTimeConstant = 10; /* s */
|
||||
if (database.has_object_field(to_wstring(name))) {
|
||||
json::value databaseEntry = database[to_wstring(name)];
|
||||
if (databaseEntry.has_number_field(L"alertnessTimeConstant"))
|
||||
alertnessTimeConstant = databaseEntry[L"alertnessTimeConstant"].as_number().to_double();
|
||||
}
|
||||
nextTaskingMilliseconds = timeNow + static_cast<unsigned long>((5 + RANDOM_ZERO_TO_ONE * alertnessTimeConstant) * 1000L);
|
||||
missOnPurposeTarget = nullptr;
|
||||
setTargetPosition(Coords(NULL));
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
setState(State::IDLE);
|
||||
}
|
||||
|
||||
setTimeToNextTasking((nextTaskingMilliseconds - timeNow) / 1000.0);
|
||||
|
||||
if (taskString.length() > 0)
|
||||
setTask(taskString);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string GroundUnit::aimAtPoint(Coords aimTarget) {
|
||||
string taskString = "";
|
||||
double dist;
|
||||
double bearing1;
|
||||
double bearing2;
|
||||
Geodesic::WGS84().Inverse(position.lat, position.lng, aimTarget.lat, aimTarget.lng, dist, bearing1, bearing2);
|
||||
|
||||
/* Aim point distance */
|
||||
double r = 15; /* m */
|
||||
|
||||
/* Compute the elevation angle of the gun*/
|
||||
double deltaHeight = (aimTarget.alt - (position.alt + barrelHeight));
|
||||
double alpha = 9.81 / 2 * dist * dist / (muzzleVelocity * muzzleVelocity);
|
||||
double inner = dist * dist - 4 * alpha * (alpha + deltaHeight);
|
||||
|
||||
/* Check we can reach the target*/
|
||||
if (inner > 0) {
|
||||
/* Compute elevation and bearing */
|
||||
double barrelElevation = r * (dist - sqrt(inner)) / (2 * alpha);
|
||||
|
||||
double lat = 0;
|
||||
double lng = 0;
|
||||
Geodesic::WGS84().Direct(position.lat, position.lng, bearing1, r, lat, lng);
|
||||
|
||||
taskString = +"Barrel elevation: " + to_string((int) round(barrelElevation)) + "m, bearing: " + to_string((int) round(bearing1)) + "deg";
|
||||
log(unitName + "(" + name + ")" + " shooting with aim at point method. Barrel elevation: " + to_string(barrelElevation) + "m, bearing: " + to_string(bearing1) + "<EFBFBD>");
|
||||
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << lat << ", lng = " << lng << ", alt = " << position.alt + barrelElevation + barrelHeight << ", radius = 0.001}";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
shellsFiredAtTasking = totalShellsFired;
|
||||
setHasTask(true);
|
||||
}
|
||||
else {
|
||||
log("Target out of range for " + unitName + "(" + name + ")");
|
||||
taskString = +"Target out of range";
|
||||
}
|
||||
|
||||
return taskString;
|
||||
}
|
||||
|
||||
void GroundUnit::changeSpeed(string change)
|
||||
{
|
||||
if (change.compare("stop") == 0)
|
||||
setState(State::IDLE);
|
||||
else if (change.compare("slow") == 0)
|
||||
setDesiredSpeed(getDesiredSpeed() - knotsToMs(5));
|
||||
else if (change.compare("fast") == 0)
|
||||
setDesiredSpeed(getDesiredSpeed() + knotsToMs(5));
|
||||
|
||||
if (getDesiredSpeed() < 0)
|
||||
setDesiredSpeed(0);
|
||||
}
|
||||
|
||||
void GroundUnit::setOnOff(bool newOnOff, bool force)
|
||||
{
|
||||
if (newOnOff != onOff || force) {
|
||||
Unit::setOnOff(newOnOff, force);
|
||||
Command* command = dynamic_cast<Command*>(new SetOnOff(groupName, onOff));
|
||||
scheduler->appendCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
void GroundUnit::setFollowRoads(bool newFollowRoads, bool force)
|
||||
{
|
||||
if (newFollowRoads != followRoads || force) {
|
||||
Unit::setFollowRoads(newFollowRoads, force);
|
||||
resetActiveDestination(); /* Reset active destination to apply option*/
|
||||
}
|
||||
}
|
||||
71
backend/core/src/helicopter.cpp
Normal file
71
backend/core/src/helicopter.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "helicopter.h"
|
||||
#include "utils.h"
|
||||
#include "logger.h"
|
||||
#include "commands.h"
|
||||
#include "scheduler.h"
|
||||
#include "defines.h"
|
||||
#include "unitsManager.h"
|
||||
|
||||
#include <GeographicLib/Geodesic.hpp>
|
||||
using namespace GeographicLib;
|
||||
|
||||
extern Scheduler* scheduler;
|
||||
extern UnitsManager* unitsManager;
|
||||
json::value Helicopter::database = json::value();
|
||||
extern string instancePath;
|
||||
|
||||
void Helicopter::loadDatabase(string path) {
|
||||
std::ifstream ifstream(instancePath + path);
|
||||
std::stringstream ss;
|
||||
ss << ifstream.rdbuf();
|
||||
std::error_code errorCode;
|
||||
database = json::value::parse(ss.str(), errorCode);
|
||||
if (database.is_object())
|
||||
log("Helicopters database loaded correctly from " + instancePath + path);
|
||||
else
|
||||
log("Error reading Helicopters database file");
|
||||
}
|
||||
|
||||
/* Helicopter */
|
||||
Helicopter::Helicopter(json::value json, unsigned int ID) : AirUnit(json, ID)
|
||||
{
|
||||
log("New Helicopter created with ID: " + to_string(ID));
|
||||
|
||||
setCategory("Helicopter");
|
||||
setDesiredSpeed(knotsToMs(100));
|
||||
setDesiredAltitude(ftToM(5000));
|
||||
};
|
||||
|
||||
void Helicopter::changeSpeed(string change)
|
||||
{
|
||||
if (change.compare("stop") == 0)
|
||||
setState(State::IDLE);
|
||||
else if (change.compare("slow") == 0)
|
||||
setDesiredSpeed(getDesiredSpeed() - knotsToMs(10));
|
||||
else if (change.compare("fast") == 0)
|
||||
setDesiredSpeed(getDesiredSpeed() + knotsToMs(10));
|
||||
|
||||
if (getDesiredSpeed() < knotsToMs(0))
|
||||
setDesiredSpeed(knotsToMs(0));
|
||||
}
|
||||
|
||||
void Helicopter::changeAltitude(string change)
|
||||
{
|
||||
if (change.compare("descend") == 0)
|
||||
{
|
||||
if (getDesiredAltitude() > 100)
|
||||
setDesiredAltitude(getDesiredAltitude() - ftToM(100));
|
||||
else if (getDesiredAltitude() > 0)
|
||||
setDesiredAltitude(getDesiredAltitude() - ftToM(10));
|
||||
}
|
||||
else if (change.compare("climb") == 0)
|
||||
{
|
||||
if (getDesiredAltitude() > 100)
|
||||
setDesiredAltitude(getDesiredAltitude() + ftToM(100));
|
||||
else if (getDesiredAltitude() >= 0)
|
||||
setDesiredAltitude(getDesiredAltitude() + ftToM(10));
|
||||
}
|
||||
|
||||
if (getDesiredAltitude() < 0)
|
||||
setDesiredAltitude(0);
|
||||
}
|
||||
@@ -12,24 +12,18 @@ using namespace GeographicLib;
|
||||
extern Scheduler* scheduler;
|
||||
extern UnitsManager* unitsManager;
|
||||
json::value NavyUnit::database = json::value();
|
||||
extern string instancePath;
|
||||
|
||||
void NavyUnit::loadDatabase(string path) {
|
||||
char* buf = nullptr;
|
||||
size_t sz = 0;
|
||||
if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr)
|
||||
{
|
||||
std::ifstream ifstream(string(buf) + path);
|
||||
std::stringstream ss;
|
||||
ss << ifstream.rdbuf();
|
||||
std::error_code errorCode;
|
||||
database = json::value::parse(ss.str(), errorCode);
|
||||
if (database.is_object())
|
||||
log("Navy Units database loaded correctly");
|
||||
else
|
||||
log("Error reading Navy Units database file");
|
||||
|
||||
free(buf);
|
||||
}
|
||||
std::ifstream ifstream(instancePath + path);
|
||||
std::stringstream ss;
|
||||
ss << ifstream.rdbuf();
|
||||
std::error_code errorCode;
|
||||
database = json::value::parse(ss.str(), errorCode);
|
||||
if (database.is_object())
|
||||
log("NavyUnits database loaded correctly from " + instancePath + path);
|
||||
else
|
||||
log("Error reading NavyUnits database file");
|
||||
}
|
||||
|
||||
/* Navy Unit */
|
||||
@@ -43,6 +37,31 @@ NavyUnit::NavyUnit(json::value json, unsigned int ID) : Unit(json, ID)
|
||||
|
||||
void NavyUnit::setDefaults(bool force)
|
||||
{
|
||||
/* Load gun values from database */
|
||||
if (database.has_object_field(to_wstring(name))) {
|
||||
json::value databaseEntry = database[to_wstring(name)];
|
||||
if (databaseEntry.has_number_field(L"barrelHeight"))
|
||||
setBarrelHeight(databaseEntry[L"barrelHeight"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"muzzleVelocity"))
|
||||
setMuzzleVelocity(databaseEntry[L"muzzleVelocity"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"aimTime"))
|
||||
setAimTime(databaseEntry[L"aimTime"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"shotsToFire"))
|
||||
setShotsToFire(databaseEntry[L"shotsToFire"].as_number().to_uint32());
|
||||
if (databaseEntry.has_number_field(L"engagementRange"))
|
||||
setEngagementRange(databaseEntry[L"engagementRange"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"shotsBaseInterval"))
|
||||
setShotsBaseInterval(databaseEntry[L"shotsBaseInterval"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"shotsBaseScatter"))
|
||||
setShotsBaseScatter(databaseEntry[L"shotsBaseScatter"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"targetingRange"))
|
||||
setTargetingRange(databaseEntry[L"targetingRange"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"aimMethodRange"))
|
||||
setAimMethodRange(databaseEntry[L"aimMethodRange"].as_number().to_double());
|
||||
if (databaseEntry.has_number_field(L"acquisitionRange"))
|
||||
setAcquisitionRange(databaseEntry[L"acquisitionRange"].as_number().to_double());
|
||||
}
|
||||
|
||||
if (!getAlive() || !getControlled() || getHuman() || !getIsLeader()) return;
|
||||
|
||||
/* Set the default IDLE state */
|
||||
@@ -56,6 +75,8 @@ void NavyUnit::setDefaults(bool force)
|
||||
|
||||
void NavyUnit::setState(unsigned char newState)
|
||||
{
|
||||
Coords currentTargetPosition = getTargetPosition();
|
||||
|
||||
/************ Perform any action required when LEAVING a state ************/
|
||||
if (newState != state) {
|
||||
switch (state) {
|
||||
@@ -65,11 +86,14 @@ void NavyUnit::setState(unsigned char newState)
|
||||
case State::REACH_DESTINATION: {
|
||||
break;
|
||||
}
|
||||
case State::FIRE_AT_AREA: {
|
||||
setTargetPosition(Coords(NULL));
|
||||
case State::ATTACK: {
|
||||
setTargetID(NULL);
|
||||
break;
|
||||
}
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
case State::FIRE_AT_AREA:
|
||||
case State::SIMULATE_FIRE_FIGHT:
|
||||
case State::SCENIC_AAA:
|
||||
case State::MISS_ON_PURPOSE: {
|
||||
setTargetPosition(Coords(NULL));
|
||||
break;
|
||||
}
|
||||
@@ -91,35 +115,57 @@ void NavyUnit::setState(unsigned char newState)
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::FIRE_AT_AREA: {
|
||||
case State::ATTACK: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::FIRE_AT_AREA: {
|
||||
setTargetPosition(currentTargetPosition);
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
resetTask();
|
||||
break;
|
||||
}
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
setTargetPosition(currentTargetPosition);
|
||||
setEnableTaskCheckFailed(false);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::SCENIC_AAA: {
|
||||
setEnableTaskCheckFailed(false);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::MISS_ON_PURPOSE: {
|
||||
setEnableTaskCheckFailed(false);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
resetTask();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (newState != state)
|
||||
resetTask();
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
|
||||
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
|
||||
state = newState;
|
||||
|
||||
triggerUpdate(DataIndex::state);
|
||||
|
||||
AIloop();
|
||||
}
|
||||
|
||||
void NavyUnit::AIloop()
|
||||
{
|
||||
srand(static_cast<unsigned int>(time(NULL)) + ID);
|
||||
|
||||
switch (state) {
|
||||
case State::IDLE: {
|
||||
setTask("Idle");
|
||||
@@ -146,6 +192,28 @@ void NavyUnit::AIloop()
|
||||
setState(State::IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case State::ATTACK: {
|
||||
Unit* target = unitsManager->getUnit(getTargetID());
|
||||
if (target != nullptr) {
|
||||
setTask("Attacking " + target->getUnitName());
|
||||
|
||||
if (!getHasTask()) {
|
||||
/* Send the command */
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
taskSS << "{id = 'AttackUnit', unitID = " << target->getID() << " }";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setState(State::IDLE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case State::FIRE_AT_AREA: {
|
||||
@@ -160,19 +228,16 @@ void NavyUnit::AIloop()
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
setTask("Simulating fire fight");
|
||||
|
||||
if (!getHasTask()) {
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
// TODO
|
||||
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 1}";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
}
|
||||
setState(State::IDLE);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
@@ -52,13 +52,23 @@ void Scheduler::execute(lua_State* L)
|
||||
if (command->getPriority() == priority)
|
||||
{
|
||||
string commandString = "Olympus.protectedCall(" + command->getString() + ")";
|
||||
if (dostring_in(L, "server", (commandString)))
|
||||
string resultString = "";
|
||||
if (dostring_in(L, "server", (commandString), resultString))
|
||||
log("Error executing command " + commandString);
|
||||
else
|
||||
log("Command '" + commandString + "' executed correctly, current load " + to_string(getLoad()));
|
||||
load = command->getLoad();
|
||||
log("Command '" + commandString + "' executed correctly, current load " + to_string(getLoad()) + ", result string: " + resultString);
|
||||
|
||||
/* Adjust the load depending on the fps */
|
||||
double fpsMultiplier = 20;
|
||||
if (getFrameRate() + 3 > 0)
|
||||
fpsMultiplier = static_cast<unsigned int>(max(1, 60 / (getFrameRate() + 3))); /* Multiplier between 1 and 20 */
|
||||
|
||||
load = static_cast<unsigned int>(command->getLoad() * fpsMultiplier);
|
||||
commands.remove(command);
|
||||
executedCommandsHashes.push_back(command->getHash());
|
||||
CommandResult commandResult = {
|
||||
command->getHash(), resultString
|
||||
};
|
||||
executedCommandResults.push_back(commandResult);
|
||||
command->executeCallback(); /* Execute the command callback (this is a lambda function that can be used to execute a function when the command is run) */
|
||||
delete command;
|
||||
return;
|
||||
@@ -82,7 +92,7 @@ void Scheduler::setCommandModeOptions(json::value value) {
|
||||
setRedSpawnPoints(value[L"spawnPoints"][L"red"].as_number().to_int32());
|
||||
}
|
||||
if (value.has_array_field(L"eras")) {
|
||||
int length = value[L"eras"].as_array().size();
|
||||
int length = static_cast<int>(value[L"eras"].as_array().size());
|
||||
vector<string> newEras;
|
||||
for (int idx = 0; idx < length; idx++)
|
||||
newEras.push_back(to_string(value[L"eras"].as_array().at(idx)));
|
||||
@@ -132,6 +142,8 @@ bool Scheduler::checkSpawnPoints(int spawnPoints, string coalition)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Scheduler::handleRequest(string key, json::value value, string username, json::value& answer)
|
||||
@@ -156,6 +168,12 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
string WP = to_string(i);
|
||||
double lat = path[i][L"lat"].as_double();
|
||||
double lng = path[i][L"lng"].as_double();
|
||||
if (path[i].has_number_field(L"threshold")) {
|
||||
double threshold = path[i][L"threshold"].as_double();
|
||||
Coords dest; dest.lat = lat; dest.lng = lng; dest.threshold = threshold;
|
||||
newPath.push_back(dest);
|
||||
continue;
|
||||
}
|
||||
Coords dest; dest.lat = lat; dest.lng = lng;
|
||||
newPath.push_back(dest);
|
||||
}
|
||||
@@ -171,7 +189,7 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
string color = to_string(value[L"color"]);
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
|
||||
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
command = dynamic_cast<Command*>(new Smoke(color, loc));
|
||||
log(username + " added a " + color + " smoke at (" + to_string(lat) + ", " + to_string(lng) + ")", true);
|
||||
@@ -185,7 +203,10 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
string country = to_string(value[L"country"]);
|
||||
|
||||
int spawnPoints = value[L"spawnPoints"].as_number().to_int32();
|
||||
if (!checkSpawnPoints(spawnPoints, coalition)) return;
|
||||
if (!checkSpawnPoints(spawnPoints, coalition)) {
|
||||
log(username + " insufficient spawn points ", true);
|
||||
return;
|
||||
}
|
||||
|
||||
vector<SpawnOptions> spawnOptions;
|
||||
for (auto unit : value[L"units"].as_array()) {
|
||||
@@ -193,11 +214,20 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
double lat = unit[L"location"][L"lat"].as_double();
|
||||
double lng = unit[L"location"][L"lng"].as_double();
|
||||
double alt = unit[L"altitude"].as_double();
|
||||
double heading = 0;
|
||||
if (unit.has_number_field(L"heading"))
|
||||
heading = unit[L"heading"].as_double();
|
||||
|
||||
Coords location; location.lat = lat; location.lng = lng; location.alt = alt;
|
||||
string loadout = to_string(unit[L"loadout"]);
|
||||
string liveryID = to_string(unit[L"liveryID"]);
|
||||
string skill = to_string(unit[L"skill"]);
|
||||
|
||||
spawnOptions.push_back({unitType, location, loadout, liveryID});
|
||||
string payload = "nil";
|
||||
if (unit.has_string_field(L"payload"))
|
||||
payload = to_string(unit[L"payload"]);
|
||||
|
||||
spawnOptions.push_back({ unitType, location, loadout, skill, liveryID, heading, payload });
|
||||
log(username + " spawned a " + coalition + " " + unitType, true);
|
||||
}
|
||||
|
||||
@@ -214,17 +244,25 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
string country = to_string(value[L"country"]);
|
||||
|
||||
int spawnPoints = value[L"spawnPoints"].as_number().to_int32();
|
||||
if (!checkSpawnPoints(spawnPoints, coalition)) return;
|
||||
if (!checkSpawnPoints(spawnPoints, coalition)) {
|
||||
log(username + " insufficient spawn points ", true);
|
||||
return;
|
||||
}
|
||||
|
||||
vector<SpawnOptions> spawnOptions;
|
||||
for (auto unit : value[L"units"].as_array()) {
|
||||
string unitType = to_string(unit[L"unitType"]);
|
||||
double lat = unit[L"location"][L"lat"].as_double();
|
||||
double lng = unit[L"location"][L"lng"].as_double();
|
||||
double heading = 0;
|
||||
if (unit.has_number_field(L"heading"))
|
||||
heading = unit[L"heading"].as_double();
|
||||
|
||||
Coords location; location.lat = lat; location.lng = lng;
|
||||
string liveryID = to_string(unit[L"liveryID"]);
|
||||
|
||||
spawnOptions.push_back({ unitType, location, "", liveryID });
|
||||
string skill = to_string(unit[L"skill"]);
|
||||
|
||||
spawnOptions.push_back({ unitType, location, "", skill, liveryID, heading });
|
||||
log(username + " spawned a " + coalition + " " + unitType, true);
|
||||
}
|
||||
|
||||
@@ -254,7 +292,7 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
unsigned int leaderID = value[L"targetID"].as_double();
|
||||
unsigned int leaderID = value[L"targetID"].as_integer();
|
||||
double offsetX = value[L"offsetX"].as_double();
|
||||
double offsetY = value[L"offsetY"].as_double();
|
||||
double offsetZ = value[L"offsetZ"].as_double();
|
||||
@@ -334,18 +372,43 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
unit->setDesiredAltitudeType(to_string(value[L"altitudeType"]));
|
||||
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") altitude type: " + to_string(value[L"altitudeType"]), true);
|
||||
}
|
||||
}/************************/
|
||||
else if (key.compare("setRacetrack") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr) {
|
||||
unit->setRacetrackLength(value[L"length"].as_double());
|
||||
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords location; location.lat = lat; location.lng = lng;
|
||||
unit->setRacetrackAnchor(location);
|
||||
|
||||
unit->setRacetrackBearing(value[L"bearing"].as_double());
|
||||
|
||||
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") racetrack length: " + to_string(value[L"length"].as_double()) + " racetrack bearing: " + to_string(value[L"bearing"].as_double()), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("cloneUnits") == 0)
|
||||
{
|
||||
vector<CloneOptions> cloneOptions;
|
||||
bool deleteOriginal = value[L"deleteOriginal"].as_bool();
|
||||
string coalition = to_string(value[L"coalition"]);
|
||||
|
||||
int spawnPoints = value[L"spawnPoints"].as_number().to_int32();
|
||||
if (coalition.compare("all") != 0 && !checkSpawnPoints(spawnPoints, coalition)) {
|
||||
log(username + " insufficient spawn points ", true);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto unit : value[L"units"].as_array()) {
|
||||
unsigned int ID = unit[L"ID"].as_integer();
|
||||
double lat = unit[L"location"][L"lat"].as_double();
|
||||
double lng = unit[L"location"][L"lng"].as_double();
|
||||
|
||||
|
||||
Coords location; location.lat = lat; location.lng = lng;
|
||||
cloneOptions.push_back({ ID, location });
|
||||
log(username + " cloning unit with ID " + to_string(ID), true);
|
||||
@@ -365,6 +428,20 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") ROE to " + to_string(ROE), true);
|
||||
}
|
||||
}
|
||||
else if (key.compare("setAlarmState") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr) {
|
||||
unsigned char alarmState = value[L"alarmState"].as_number().to_uint32();
|
||||
unit->setAlarmState(alarmState);
|
||||
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") alarm state to " + to_string(alarmState), true);
|
||||
}
|
||||
else {
|
||||
log("Error while setting setAlarmState. Unit does not exist.");
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setReactionToThreat") == 0)
|
||||
{
|
||||
@@ -472,6 +549,29 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setEngagementProperties") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr)
|
||||
{
|
||||
/* Engagement properties tasking */
|
||||
unit->setBarrelHeight(value[L"barrelHeight"].as_number().to_double());
|
||||
unit->setMuzzleVelocity(value[L"muzzleVelocity"].as_number().to_double());
|
||||
unit->setAimTime(value[L"aimTime"].as_number().to_double());
|
||||
unit->setShotsToFire(value[L"shotsToFire"].as_number().to_uint32());
|
||||
unit->setShotsBaseInterval(value[L"shotsBaseInterval"].as_number().to_double());
|
||||
unit->setShotsBaseScatter(value[L"shotsBaseScatter"].as_number().to_double());
|
||||
unit->setEngagementRange(value[L"engagementRange"].as_number().to_double());
|
||||
unit->setTargetingRange(value[L"targetingRange"].as_number().to_double());
|
||||
unit->setAimMethodRange(value[L"aimMethodRange"].as_number().to_double());
|
||||
unit->setAcquisitionRange(value[L"acquisitionRange"].as_number().to_double());
|
||||
|
||||
log(username + " updated unit " + unit->getUnitName() + "(" + unit->getName() + ") engagementProperties", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setFollowRoads") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
@@ -492,7 +592,7 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr) {
|
||||
unit->setOnOff(onOff);
|
||||
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") onOff to: " + (onOff? "true": "false"), true);
|
||||
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") onOff to: " + (onOff ? "true" : "false"), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
@@ -516,8 +616,8 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::BOMB_POINT);
|
||||
unit->setTargetPosition(loc);
|
||||
unit->setState(State::BOMB_POINT);
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to bomb a point", true);
|
||||
}
|
||||
}
|
||||
@@ -531,8 +631,8 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::CARPET_BOMB);
|
||||
unit->setTargetPosition(loc);
|
||||
unit->setState(State::CARPET_BOMB);
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to perform carpet bombing", true);
|
||||
}
|
||||
}
|
||||
@@ -547,8 +647,8 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::BOMB_BUILDING);
|
||||
unit->setTargetPosition(loc);
|
||||
unit->setState(State::BOMB_BUILDING);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
@@ -559,10 +659,15 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
|
||||
if (value[L"location"].has_number_field(L"alt")) {
|
||||
loc.alt = value[L"location"][L"alt"].as_double();
|
||||
}
|
||||
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::FIRE_AT_AREA);
|
||||
unit->setTargetPosition(loc);
|
||||
unit->setState(State::FIRE_AT_AREA);
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to fire at area", true);
|
||||
}
|
||||
}
|
||||
@@ -577,8 +682,8 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
Coords loc; loc.lat = lat; loc.lng = lng; loc.alt = alt;
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::SIMULATE_FIRE_FIGHT);
|
||||
unit->setTargetPosition(loc);
|
||||
unit->setState(State::SIMULATE_FIRE_FIGHT);
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to simulate a fire fight", true);
|
||||
}
|
||||
}
|
||||
@@ -611,7 +716,7 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
unitsManager->acquireControl(ID);
|
||||
unsigned char operateAs = value[L"operateAs"].as_number().to_uint32();
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr)
|
||||
if (unit != nullptr)
|
||||
unit->setOperateAs(operateAs);
|
||||
}
|
||||
/************************/
|
||||
@@ -658,7 +763,66 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setCommandModeOptions") == 0)
|
||||
else if (key.compare("fireLaser") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr) {
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
unsigned int code = value[L"code"].as_integer();
|
||||
|
||||
log("Firing laser with code " + to_string(code) + " from unit " + unit->getUnitName() + " to (" + to_string(lat) + ", " + to_string(lng) + ")");
|
||||
|
||||
command = dynamic_cast<Command*>(new FireLaser(ID, code, loc));
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("fireInfrared") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr) {
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
|
||||
log("Firing infrared from unit " + unit->getUnitName() + " to (" + to_string(lat) + ", " + to_string(lng) + ")");
|
||||
|
||||
command = dynamic_cast<Command*>(new FireInfrared(ID, loc));
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setLaserCode") == 0)
|
||||
{
|
||||
unsigned int spotID = value[L"spotID"].as_integer();
|
||||
unsigned int code = value[L"code"].as_integer();
|
||||
|
||||
log("Setting laser code " + to_string(code) + " to spot with ID " + to_string(spotID));
|
||||
command = dynamic_cast<Command*>(new SetLaserCode(spotID, code));
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("moveSpot") == 0)
|
||||
{
|
||||
unsigned int spotID = value[L"spotID"].as_integer();
|
||||
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
|
||||
log("Moving spot with ID " + to_string(spotID) + " to (" + to_string(lat) + ", " + to_string(lng) + ")");
|
||||
command = dynamic_cast<Command*>(new MoveSpot(spotID, loc));
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("deleteSpot") == 0)
|
||||
{
|
||||
unsigned int spotID = value[L"spotID"].as_integer();
|
||||
log("Deleting spot with ID " + to_string(spotID));
|
||||
command = dynamic_cast<Command*>(new DeleteSpot(spotID));
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setCommandModeOptions") == 0)
|
||||
{
|
||||
setCommandModeOptions(value);
|
||||
log(username + " updated the Command Mode Options", true);
|
||||
@@ -668,6 +832,53 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
unitsManager->loadDatabases();
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setCargoWeight") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr) {
|
||||
double weight = value[L"weight"].as_double();
|
||||
unit->setCargoWeight(weight);
|
||||
log(username + " set weight to unit " + unit->getUnitName() + "(" + unit->getName() + "), " + to_string(weight), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("registerDrawArgument") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr) {
|
||||
int argument = value[L"argument"].as_integer();
|
||||
bool active = value[L"active"].as_bool();
|
||||
|
||||
command = dynamic_cast<Command*>(new RegisterDrawArgument(ID, argument, active));
|
||||
|
||||
log(username + " registered draw argument " + to_string(argument) + " for unit " + unit->getUnitName() + "(" + unit->getName() + "), value:" + to_string(active), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setCustomString") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr) {
|
||||
string customString = to_string(value[L"customString"]);
|
||||
unit->setCustomString(customString);
|
||||
log(username + " set custom string to unit " + unit->getUnitName() + "(" + unit->getName() + "), " + customString, true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setCustomInteger") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr) {
|
||||
double customNumber = value[L"customInteger"].as_double();
|
||||
unit->setCustomInteger(customNumber);
|
||||
log(username + " set custom number to unit " + unit->getUnitName() + "(" + unit->getName() + "), " + to_string(customNumber), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else
|
||||
{
|
||||
log("Unknown command: " + key);
|
||||
@@ -2,9 +2,12 @@
|
||||
#include "logger.h"
|
||||
#include "luatools.h"
|
||||
#include "dcstools.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
extern string instancePath;
|
||||
|
||||
bool executeLuaScript(lua_State* L, string path)
|
||||
{
|
||||
replace(path.begin(), path.end(), '\\', '/');
|
||||
@@ -36,21 +39,9 @@ void registerLuaFunctions(lua_State* L)
|
||||
log("protectedCall registered successfully");
|
||||
}
|
||||
|
||||
char* buf = nullptr;
|
||||
size_t sz = 0;
|
||||
if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr)
|
||||
{
|
||||
modLocation = buf;
|
||||
free(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
log("DCSOLYMPUS_PATH environment variable is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
executeLuaScript(L, modLocation + "\\Scripts\\mist.lua");
|
||||
executeLuaScript(L, modLocation + "\\Scripts\\OlympusCommand.lua");
|
||||
executeLuaScript(L, modLocation + "\\Scripts\\unitPayloads.lua");
|
||||
executeLuaScript(L, modLocation + "\\Scripts\\templates.lua");
|
||||
executeLuaScript(L, instancePath + MIST_SCRIPT);
|
||||
executeLuaScript(L, instancePath + OLYMPUS_COMMAND_SCRIPT);
|
||||
executeLuaScript(L, instancePath + UNIT_PAYLOADS_SCRIPT);
|
||||
executeLuaScript(L, instancePath + TEMPLATES_SCRIPT);
|
||||
executeLuaScript(L, instancePath + MODS_SCRIPT);
|
||||
}
|
||||
@@ -17,8 +17,11 @@ extern UnitsManager* unitsManager;
|
||||
extern WeaponsManager* weaponsManager;
|
||||
extern Scheduler* scheduler;
|
||||
extern json::value missionData;
|
||||
extern json::value drawingsByLayer;
|
||||
extern json::value executionResults;
|
||||
extern mutex mutexLock;
|
||||
extern string sessionHash;
|
||||
extern string instancePath;
|
||||
|
||||
void handle_eptr(std::exception_ptr eptr)
|
||||
{
|
||||
@@ -88,7 +91,7 @@ void Server::handle_get(http_request request)
|
||||
try {
|
||||
time = stoull((*(query.find(L"time"))).second);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
catch (...) {
|
||||
time = 0;
|
||||
}
|
||||
}
|
||||
@@ -127,6 +130,9 @@ void Server::handle_get(http_request request)
|
||||
/* Bullseyes data */
|
||||
else if (URI.compare(BULLSEYE_URI) == 0 && missionData.has_object_field(L"bullseyes"))
|
||||
answer[L"bullseyes"] = missionData[L"bullseyes"];
|
||||
/* Spots (laser/IR) data */
|
||||
else if (URI.compare(SPOTS_URI) == 0 && missionData.has_object_field(L"spots"))
|
||||
answer[L"spots"] = missionData[L"spots"];
|
||||
/* Mission data */
|
||||
else if (URI.compare(MISSION_URI) == 0 && missionData.has_object_field(L"mission")) {
|
||||
answer[L"mission"] = missionData[L"mission"];
|
||||
@@ -144,6 +150,14 @@ void Server::handle_get(http_request request)
|
||||
}
|
||||
else if (URI.compare(COMMANDS_URI) == 0 && query.find(L"commandHash") != query.end()) {
|
||||
answer[L"commandExecuted"] = json::value(scheduler->isCommandExecuted(to_string(query[L"commandHash"])));
|
||||
if (executionResults.has_field(query[L"commandHash"]))
|
||||
answer[L"commandResult"] = executionResults[query[L"commandHash"]];
|
||||
else
|
||||
answer[L"commandResult"] = json::value::null();
|
||||
}
|
||||
/* Drawings data*/
|
||||
else if (URI.compare(DRAWINGS_URI) == 0 && drawingsByLayer.has_object_field(L"drawings")) {
|
||||
answer[L"drawings"] = drawingsByLayer[L"drawings"];
|
||||
}
|
||||
|
||||
/* Common data */
|
||||
@@ -286,39 +300,32 @@ string Server::extractPassword(http_request& request) {
|
||||
void Server::task()
|
||||
{
|
||||
string address = REST_ADDRESS;
|
||||
string modLocation;
|
||||
char* buf = nullptr;
|
||||
size_t sz = 0;
|
||||
if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr)
|
||||
{
|
||||
std::ifstream ifstream(string(buf) + OLYMPUS_JSON_PATH);
|
||||
std::stringstream ss;
|
||||
ss << ifstream.rdbuf();
|
||||
std::error_code errorCode;
|
||||
json::value config = json::value::parse(ss.str(), errorCode);
|
||||
if (config.is_object() && config.has_object_field(L"server") &&
|
||||
config[L"server"].has_string_field(L"address") && config[L"server"].has_number_field(L"port"))
|
||||
{
|
||||
address = "http://" + to_string(config[L"server"][L"address"]) + ":" + to_string(config[L"server"][L"port"].as_number().to_int32());
|
||||
log("Starting server on " + address);
|
||||
}
|
||||
else
|
||||
log("Error reading configuration file. Starting server on " + address);
|
||||
string jsonLocation = instancePath + OLYMPUS_JSON_PATH;
|
||||
|
||||
if (config.is_object() && config.has_object_field(L"authentication"))
|
||||
{
|
||||
if (config[L"authentication"].has_string_field(L"gameMasterPassword")) gameMasterPassword = to_string(config[L"authentication"][L"gameMasterPassword"]);
|
||||
if (config[L"authentication"].has_string_field(L"blueCommanderPassword")) blueCommanderPassword = to_string(config[L"authentication"][L"blueCommanderPassword"]);
|
||||
if (config[L"authentication"].has_string_field(L"redCommanderPassword")) redCommanderPassword = to_string(config[L"authentication"][L"redCommanderPassword"]);
|
||||
}
|
||||
else
|
||||
log("Error reading configuration file. No password set.");
|
||||
free(buf);
|
||||
log("Reading configuration from " + jsonLocation);
|
||||
|
||||
std::ifstream ifstream(jsonLocation);
|
||||
std::stringstream ss;
|
||||
ss << ifstream.rdbuf();
|
||||
std::error_code errorCode;
|
||||
json::value config = json::value::parse(ss.str(), errorCode);
|
||||
if (config.is_object() && config.has_object_field(L"backend") &&
|
||||
config[L"backend"].has_string_field(L"address") && config[L"backend"].has_number_field(L"port"))
|
||||
{
|
||||
address = "http://" + to_string(config[L"backend"][L"address"]) + ":" + to_string(config[L"backend"][L"port"].as_number().to_int32());
|
||||
log("Starting backend on " + address);
|
||||
}
|
||||
else
|
||||
log("Error reading configuration file. Starting backend on " + address);
|
||||
|
||||
if (config.is_object() && config.has_object_field(L"authentication"))
|
||||
{
|
||||
log("DCSOLYMPUS_PATH environment variable is missing, starting server on " + address);
|
||||
if (config[L"authentication"].has_string_field(L"gameMasterPassword")) gameMasterPassword = to_string(config[L"authentication"][L"gameMasterPassword"]);
|
||||
if (config[L"authentication"].has_string_field(L"blueCommanderPassword")) blueCommanderPassword = to_string(config[L"authentication"][L"blueCommanderPassword"]);
|
||||
if (config[L"authentication"].has_string_field(L"redCommanderPassword")) redCommanderPassword = to_string(config[L"authentication"][L"redCommanderPassword"]);
|
||||
}
|
||||
else
|
||||
log("Error reading configuration file. No password set.");
|
||||
|
||||
http_listener listener(to_wstring(address + "/" + REST_URI));
|
||||
|
||||
@@ -336,7 +343,7 @@ void Server::task()
|
||||
.then([&listener]() {log("RESTServer starting to listen"); })
|
||||
.wait();
|
||||
|
||||
while (runListener);
|
||||
while (runListener) { Sleep(1000); };
|
||||
|
||||
listener.close()
|
||||
.then([&listener]() {log("RESTServer stopping connections"); })
|
||||
@@ -28,25 +28,6 @@ Unit::~Unit()
|
||||
|
||||
void Unit::initialize(json::value json)
|
||||
{
|
||||
if (json.has_string_field(L"name"))
|
||||
setName(to_string(json[L"name"]));
|
||||
|
||||
if (json.has_string_field(L"unitName"))
|
||||
setUnitName(to_string(json[L"unitName"]));
|
||||
|
||||
if (json.has_string_field(L"groupName"))
|
||||
setGroupName(to_string(json[L"groupName"]));
|
||||
|
||||
if (json.has_number_field(L"coalitionID"))
|
||||
setCoalition(json[L"coalitionID"].as_number().to_int32());
|
||||
|
||||
//if (json.has_number_field(L"Country"))
|
||||
// setCountry(json[L"Country"].as_number().to_int32());
|
||||
|
||||
/* All units which contain the name "Olympus" are automatically under AI control */
|
||||
if (getUnitName().find("Olympus") != string::npos)
|
||||
setControlled(true);
|
||||
|
||||
update(json, 0);
|
||||
setDefaults();
|
||||
}
|
||||
@@ -54,6 +35,32 @@ void Unit::initialize(json::value json)
|
||||
|
||||
void Unit::update(json::value json, double dt)
|
||||
{
|
||||
if (json.has_string_field(L"name"))
|
||||
setName(to_string(json[L"name"]));
|
||||
|
||||
if (json.has_string_field(L"unitName"))
|
||||
setUnitName(to_string(json[L"unitName"]));
|
||||
|
||||
if (json.has_number_field(L"groupID"))
|
||||
setGroupID(json[L"groupID"].as_number().to_uint32());
|
||||
if (json.has_number_field(L"unitID"))
|
||||
setUnitID(json[L"unitID"].as_number().to_uint32());
|
||||
|
||||
if (json.has_string_field(L"groupName"))
|
||||
setGroupName(to_string(json[L"groupName"]));
|
||||
|
||||
if (json.has_string_field(L"callsign"))
|
||||
setCallsign(to_string(json[L"callsign"]));
|
||||
|
||||
if (json.has_number_field(L"coalitionID"))
|
||||
setCoalition(json[L"coalitionID"].as_number().to_int32());
|
||||
if (json.has_number_field(L"country"))
|
||||
setCountry(json[L"country"].as_number().to_int32());
|
||||
|
||||
/* All units which contain the name "Olympus" are automatically under AI control */
|
||||
if (getUnitName().find("Olympus") != string::npos)
|
||||
setControlled(true);
|
||||
|
||||
if (json.has_object_field(L"position"))
|
||||
{
|
||||
setPosition({
|
||||
@@ -66,6 +73,9 @@ void Unit::update(json::value json, double dt)
|
||||
if (json.has_number_field(L"heading"))
|
||||
setHeading(json[L"heading"].as_number().to_double());
|
||||
|
||||
if (json.has_number_field(L"track"))
|
||||
setTrack(json[L"track"].as_number().to_double());
|
||||
|
||||
if (json.has_number_field(L"speed"))
|
||||
setSpeed(json[L"speed"].as_number().to_double());
|
||||
|
||||
@@ -78,6 +88,9 @@ void Unit::update(json::value json, double dt)
|
||||
if (json.has_boolean_field(L"isAlive"))
|
||||
setAlive(json[L"isAlive"].as_bool());
|
||||
|
||||
if (json.has_boolean_field(L"radarState"))
|
||||
setRadarState(json[L"radarState"].as_bool());
|
||||
|
||||
if (json.has_boolean_field(L"isHuman"))
|
||||
setHuman(json[L"isHuman"].as_bool());
|
||||
|
||||
@@ -115,6 +128,20 @@ void Unit::update(json::value json, double dt)
|
||||
setAmmo(ammo);
|
||||
}
|
||||
|
||||
if (json.has_object_field(L"drawArguments")) {
|
||||
vector<DataTypes::DrawArgument> drawArguments;
|
||||
for (auto const& el : json[L"drawArguments"].as_object()) {
|
||||
DataTypes::DrawArgument drawArgumentItem;
|
||||
auto drawArgumentJson = el.second;
|
||||
if (drawArgumentJson.has_number_field(L"argument"))
|
||||
drawArgumentItem.argument = drawArgumentJson[L"argument"].as_number().to_uint32();
|
||||
if (drawArgumentJson.has_number_field(L"value"))
|
||||
drawArgumentItem.value = drawArgumentJson[L"value"].as_number().to_double();
|
||||
drawArguments.push_back(drawArgumentItem);
|
||||
}
|
||||
setDrawArguments(drawArguments);
|
||||
}
|
||||
|
||||
if (json.has_object_field(L"contacts")) {
|
||||
vector<DataTypes::Contact> contacts;
|
||||
for (auto const& el : json[L"contacts"].as_object()) {
|
||||
@@ -140,12 +167,15 @@ void Unit::update(json::value json, double dt)
|
||||
if (json.has_number_field(L"health"))
|
||||
setHealth(static_cast<unsigned char>(json[L"health"].as_number().to_uint32()));
|
||||
|
||||
if (json.has_boolean_field(L"airborne"))
|
||||
setAirborne(json[L"airborne"].as_bool());
|
||||
|
||||
runAILoop();
|
||||
}
|
||||
|
||||
void Unit::setDefaults(bool force)
|
||||
{
|
||||
|
||||
setAlarmState(AlarmState::AUTO, force);
|
||||
}
|
||||
|
||||
void Unit::runAILoop() {
|
||||
@@ -203,6 +233,7 @@ void Unit::refreshLeaderData(unsigned long long time) {
|
||||
case DataIndex::operateAs: updateValue(operateAs, leader->operateAs, datumIndex); break;
|
||||
case DataIndex::shotsScatter: updateValue(shotsScatter, leader->shotsScatter, datumIndex); break;
|
||||
case DataIndex::shotsIntensity: updateValue(shotsIntensity, leader->shotsIntensity, datumIndex); break;
|
||||
case DataIndex::alarmState: updateValue(alarmState, leader->alarmState, datumIndex); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,6 +269,10 @@ void Unit::getData(stringstream& ss, unsigned long long time)
|
||||
appendString(ss, datumIndex, category);
|
||||
datumIndex = DataIndex::alive;
|
||||
appendNumeric(ss, datumIndex, alive);
|
||||
datumIndex = DataIndex::unitID;
|
||||
appendNumeric(ss, datumIndex, unitID);
|
||||
datumIndex = DataIndex::groupID;
|
||||
appendNumeric(ss, datumIndex, groupID);
|
||||
}
|
||||
else {
|
||||
for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++)
|
||||
@@ -246,12 +281,17 @@ void Unit::getData(stringstream& ss, unsigned long long time)
|
||||
switch (datumIndex) {
|
||||
case DataIndex::category: appendString(ss, datumIndex, category); break;
|
||||
case DataIndex::alive: appendNumeric(ss, datumIndex, alive); break;
|
||||
case DataIndex::alarmState: appendNumeric(ss, datumIndex, alarmState); break;
|
||||
case DataIndex::radarState: appendNumeric(ss, datumIndex, radarState); break;
|
||||
case DataIndex::human: appendNumeric(ss, datumIndex, human); break;
|
||||
case DataIndex::controlled: appendNumeric(ss, datumIndex, controlled); break;
|
||||
case DataIndex::coalition: appendNumeric(ss, datumIndex, coalition); break;
|
||||
case DataIndex::country: appendNumeric(ss, datumIndex, country); break;
|
||||
case DataIndex::name: appendString(ss, datumIndex, name); break;
|
||||
case DataIndex::unitName: appendString(ss, datumIndex, unitName); break;
|
||||
case DataIndex::callsign: appendString(ss, datumIndex, callsign); break;
|
||||
case DataIndex::unitID: appendNumeric(ss, datumIndex, unitID); break;
|
||||
case DataIndex::groupID: appendNumeric(ss, datumIndex, groupID); break;
|
||||
case DataIndex::groupName: appendString(ss, datumIndex, groupName); break;
|
||||
case DataIndex::state: appendNumeric(ss, datumIndex, state); break;
|
||||
case DataIndex::task: appendString(ss, datumIndex, task); break;
|
||||
@@ -261,6 +301,7 @@ void Unit::getData(stringstream& ss, unsigned long long time)
|
||||
case DataIndex::horizontalVelocity: appendNumeric(ss, datumIndex, horizontalVelocity); break;
|
||||
case DataIndex::verticalVelocity: appendNumeric(ss, datumIndex, verticalVelocity); break;
|
||||
case DataIndex::heading: appendNumeric(ss, datumIndex, heading); break;
|
||||
case DataIndex::track: appendNumeric(ss, datumIndex, track); break;
|
||||
case DataIndex::isActiveTanker: appendNumeric(ss, datumIndex, isActiveTanker); break;
|
||||
case DataIndex::isActiveAWACS: appendNumeric(ss, datumIndex, isActiveAWACS); break;
|
||||
case DataIndex::onOff: appendNumeric(ss, datumIndex, onOff); break;
|
||||
@@ -288,6 +329,25 @@ void Unit::getData(stringstream& ss, unsigned long long time)
|
||||
case DataIndex::shotsScatter: appendNumeric(ss, datumIndex, shotsScatter); break;
|
||||
case DataIndex::shotsIntensity: appendNumeric(ss, datumIndex, shotsIntensity); break;
|
||||
case DataIndex::health: appendNumeric(ss, datumIndex, health); break;
|
||||
case DataIndex::racetrackLength: appendNumeric(ss, datumIndex, racetrackLength); break;
|
||||
case DataIndex::racetrackAnchor: appendNumeric(ss, datumIndex, racetrackAnchor); break;
|
||||
case DataIndex::racetrackBearing: appendNumeric(ss, datumIndex, racetrackBearing); break;
|
||||
//case DataIndex::timeToNextTasking: appendNumeric(ss, datumIndex, timeToNextTasking); break; Useful for debugging, but useless in production and very data hungry
|
||||
case DataIndex::barrelHeight: appendNumeric(ss, datumIndex, barrelHeight); break;
|
||||
case DataIndex::muzzleVelocity: appendNumeric(ss, datumIndex, muzzleVelocity); break;
|
||||
case DataIndex::aimTime: appendNumeric(ss, datumIndex, aimTime); break;
|
||||
case DataIndex::shotsToFire: appendNumeric(ss, datumIndex, shotsToFire); break;
|
||||
case DataIndex::shotsBaseInterval: appendNumeric(ss, datumIndex, shotsBaseInterval); break;
|
||||
case DataIndex::shotsBaseScatter: appendNumeric(ss, datumIndex, shotsBaseScatter); break;
|
||||
case DataIndex::engagementRange: appendNumeric(ss, datumIndex, engagementRange); break;
|
||||
case DataIndex::targetingRange: appendNumeric(ss, datumIndex, targetingRange); break;
|
||||
case DataIndex::aimMethodRange: appendNumeric(ss, datumIndex, aimMethodRange); break;
|
||||
case DataIndex::acquisitionRange: appendNumeric(ss, datumIndex, acquisitionRange); break;
|
||||
case DataIndex::airborne: appendNumeric(ss, datumIndex, airborne); break;
|
||||
case DataIndex::cargoWeight: appendNumeric(ss, datumIndex, cargoWeight); break;
|
||||
case DataIndex::drawArguments: appendVector(ss, datumIndex, drawArguments); break;
|
||||
case DataIndex::customString: appendString(ss, datumIndex, customString); break;
|
||||
case DataIndex::customInteger: appendNumeric(ss, datumIndex, customInteger); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -426,7 +486,11 @@ void Unit::resetTask()
|
||||
void Unit::setFormationOffset(Offset newFormationOffset)
|
||||
{
|
||||
formationOffset = newFormationOffset;
|
||||
resetTask();
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::formationOffset);
|
||||
}
|
||||
@@ -442,6 +506,17 @@ void Unit::setROE(unsigned char newROE, bool force)
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::setAlarmState(unsigned char newAlarmState, bool force)
|
||||
{
|
||||
if (alarmState != newAlarmState || force) {
|
||||
alarmState = newAlarmState;
|
||||
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ALARM_STATE, static_cast<unsigned int>(newAlarmState)));
|
||||
scheduler->appendCommand(command);
|
||||
|
||||
triggerUpdate(DataIndex::alarmState);
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::setReactionToThreat(unsigned char newReactionToThreat, bool force)
|
||||
{
|
||||
if (reactionToThreat != newReactionToThreat || force) {
|
||||
@@ -515,7 +590,11 @@ void Unit::setIsActiveTanker(bool newIsActiveTanker)
|
||||
{
|
||||
if (isActiveTanker != newIsActiveTanker) {
|
||||
isActiveTanker = newIsActiveTanker;
|
||||
resetTask();
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::isActiveTanker);
|
||||
}
|
||||
@@ -525,7 +604,11 @@ void Unit::setIsActiveAWACS(bool newIsActiveAWACS)
|
||||
{
|
||||
if (isActiveAWACS != newIsActiveAWACS) {
|
||||
isActiveAWACS = newIsActiveAWACS;
|
||||
resetTask();
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::isActiveAWACS);
|
||||
}
|
||||
@@ -636,14 +719,33 @@ void Unit::setGeneralSettings(DataTypes::GeneralSettings newGeneralSettings, boo
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::setDrawArguments(vector<DataTypes::DrawArgument> newDrawArguments)
|
||||
{
|
||||
if (drawArguments.size() == newDrawArguments.size()) {
|
||||
bool equal = true;
|
||||
for (int i = 0; i < drawArguments.size(); i++) {
|
||||
if (drawArguments.at(i) != newDrawArguments.at(i))
|
||||
{
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (equal)
|
||||
return;
|
||||
}
|
||||
drawArguments = newDrawArguments;
|
||||
triggerUpdate(DataIndex::drawArguments);
|
||||
}
|
||||
|
||||
void Unit::setDesiredSpeed(double newDesiredSpeed)
|
||||
{
|
||||
if (desiredSpeed != newDesiredSpeed) {
|
||||
desiredSpeed = newDesiredSpeed;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::desiredSpeed);
|
||||
}
|
||||
@@ -653,10 +755,11 @@ void Unit::setDesiredAltitude(double newDesiredAltitude)
|
||||
{
|
||||
if (desiredAltitude != newDesiredAltitude) {
|
||||
desiredAltitude = newDesiredAltitude;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::desiredAltitude);
|
||||
}
|
||||
@@ -666,10 +769,11 @@ void Unit::setDesiredSpeedType(string newDesiredSpeedType)
|
||||
{
|
||||
if (desiredSpeedType != (newDesiredSpeedType.compare("GS") == 0)) {
|
||||
desiredSpeedType = newDesiredSpeedType.compare("GS") == 0;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::desiredSpeedType);
|
||||
}
|
||||
@@ -679,10 +783,11 @@ void Unit::setDesiredAltitudeType(string newDesiredAltitudeType)
|
||||
{
|
||||
if (desiredAltitudeType != (newDesiredAltitudeType.compare("AGL") == 0)) {
|
||||
desiredAltitudeType = newDesiredAltitudeType.compare("AGL") == 0;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::desiredAltitudeType);
|
||||
}
|
||||
@@ -692,12 +797,13 @@ void Unit::goToDestination(string enrouteTask)
|
||||
{
|
||||
if (activeDestination != NULL)
|
||||
{
|
||||
Command* command = dynamic_cast<Command*>(new Move(groupName, activeDestination, getDesiredSpeed(), getDesiredSpeedType() ? "GS" : "CAS", getDesiredAltitude(), getDesiredAltitudeType() ? "AGL" : "ASL", enrouteTask, getCategory(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
Command* command = dynamic_cast<Command*>(new Move(groupName, activeDestination, getDesiredSpeed(), getDesiredSpeedType() ? "GS" : "CAS", getDesiredAltitude(), getDesiredAltitudeType() ? "AGL" : "ASL", enrouteTask, getCategory(), getFollowRoads(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: if the current active path has a threshold set, that value will be used instead of the passed one
|
||||
bool Unit::isDestinationReached(double threshold)
|
||||
{
|
||||
if (activeDestination != NULL)
|
||||
@@ -707,7 +813,7 @@ bool Unit::isDestinationReached(double threshold)
|
||||
{
|
||||
double dist = 0;
|
||||
Geodesic::WGS84().Inverse(p->getPosition().lat, p->getPosition().lng, activeDestination.lat, activeDestination.lng, dist);
|
||||
if (dist < threshold)
|
||||
if (dist < (activeDestination.threshold == 0? threshold: activeDestination.threshold))
|
||||
{
|
||||
log(unitName + " destination reached");
|
||||
return true;
|
||||
@@ -788,3 +894,11 @@ void Unit::setHasTaskAssigned(bool newHasTaskAssigned) {
|
||||
void Unit::triggerUpdate(unsigned char datumIndex) {
|
||||
updateTimeMap[datumIndex] = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
unsigned int Unit::computeTotalAmmo()
|
||||
{
|
||||
unsigned int totalShells = 0;
|
||||
for (auto const& ammoItem : ammo)
|
||||
totalShells += ammoItem.quantity;
|
||||
return totalShells;
|
||||
}
|
||||
@@ -151,7 +151,7 @@ void UnitsManager::deleteUnit(unsigned int ID, bool explosion, string explosionT
|
||||
}
|
||||
}
|
||||
|
||||
Unit* UnitsManager::getClosestUnit(Unit* unit, unsigned char coalition, vector<string> categories, double &distance) {
|
||||
Unit* UnitsManager::getClosestUnit(Unit* unit, unsigned char coalition, vector<string> categories, double &distance, bool airborneOnly) {
|
||||
Unit* closestUnit = nullptr;
|
||||
distance = 0;
|
||||
|
||||
@@ -167,6 +167,9 @@ Unit* UnitsManager::getClosestUnit(Unit* unit, unsigned char coalition, vector<s
|
||||
|
||||
/* Check if the unit belongs to the desired coalition, is alive, and is of the category requested */
|
||||
if (requestedCategory && p.second->getCoalition() == coalition && p.second->getAlive()) {
|
||||
/* Check if the unit is airborne */
|
||||
if (airborneOnly && !p.second->getAirborne())
|
||||
continue;
|
||||
/* Compute the distance from the unit to the tested unit */
|
||||
double dist;
|
||||
double bearing1;
|
||||
@@ -194,10 +197,13 @@ Unit* UnitsManager::getClosestUnit(Unit* unit, unsigned char coalition, vector<s
|
||||
return closestUnit;
|
||||
}
|
||||
|
||||
map<Unit*, double> UnitsManager::getUnitsInRange(Unit* unit, unsigned char coalition, vector<string> categories, double range) {
|
||||
map<Unit*, double> UnitsManager::getUnitsInRange(Unit* unit, unsigned char coalition, vector<string> categories, double range, bool airborneOnly) {
|
||||
map<Unit*, double> unitsInRange;
|
||||
|
||||
for (auto const& p : units) {
|
||||
if (airborneOnly && !p.second->getAirborne())
|
||||
continue;
|
||||
|
||||
/* Check if the units category is of the correct type */
|
||||
bool requestedCategory = false;
|
||||
for (auto const& category : categories) {
|
||||
@@ -113,4 +113,11 @@ Bomb::Bomb(json::value json, unsigned int ID) : Weapon(json, ID)
|
||||
{
|
||||
log("New Bomb created with ID: " + to_string(ID));
|
||||
setCategory("Bomb");
|
||||
};
|
||||
|
||||
/* Shell */
|
||||
Shell::Shell(json::value json, unsigned int ID) : Weapon(json, ID)
|
||||
{
|
||||
log("New Shell created with ID: " + to_string(ID));
|
||||
setCategory("Shell");
|
||||
};
|
||||
@@ -41,6 +41,8 @@ void WeaponsManager::update(json::value& json, double dt)
|
||||
weapons[ID] = dynamic_cast<Weapon*>(new Missile(p.second, ID));
|
||||
else if (category.compare("Bomb") == 0)
|
||||
weapons[ID] = dynamic_cast<Weapon*>(new Bomb(p.second, ID));
|
||||
else if (category.compare("Shell") == 0)
|
||||
weapons[ID] = dynamic_cast<Weapon*>(new Shell(p.second, ID));
|
||||
|
||||
/* Initialize the weapon if creation was successfull */
|
||||
if (weapons.count(ID) != 0) {
|
||||
110
backend/dcstools/dcstools.rc
Normal file
110
backend/dcstools/dcstools.rc
Normal file
@@ -0,0 +1,110 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Italian (Italy) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
|
||||
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // Italian (Italy) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United Kingdom) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,0,0,0
|
||||
PRODUCTVERSION 1,0,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "DCS Olympus"
|
||||
VALUE "FileDescription", "DCS Olympus"
|
||||
VALUE "FileVersion", "2.0.0.0"
|
||||
VALUE "InternalName", "dcstools.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2023"
|
||||
VALUE "OriginalFilename", "dcstools.dll"
|
||||
VALUE "ProductName", "DCS Olympus"
|
||||
VALUE "ProductVersion", "2.0.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (United Kingdom) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\dcstools.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\luatools\luatools.vcxproj">
|
||||
@@ -32,6 +33,9 @@
|
||||
<Project>{b85009ce-4a5c-4a5a-b85d-001b3a2651b2}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="dcstools.rc" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
@@ -73,19 +77,23 @@
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>.\..\..\bin\</OutDir>
|
||||
<OutDir>.\..\..\build\backend\bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
@@ -134,6 +142,7 @@
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<Version>{{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}</Version>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -23,5 +23,13 @@
|
||||
<ClInclude Include="include\dcstools.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="dcstools.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -7,6 +7,7 @@ void DllExport LogWarning(lua_State* L, string message);
|
||||
void DllExport LogError(lua_State* L, string message);
|
||||
void DllExport Log(lua_State* L, string message, unsigned int level);
|
||||
int DllExport dostring_in(lua_State* L, string target, string command);
|
||||
int DllExport dostring_in(lua_State* L, string target, string command, string& result);
|
||||
void DllExport getAllUnits(lua_State* L, map<unsigned int, json::value>& unitJSONs);
|
||||
unsigned int DllExport TACANChannelToFrequency(unsigned int channel, char XY);
|
||||
|
||||
14
backend/dcstools/resource.h
Normal file
14
backend/dcstools/resource.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by dcstools.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -82,7 +82,7 @@ void getAllUnits(lua_State* L, map<unsigned int, json::value>& unitJSONs)
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, 2) != 0)
|
||||
{
|
||||
unsigned int ID = lua_tonumber(L, -2);
|
||||
unsigned int ID = static_cast<unsigned int>(lua_tonumber(L, -2));
|
||||
if (unitJSONs.find(ID) == unitJSONs.end())
|
||||
unitJSONs[ID] = json::value::object();
|
||||
luaTableToJSON(L, -1, unitJSONs[ID]);
|
||||
@@ -101,7 +101,24 @@ int dostring_in(lua_State* L, string target, string command)
|
||||
lua_getfield(L, -1, "dostring_in");
|
||||
lua_pushstring(L, target.c_str());
|
||||
lua_pushstring(L, command.c_str());
|
||||
return lua_pcall(L, 2, 0, 0);
|
||||
int res = lua_pcall(L, 2, 0, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
int dostring_in(lua_State* L, string target, string command, string &result)
|
||||
{
|
||||
lua_getglobal(L, "net");
|
||||
lua_getfield(L, -1, "dostring_in");
|
||||
lua_pushstring(L, target.c_str());
|
||||
lua_pushstring(L, command.c_str());
|
||||
int res = lua_pcall(L, 2, 0, 0);
|
||||
|
||||
// Get the first result in the stack
|
||||
if (lua_isstring(L, -1)) {
|
||||
result = lua_tostring(L, -1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
unsigned int TACANChannelToFrequency(unsigned int channel, char XY)
|
||||
2579
backend/docs
Normal file
2579
backend/docs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "framework.h"
|
||||
|
||||
void DllExport setLogDirectory(std::string m_dirPath);
|
||||
void DllExport log(const std::string& sMessage, bool addToJSON = false);
|
||||
void DllExport log(const std::wstring& sMessage, bool addToJSON = false);
|
||||
void DllExport getLogsJSON(json::value& json, unsigned long long time);
|
||||
@@ -8,6 +8,7 @@ public:
|
||||
void log(const string& sMessage, bool addToJSON);
|
||||
void log(const wstring& sMessage, bool addToJSON);
|
||||
void toJSON(json::value& json, unsigned long long time);
|
||||
void setDirectory(string newDirPath);
|
||||
|
||||
static Logger* GetLogger();
|
||||
|
||||
@@ -20,9 +21,11 @@ private:
|
||||
static Logger* m_pThis;
|
||||
static ofstream m_Logfile;
|
||||
static std::map<unsigned long long, std::string> m_logs;
|
||||
static string m_dirPath;
|
||||
|
||||
mutex mutexLock;
|
||||
|
||||
void Clear();
|
||||
void Open();
|
||||
void Close();
|
||||
};
|
||||
110
backend/logger/logger.rc
Normal file
110
backend/logger/logger.rc
Normal file
@@ -0,0 +1,110 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Italian (Italy) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
|
||||
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // Italian (Italy) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United Kingdom) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,0,0,0
|
||||
PRODUCTVERSION 1,0,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "DCS Olympus"
|
||||
VALUE "FileDescription", "DCS Olympus"
|
||||
VALUE "FileVersion", "2.0.0.0"
|
||||
VALUE "InternalName", "logger.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2023"
|
||||
VALUE "OriginalFilename", "logger.dll"
|
||||
VALUE "ProductName", "DCS Olympus"
|
||||
VALUE "ProductVersion", "2.0.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (United Kingdom) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
@@ -25,12 +25,16 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\interface.h" />
|
||||
<ClInclude Include="include\logger.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\utils\utils.vcxproj">
|
||||
<Project>{b85009ce-4a5c-4a5a-b85d-001b3a2651b2}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="logger.rc" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
@@ -72,19 +76,23 @@
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>.\..\..\bin\</OutDir>
|
||||
<OutDir>.\..\..\build\backend\bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
@@ -133,6 +141,7 @@
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<Version>{{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}</Version>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -29,5 +29,13 @@
|
||||
<ClInclude Include="include\interface.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="logger.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
14
backend/logger/resource.h
Normal file
14
backend/logger/resource.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by logger.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -4,6 +4,11 @@
|
||||
|
||||
#define LOGGER Logger::GetLogger()
|
||||
|
||||
void setLogDirectory(string m_dirPath)
|
||||
{
|
||||
LOGGER->setDirectory(m_dirPath);
|
||||
}
|
||||
|
||||
void log(const string& message, bool addToJSON)
|
||||
{
|
||||
LOGGER->log(message, addToJSON);
|
||||
@@ -8,25 +8,51 @@ const string Logger::m_sFileName = LOG_NAME;
|
||||
Logger* Logger::m_pThis = NULL;
|
||||
ofstream Logger::m_Logfile;
|
||||
std::map<unsigned long long, std::string> Logger::m_logs;
|
||||
std::string Logger::m_dirPath;
|
||||
|
||||
Logger::Logger()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Logger* Logger::GetLogger()
|
||||
{
|
||||
if (m_pThis == NULL) {
|
||||
m_pThis = new Logger();
|
||||
std::filesystem::path dirPath = std::filesystem::temp_directory_path();
|
||||
m_Logfile.open((dirPath.string() + m_sFileName).c_str(), ios::out);
|
||||
m_pThis->Clear();
|
||||
}
|
||||
return m_pThis;
|
||||
}
|
||||
|
||||
void Logger::setDirectory(string newDirPath)
|
||||
{
|
||||
m_dirPath = newDirPath;
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Logger::Clear()
|
||||
{
|
||||
lock_guard<mutex> guard(mutexLock);
|
||||
try {
|
||||
m_Logfile.open((m_dirPath + m_sFileName).c_str(), ios::out | ios::trunc);
|
||||
}
|
||||
catch (...) {
|
||||
std::filesystem::path m_dirPath = std::filesystem::temp_directory_path();
|
||||
m_Logfile.open((m_dirPath.string() + m_sFileName).c_str(), ios::out | ios::trunc);
|
||||
}
|
||||
m_Logfile << "Creating a new log instance\n";
|
||||
m_pThis->Close();
|
||||
}
|
||||
|
||||
void Logger::Open()
|
||||
{
|
||||
std::filesystem::path dirPath = std::filesystem::temp_directory_path();
|
||||
m_Logfile.open((dirPath.string() + m_sFileName).c_str(), ios::out | ios::app);
|
||||
try {
|
||||
m_Logfile.open((m_dirPath + m_sFileName).c_str(), ios::out | std::ios::app);
|
||||
}
|
||||
catch (...) {
|
||||
std::filesystem::path m_dirPath = std::filesystem::temp_directory_path();
|
||||
m_Logfile.open((m_dirPath.string() + m_sFileName).c_str(), ios::out | std::ios::app);
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::Close()
|
||||
@@ -5,6 +5,7 @@ void DllExport stackUpdate(lua_State* L, int& stackDepth, int initialStack = 0);
|
||||
void DllExport stackPop(lua_State* L, int popDepth = 1);
|
||||
void DllExport stackClean(lua_State* L, int stackDepth);
|
||||
void DllExport luaTableToJSON(lua_State* L, int index, json::value& json, bool logKeys = false);
|
||||
void DllExport luaLogTableKeys(lua_State* L, int index);
|
||||
|
||||
#define STACK_UPDATE stackUpdate(L, stackDepth, initialStack);
|
||||
#define STACK_INIT int stackDepth = 0; int initialStack = 0; stackUpdate(L, initialStack);
|
||||
110
backend/luatools/luatools.rc
Normal file
110
backend/luatools/luatools.rc
Normal file
@@ -0,0 +1,110 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Italian (Italy) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
|
||||
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // Italian (Italy) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United Kingdom) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,0,0,0
|
||||
PRODUCTVERSION 1,0,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "DCS Olympus"
|
||||
VALUE "FileDescription", "DCS Olympus"
|
||||
VALUE "FileVersion", "2.0.0.0"
|
||||
VALUE "InternalName", "luatools.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2023"
|
||||
VALUE "OriginalFilename", "luatools.dll"
|
||||
VALUE "ProductName", "DCS Olympus"
|
||||
VALUE "ProductVersion", "2.0.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (United Kingdom) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
@@ -60,19 +60,23 @@
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>.\..\..\bin\</OutDir>
|
||||
<OutDir>.\..\..\build\backend\bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
@@ -121,6 +125,7 @@
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<Version>{{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}</Version>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -160,6 +165,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\luatools.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="luatools.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
@@ -23,5 +23,13 @@
|
||||
<ClInclude Include="include\luatools.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="luatools.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
14
backend/luatools/resource.h
Normal file
14
backend/luatools/resource.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by luatools.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -18,6 +18,29 @@ void stackClean(lua_State* L, int stackDepth)
|
||||
lua_pop(L, stackDepth);
|
||||
}
|
||||
|
||||
|
||||
void luaLogTableKeys(lua_State* L, int index)
|
||||
{
|
||||
if (lua_istable(L, index))
|
||||
{
|
||||
STACK_INIT;
|
||||
|
||||
lua_pushvalue(L, index);
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2))
|
||||
{
|
||||
lua_pushvalue(L, -2);
|
||||
const char* key = lua_tostring(L, -1);
|
||||
log(key);
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
STACK_CLEAN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaTableToJSON(lua_State* L, int index, json::value& json, bool logKeys)
|
||||
{
|
||||
if (lua_istable(L, index))
|
||||
110
backend/olympus/olympus.rc
Normal file
110
backend/olympus/olympus.rc
Normal file
@@ -0,0 +1,110 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Italian (Italy) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
|
||||
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // Italian (Italy) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United Kingdom) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,0,0,0
|
||||
PRODUCTVERSION 1,0,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "DCS Olympus"
|
||||
VALUE "FileDescription", "DCS Olympus"
|
||||
VALUE "FileVersion", "2.0.0.0"
|
||||
VALUE "InternalName", "olympus.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2023"
|
||||
VALUE "OriginalFilename", "olympus.dll"
|
||||
VALUE "ProductName", "DCS Olympus"
|
||||
VALUE "ProductVersion", "2.0.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (United Kingdom) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
@@ -20,10 +20,19 @@
|
||||
<ProjectReference Include="..\logger\logger.vcxproj">
|
||||
<Project>{873ecabe-fcfe-4217-ac15-91959c3cf1c6}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\luatools\luatools.vcxproj">
|
||||
<Project>{de139ec1-4f88-47d5-be73-f41915fe14a3}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\utils\utils.vcxproj">
|
||||
<Project>{b85009ce-4a5c-4a5a-b85d-001b3a2651b2}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="olympus.rc" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
@@ -53,9 +62,11 @@
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -64,10 +75,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>.\..\..\bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgAutoLink>true</VcpkgAutoLink>
|
||||
<OutDir>.\..\..\build\backend\bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
@@ -87,6 +95,7 @@
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>lua.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\third-party\lua</AdditionalLibraryDirectories>
|
||||
<Version>{{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}</Version>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -112,6 +121,7 @@
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>lua.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\third-party\lua</AdditionalLibraryDirectories>
|
||||
<DelayLoadDLLs>dcstools.dll;logger.dll;utils.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
@@ -13,4 +13,10 @@
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="olympus.rc" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
14
backend/olympus/resource.h
Normal file
14
backend/olympus/resource.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by olympus.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -5,38 +5,60 @@
|
||||
|
||||
/* Run-time linking to core dll allows for "hot swap". This is useful for development but could be removed when stable.*/
|
||||
HINSTANCE hGetProcIDDLL = NULL;
|
||||
typedef int(__stdcall* f_coreInit)(lua_State* L);
|
||||
typedef int(__stdcall* f_coreInit)(lua_State* L, const char* path);
|
||||
typedef int(__stdcall* f_coreDeinit)(lua_State* L);
|
||||
typedef int(__stdcall* f_coreFrame)(lua_State* L);
|
||||
typedef int(__stdcall* f_coreUnitsData)(lua_State* L);
|
||||
typedef int(__stdcall* f_coreWeaponsData)(lua_State* L);
|
||||
typedef int(__stdcall* f_coreMissionData)(lua_State* L);
|
||||
typedef int(__stdcall* f_coreDrawingsData)(lua_State* L);
|
||||
typedef int(__stdcall* f_coreSetExecutionResults)(lua_State* L);
|
||||
f_coreInit coreInit = nullptr;
|
||||
f_coreDeinit coreDeinit = nullptr;
|
||||
f_coreFrame coreFrame = nullptr;
|
||||
f_coreUnitsData coreUnitsData = nullptr;
|
||||
f_coreWeaponsData coreWeaponsData = nullptr;
|
||||
f_coreMissionData coreMissionData = nullptr;
|
||||
f_coreDrawingsData coreDrawingsData = nullptr;
|
||||
f_coreSetExecutionResults coreExecutionResults = nullptr;
|
||||
|
||||
string modPath;
|
||||
|
||||
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
|
||||
std::string GetLastErrorAsString()
|
||||
{
|
||||
//Get the error message ID, if any.
|
||||
DWORD errorMessageID = ::GetLastError();
|
||||
if (errorMessageID == 0) {
|
||||
return std::string(); //No error message has been recorded
|
||||
}
|
||||
|
||||
LPSTR messageBuffer = nullptr;
|
||||
|
||||
//Ask Win32 to give us the string version of that message ID.
|
||||
//The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
|
||||
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
|
||||
|
||||
//Copy the error message into a std::string.
|
||||
std::string message(messageBuffer, size);
|
||||
|
||||
//Free the Win32's string's buffer.
|
||||
LocalFree(messageBuffer);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
static int onSimulationStart(lua_State* L)
|
||||
{
|
||||
LogInfo(L, "Trying to load core.dll from " + modPath);
|
||||
SetDllDirectoryA(modPath.c_str());
|
||||
|
||||
setLogDirectory(modPath);
|
||||
|
||||
log("onSimulationStart callback called successfully");
|
||||
|
||||
string modLocation;
|
||||
string dllLocation;
|
||||
char* buf = nullptr;
|
||||
size_t sz = 0;
|
||||
if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr)
|
||||
{
|
||||
modLocation = buf;
|
||||
free(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
log("DCSOLYMPUS_PATH environment variable is missing");
|
||||
goto error;
|
||||
}
|
||||
dllLocation = modLocation + "\\bin\\core.dll";
|
||||
string dllLocation = modPath + "\\core.dll";
|
||||
|
||||
log("Loading core.dll");
|
||||
hGetProcIDDLL = LoadLibrary(to_wstring(dllLocation).c_str());
|
||||
@@ -90,14 +112,28 @@ static int onSimulationStart(lua_State* L)
|
||||
goto error;
|
||||
}
|
||||
|
||||
coreInit(L);
|
||||
coreDrawingsData = (f_coreDrawingsData)GetProcAddress(hGetProcIDDLL, "coreDrawingsData");
|
||||
if (!coreDrawingsData)
|
||||
{
|
||||
LogError(L, "Error getting coreDrawingsData ProcAddress from DLL");
|
||||
goto error;
|
||||
}
|
||||
|
||||
coreExecutionResults = (f_coreSetExecutionResults)GetProcAddress(hGetProcIDDLL, "coreSetExecutionResults");
|
||||
if (!coreExecutionResults)
|
||||
{
|
||||
LogError(L, "Error getting coreSetExecutionResults ProcAddress from DLL");
|
||||
goto error;
|
||||
}
|
||||
|
||||
coreInit(L, modPath.c_str());
|
||||
|
||||
LogInfo(L, "Module loaded and started successfully.");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
LogError(L, "Error while loading module, see Olympus.log in temporary folder for additional details.");
|
||||
LogError(L, "Error while loading module: " + GetLastErrorAsString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -137,6 +173,8 @@ static int onSimulationStop(lua_State* L)
|
||||
coreUnitsData = nullptr;
|
||||
coreWeaponsData = nullptr;
|
||||
coreMissionData = nullptr;
|
||||
|
||||
coreDrawingsData = nullptr;
|
||||
}
|
||||
|
||||
hGetProcIDDLL = NULL;
|
||||
@@ -144,7 +182,7 @@ static int onSimulationStop(lua_State* L)
|
||||
return 0;
|
||||
|
||||
error:
|
||||
LogError(L, "Error while unloading module, see Olympus.log in temporary folder for additional details.");
|
||||
LogError(L, "Error while unloading module: " + GetLastErrorAsString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -175,6 +213,24 @@ static int setMissionData(lua_State* L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setDrawingsData(lua_State* L)
|
||||
{
|
||||
if (coreDrawingsData)
|
||||
{
|
||||
coreDrawingsData(L);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setExecutionResults(lua_State* L)
|
||||
{
|
||||
if (coreExecutionResults)
|
||||
{
|
||||
coreExecutionResults(L);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg Map[] = {
|
||||
{"onSimulationStart", onSimulationStart},
|
||||
{"onSimulationFrame", onSimulationFrame},
|
||||
@@ -182,11 +238,41 @@ static const luaL_Reg Map[] = {
|
||||
{"setUnitsData", setUnitsData },
|
||||
{"setWeaponsData", setWeaponsData },
|
||||
{"setMissionData", setMissionData },
|
||||
{"setDrawingsData", setDrawingsData },
|
||||
{"setExecutionResults", setExecutionResults },
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
extern "C" DllExport int luaopen_olympus(lua_State * L)
|
||||
{
|
||||
lua_getglobal(L, "require");
|
||||
lua_pushstring(L, "lfs");
|
||||
lua_pcall(L, 1, 1, 0);
|
||||
lua_getfield(L, -1, "writedir");
|
||||
lua_pcall(L, 0, 1, 0);
|
||||
if (lua_isstring(L, -1)) {
|
||||
modPath = string(lua_tostring(L, -1)) + "Mods\\Services\\Olympus\\bin\\";
|
||||
SetDllDirectoryA(modPath.c_str());
|
||||
LogInfo(L, "Instance location retrieved successfully");
|
||||
}
|
||||
else {
|
||||
/* Log without using the helper dlls because we have not loaded them yet here */
|
||||
lua_getglobal(L, "log");
|
||||
lua_getfield(L, -1, "ERROR");
|
||||
int errorLevel = (int)lua_tointeger(L, -1);
|
||||
|
||||
lua_getglobal(L, "log");
|
||||
lua_getfield(L, -1, "write");
|
||||
lua_pushstring(L, "Olympus.dll");
|
||||
lua_pushnumber(L, errorLevel);
|
||||
lua_pushstring(L, "An error has occurred while trying to retrieve Olympus's instance location");
|
||||
lua_pcall(L, 3, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LogInfo(L, "Loading .dlls from " + modPath);
|
||||
|
||||
luaL_register(L, "olympus", Map);
|
||||
return 1;
|
||||
}
|
||||
30
backend/shared/include/defines.h
Normal file
30
backend/shared/include/defines.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#define VERSION "{{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}"
|
||||
#define LOG_NAME "..\\..\\..\\..\\Logs\\Olympus_log.txt"
|
||||
|
||||
#define REST_ADDRESS "http://localhost:3001"
|
||||
#define REST_URI "olympus"
|
||||
#define UNITS_URI "units"
|
||||
#define WEAPONS_URI "weapons"
|
||||
#define LOGS_URI "logs"
|
||||
#define AIRBASES_URI "airbases"
|
||||
#define BULLSEYE_URI "bullseyes"
|
||||
#define SPOTS_URI "spots"
|
||||
#define MISSION_URI "mission"
|
||||
#define COMMANDS_URI "commands"
|
||||
#define DRAWINGS_URI "drawings"
|
||||
|
||||
#define FRAMERATE_TIME_INTERVAL 0.05
|
||||
|
||||
#define OLYMPUS_JSON_PATH "..\\..\\..\\..\\Config\\olympus.json"
|
||||
#define AIRCRAFT_DATABASE_PATH "..\\databases\\units\\aircraftdatabase.json"
|
||||
#define HELICOPTER_DATABASE_PATH "..\\databases\\units\\helicopterdatabase.json"
|
||||
#define GROUNDUNIT_DATABASE_PATH "..\\databases\\units\\groundunitdatabase.json"
|
||||
#define NAVYUNIT_DATABASE_PATH "..\\databases\\units\\navyunitdatabase.json"
|
||||
|
||||
#define MIST_SCRIPT "..\\Scripts\\mist.lua"
|
||||
#define OLYMPUS_COMMAND_SCRIPT "..\\Scripts\\OlympusCommand.lua"
|
||||
#define UNIT_PAYLOADS_SCRIPT "..\\Scripts\\unitPayloads.lua"
|
||||
#define TEMPLATES_SCRIPT "..\\Scripts\\templates.lua"
|
||||
#define MODS_SCRIPT "..\\Scripts\\mods.lua"
|
||||
@@ -6,6 +6,7 @@ struct Coords {
|
||||
double lat = 0;
|
||||
double lng = 0;
|
||||
double alt = 0;
|
||||
double threshold = 0; // used for proximity checks only, not part of the actual coordinates
|
||||
};
|
||||
|
||||
struct Offset {
|
||||
14
backend/utils/resource.h
Normal file
14
backend/utils/resource.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by utils.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "framework.h"
|
||||
#include "utils.h"
|
||||
#include <chrono>
|
||||
|
||||
// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
|
||||
const std::string CurrentDateTime()
|
||||
@@ -44,6 +45,11 @@ std::string to_string(const std::wstring& wstr)
|
||||
|
||||
std::string random_string(size_t length)
|
||||
{
|
||||
// Use nanoseconds since epoch as a seed for random number generation
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
auto nanos = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
|
||||
srand(static_cast<unsigned int>(nanos));
|
||||
|
||||
auto randchar = []() -> char
|
||||
{
|
||||
const char charset[] =
|
||||
@@ -58,9 +64,9 @@ std::string random_string(size_t length)
|
||||
return str;
|
||||
}
|
||||
|
||||
bool operator== (const Coords& a, const Coords& b) { return a.lat == b.lat && a.lng == b.lng && a.alt == b.alt; }
|
||||
bool operator== (const Coords& a, const Coords& b) { return a.lat == b.lat && a.lng == b.lng && a.alt == b.alt && a.threshold == b.threshold; }
|
||||
bool operator!= (const Coords& a, const Coords& b) { return !(a == b); }
|
||||
bool operator== (const Coords& a, const double& b) { return a.lat == b && a.lng == b && a.alt == b; }
|
||||
bool operator== (const Coords& a, const double& b) { return a.lat == b && a.lng == b && a.alt == b && a.threshold == b; }
|
||||
bool operator!= (const Coords& a, const double& b) { return !(a == b); }
|
||||
|
||||
bool operator== (const Offset& a, const Offset& b) { return a.x == b.x && a.y == b.y && a.z == b.z; }
|
||||
110
backend/utils/utils.rc
Normal file
110
backend/utils/utils.rc
Normal file
@@ -0,0 +1,110 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Italian (Italy) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
|
||||
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // Italian (Italy) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United Kingdom) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,0,0,0
|
||||
PRODUCTVERSION 1,0,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "DCS Olympus"
|
||||
VALUE "FileDescription", "DCS Olympus"
|
||||
VALUE "FileVersion", "2.0.0.0"
|
||||
VALUE "InternalName", "utils.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2023"
|
||||
VALUE "OriginalFilename", "utils.dll"
|
||||
VALUE "ProductName", "TODO: <Product name>"
|
||||
VALUE "ProductVersion", "2.0.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (United Kingdom) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
@@ -20,10 +20,14 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\utils.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\utils.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="utils.rc" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
@@ -65,19 +69,23 @@
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\DCSOlympus.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>.\..\..\bin\</OutDir>
|
||||
<OutDir>.\..\..\build\backend\bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>.\..\..\bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
@@ -14,10 +14,16 @@
|
||||
<ClInclude Include="include\utils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\utils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="utils.rc" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
14
backend/vcpkg-configuration.json
Normal file
14
backend/vcpkg-configuration.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"default-registry": {
|
||||
"kind": "git",
|
||||
"baseline": "7f9f0e44db287e8e67c0e888141bfa200ab45121",
|
||||
"repository": "https://github.com/microsoft/vcpkg"
|
||||
},
|
||||
"registries": [
|
||||
{
|
||||
"kind": "artifact",
|
||||
"location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip",
|
||||
"name": "microsoft"
|
||||
}
|
||||
]
|
||||
}
|
||||
6
backend/vcpkg.json
Normal file
6
backend/vcpkg.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"cpprestsdk",
|
||||
"geographiclib"
|
||||
]
|
||||
}
|
||||
@@ -1,17 +1,2 @@
|
||||
cd src
|
||||
msbuild olympus.sln /t:Rebuild /p:Configuration=Release
|
||||
cd ..
|
||||
cd client
|
||||
call npm install
|
||||
rmdir /s /q "hgt"
|
||||
call npm run emit-declarations
|
||||
call npm run build
|
||||
cd "plugins\controltips"
|
||||
call npm run build
|
||||
cd "..\.."
|
||||
cd "plugins\databasemanager"
|
||||
call npm run build
|
||||
cd "..\.."
|
||||
call npm prune --production
|
||||
cd ..
|
||||
call "C:\Program Files (x86)\Inno Setup 6\iscc.exe" "installer\olympus.iss"
|
||||
call .\scripts\batch\build.bat
|
||||
call .\scripts\batch\package.bat
|
||||
2
client/.vscode/settings.json
vendored
2
client/.vscode/settings.json
vendored
@@ -1,2 +0,0 @@
|
||||
{
|
||||
}
|
||||
2366
client/@types/olympus/index.d.ts
vendored
2366
client/@types/olympus/index.d.ts
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,49 +0,0 @@
|
||||
var express = require('express');
|
||||
var path = require('path');
|
||||
var cookieParser = require('cookie-parser');
|
||||
var logger = require('morgan');
|
||||
var fs = require('fs');
|
||||
var bodyParser = require('body-parser');
|
||||
|
||||
var atcRouter = require('./routes/api/atc');
|
||||
var airbasesRouter = require('./routes/api/airbases');
|
||||
var elevationRouter = require('./routes/api/elevation');
|
||||
var databasesRouter = require('./routes/api/databases');
|
||||
var indexRouter = require('./routes/index');
|
||||
var uikitRouter = require('./routes/uikit');
|
||||
var usersRouter = require('./routes/users');
|
||||
var resourcesRouter = require('./routes/resources');
|
||||
var pluginsRouter = require('./routes/plugins');
|
||||
|
||||
var app = express();
|
||||
|
||||
app.use(logger('dev'));
|
||||
app.use(bodyParser.json({limit: '50mb'}));
|
||||
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
|
||||
app.use(cookieParser());
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
app.use('/', indexRouter);
|
||||
app.use('/api/atc', atcRouter);
|
||||
app.use('/api/airbases', airbasesRouter);
|
||||
app.use('/api/elevation', elevationRouter);
|
||||
app.use('/api/databases', databasesRouter);
|
||||
app.use('/plugins', pluginsRouter)
|
||||
app.use('/users', usersRouter);
|
||||
app.use('/uikit', uikitRouter);
|
||||
app.use('/resources', resourcesRouter);
|
||||
|
||||
app.set('view engine', 'ejs');
|
||||
|
||||
let rawdata = fs.readFileSync('../olympus.json');
|
||||
let config = JSON.parse(rawdata);
|
||||
if (config["server"] != undefined)
|
||||
app.get('/config', (req, res) => res.send(config["server"]));
|
||||
|
||||
module.exports = app;
|
||||
|
||||
const DemoDataGenerator = require('./demo.js');
|
||||
var demoDataGenerator = new DemoDataGenerator(app);
|
||||
|
||||
|
||||
|
||||
100
client/bin/www
100
client/bin/www
@@ -1,100 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var fs = require('fs');
|
||||
let rawdata = fs.readFileSync('../olympus.json');
|
||||
let config = JSON.parse(rawdata);
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var app = require('../app');
|
||||
var debug = require('debug')('client:server');
|
||||
var http = require('http');
|
||||
|
||||
/**
|
||||
* Get port from environment and store in Express.
|
||||
*/
|
||||
|
||||
var configPort = null;
|
||||
if (config["client"] != undefined && config["client"]["port"] != undefined) {
|
||||
configPort = config["client"]["port"];
|
||||
}
|
||||
|
||||
var port = normalizePort(configPort || '3000');
|
||||
app.set('port', port);
|
||||
console.log("Express server listening on port: " + port)
|
||||
|
||||
/**
|
||||
* Create HTTP server.
|
||||
*/
|
||||
|
||||
var server = http.createServer(app);
|
||||
|
||||
/**
|
||||
* Listen on provided port, on all network interfaces.
|
||||
*/
|
||||
|
||||
server.listen(port);
|
||||
server.on('error', onError);
|
||||
server.on('listening', onListening);
|
||||
|
||||
/**
|
||||
* Normalize a port into a number, string, or false.
|
||||
*/
|
||||
|
||||
function normalizePort(val) {
|
||||
var port = parseInt(val, 10);
|
||||
|
||||
if (isNaN(port)) {
|
||||
// named pipe
|
||||
return val;
|
||||
}
|
||||
|
||||
if (port >= 0) {
|
||||
// port number
|
||||
return port;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event listener for HTTP server "error" event.
|
||||
*/
|
||||
|
||||
function onError(error) {
|
||||
if (error.syscall !== 'listen') {
|
||||
throw error;
|
||||
}
|
||||
|
||||
var bind = typeof port === 'string'
|
||||
? 'Pipe ' + port
|
||||
: 'Port ' + port;
|
||||
|
||||
// handle specific listen errors with friendly messages
|
||||
switch (error.code) {
|
||||
case 'EACCES':
|
||||
console.error(bind + ' requires elevated privileges');
|
||||
process.exit(1);
|
||||
break;
|
||||
case 'EADDRINUSE':
|
||||
console.error(bind + ' is already in use');
|
||||
process.exit(1);
|
||||
break;
|
||||
default:
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event listener for HTTP server "listening" event.
|
||||
*/
|
||||
|
||||
function onListening() {
|
||||
var addr = server.address();
|
||||
var bind = typeof addr === 'string'
|
||||
? 'pipe ' + addr
|
||||
: 'port ' + addr.port;
|
||||
debug('Listening on ' + bind);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
copy .\\node_modules\\leaflet\\dist\\leaflet.css .\\public\\stylesheets\\leaflet\\leaflet.css
|
||||
copy .\\node_modules\\leaflet-gesture-handling\\dist\\leaflet-gesture-handling.css .\\public\\stylesheets\\leaflet\\leaflet-gesture-handling.css
|
||||
copy .\\node_modules\\leaflet.nauticscale\\dist\\leaflet.nauticscale.js .\\public\\javascripts\\leaflet.nauticscale.js
|
||||
copy .\\node_modules\\leaflet-path-drag\\dist\\L.Path.Drag.js .\\public\\javascripts\\L.Path.Drag.js
|
||||
@@ -1,2 +0,0 @@
|
||||
start cmd /k "npm run start"
|
||||
start cmd /k "watchify .\src\index.ts --debug -o .\public\javascripts\bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ]
|
||||
472
client/demo.js
472
client/demo.js
@@ -1,472 +0,0 @@
|
||||
const { random } = require('@turf/turf');
|
||||
var basicAuth = require('express-basic-auth')
|
||||
var enc = new TextEncoder();
|
||||
|
||||
const aircraftDatabase = require('./public/databases/units/aircraftDatabase.json');
|
||||
const helicopterDatabase = require('./public/databases/units/helicopterDatabase.json');
|
||||
const groundUnitDatabase = require('./public/databases/units/groundUnitDatabase.json');
|
||||
const navyUnitDatabase = require('./public/databases/units/navyUnitDatabase.json');
|
||||
|
||||
const DEMO_UNIT_DATA = {}
|
||||
|
||||
const DEMO_WEAPONS_DATA = {
|
||||
/*["1001"]:{ category: "Missile", alive: true, coalition: 2, name: "", position: { lat: 37.1, lng: -116, alt: 1000 }, speed: 200, heading: 45 * Math.PI / 180 }, */
|
||||
}
|
||||
|
||||
class DemoDataGenerator {
|
||||
constructor(app)
|
||||
{
|
||||
app.get('/demo/units', (req, res) => this.units(req, res));
|
||||
app.get('/demo/weapons', (req, res) => this.weapons(req, res));
|
||||
app.get('/demo/logs', (req, res) => this.logs(req, res));
|
||||
app.get('/demo/bullseyes', (req, res) => this.bullseyes(req, res));
|
||||
app.get('/demo/airbases', (req, res) => this.airbases(req, res));
|
||||
app.get('/demo/mission', (req, res) => this.mission(req, res));
|
||||
app.get('/demo/commands', (req, res) => this.command(req, res));
|
||||
app.put('/demo', (req, res) => this.put(req, res));
|
||||
|
||||
app.use('/demo', basicAuth({
|
||||
users: {
|
||||
'admin': 'password',
|
||||
'blue': 'bluepassword',
|
||||
'red': 'redpassword'
|
||||
},
|
||||
}))
|
||||
|
||||
|
||||
let baseData = { alive: true, human: false, controlled: true, coalition: 2, country: 0, unitName: "Cool guy", groupName: "Cool group 1", state: 1, task: "Being cool!",
|
||||
hasTask: true, position: { lat: 37, lng: -116, alt: 1000 }, speed: 200, horizontalVelocity: 200, verticalVelicity: 0, heading: 45, isActiveTanker: false, isActiveAWACS: false, onOff: true, followRoads: false, fuel: 50,
|
||||
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
|
||||
formationOffset: { x: 0, y: 0, z: 0 },
|
||||
targetID: 0,
|
||||
targetPosition: { lat: 0, lng: 0, alt: 0 },
|
||||
ROE: 1,
|
||||
reactionToThreat: 1,
|
||||
emissionsCountermeasures: 1,
|
||||
TACAN: { isOn: false, XY: 'Y', callsign: 'TKR', channel: 40 },
|
||||
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
|
||||
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
|
||||
ammo: [],
|
||||
contacts: [],
|
||||
activePath: [],
|
||||
isLeader: true
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
UNCOMMENT TO TEST ALL UNITS
|
||||
|
||||
var databases = Object.assign({}, aircraftDatabase, helicopterDatabase, groundUnitDatabase, navyUnitDatabase);
|
||||
var t = Object.keys(databases).length;
|
||||
var l = Math.floor(Math.sqrt(t));
|
||||
let latIdx = 0;
|
||||
let lngIdx = 0;
|
||||
let idx = 1;
|
||||
console.log(l)
|
||||
for (let name in databases) {
|
||||
if (databases[name].enabled) {
|
||||
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
|
||||
DEMO_UNIT_DATA[idx].name = name;
|
||||
DEMO_UNIT_DATA[idx].groupName = `Group-${idx}`;
|
||||
DEMO_UNIT_DATA[idx].position.lat += latIdx / 5;
|
||||
DEMO_UNIT_DATA[idx].position.lng += lngIdx / 5;
|
||||
|
||||
latIdx += 1;
|
||||
if (latIdx === l) {
|
||||
latIdx = 0;
|
||||
lngIdx += 1;
|
||||
}
|
||||
|
||||
if (name in aircraftDatabase)
|
||||
DEMO_UNIT_DATA[idx].category = "Aircraft";
|
||||
else if (name in helicopterDatabase)
|
||||
DEMO_UNIT_DATA[idx].category = "Helicopter";
|
||||
else if (name in groundUnitDatabase)
|
||||
DEMO_UNIT_DATA[idx].category = "GroundUnit";
|
||||
else if (name in navyUnitDatabase)
|
||||
DEMO_UNIT_DATA[idx].category = "NavyUnit";
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
let idx = 1;
|
||||
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
|
||||
DEMO_UNIT_DATA[idx].name = "S_75M_Volhov";
|
||||
DEMO_UNIT_DATA[idx].groupName = `Group`;
|
||||
DEMO_UNIT_DATA[idx].position.lat += idx / 100;
|
||||
DEMO_UNIT_DATA[idx].category = "GroundUnit";
|
||||
DEMO_UNIT_DATA[idx].isLeader = true;
|
||||
|
||||
idx += 1;
|
||||
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
|
||||
DEMO_UNIT_DATA[idx].name = "SNR_75V";
|
||||
DEMO_UNIT_DATA[idx].groupName = `Group`;
|
||||
DEMO_UNIT_DATA[idx].position.lat += idx / 100;
|
||||
DEMO_UNIT_DATA[idx].category = "GroundUnit";
|
||||
DEMO_UNIT_DATA[idx].isLeader = false;
|
||||
|
||||
idx += 1;
|
||||
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
|
||||
DEMO_UNIT_DATA[idx].name = "Ural-4320 APA-5D";
|
||||
DEMO_UNIT_DATA[idx].groupName = `Group`;
|
||||
DEMO_UNIT_DATA[idx].position.lat += idx / 100;
|
||||
DEMO_UNIT_DATA[idx].category = "GroundUnit";
|
||||
DEMO_UNIT_DATA[idx].isLeader = false;
|
||||
|
||||
this.startTime = Date.now();
|
||||
}
|
||||
|
||||
units(req, res){
|
||||
var array = new Uint8Array();
|
||||
var time = Date.now();
|
||||
array = this.concat(array, this.uint64ToByteArray(BigInt(time)));
|
||||
if (req.query["time"] == 0){
|
||||
for (let idx in DEMO_UNIT_DATA) {
|
||||
const unit = DEMO_UNIT_DATA[idx];
|
||||
array = this.concat(array, this.uint32ToByteArray(idx));
|
||||
array = this.appendString(array, unit.category, 1);
|
||||
array = this.appendUint8(array, unit.alive, 2);
|
||||
array = this.appendUint8(array, unit.human, 3);
|
||||
array = this.appendUint8(array, unit.controlled, 4);
|
||||
array = this.appendUint16(array, unit.coalition, 5);
|
||||
array = this.appendUint8(array, unit.country, 6);
|
||||
array = this.appendString(array, unit.name, 7);
|
||||
array = this.appendString(array, unit.unitName, 8);
|
||||
array = this.appendString(array, unit.groupName, 9);
|
||||
array = this.appendUint8(array, unit.state, 10);
|
||||
array = this.appendString(array, unit.task, 11);
|
||||
array = this.appendUint8(array, unit.hasTask, 12);
|
||||
array = this.appendCoordinates(array, unit.position, 13);
|
||||
array = this.appendDouble(array, unit.speed, 14);
|
||||
array = this.appendDouble(array, unit.horizontalVelocity, 15);
|
||||
array = this.appendDouble(array, unit.verticalVelicity, 16);
|
||||
array = this.appendDouble(array, unit.heading, 17);
|
||||
array = this.appendUint8(array, unit.isActiveTanker, 18);
|
||||
array = this.appendUint8(array, unit.isActiveAWACS, 19);
|
||||
array = this.appendUint8(array, unit.onOff, 20);
|
||||
array = this.appendUint8(array, unit.followRoads, 21);
|
||||
array = this.appendUint16(array, unit.fuel, 22);
|
||||
array = this.appendDouble(array, unit.desiredSpeed, 23);
|
||||
array = this.appendUint8(array, unit.desiredSpeedType, 24);
|
||||
array = this.appendDouble(array, unit.desiredAltitude, 25);
|
||||
array = this.appendUint8(array, unit.desiredAltitudeType, 26);
|
||||
array = this.appendUint32(array, unit.leaderID, 27);
|
||||
array = this.appendOffset(array, unit.formationOffset, 28);
|
||||
array = this.appendUint32(array, unit.targetID, 29);
|
||||
array = this.appendCoordinates(array, unit.targetPosition, 30);
|
||||
array = this.appendUint8(array, unit.ROE, 31);
|
||||
array = this.appendUint8(array, unit.reactionToThreat, 32);
|
||||
array = this.appendUint8(array, unit.emissionsCountermeasures, 33);
|
||||
array = this.appendTACAN(array, unit.TACAN, 34);
|
||||
array = this.appendRadio(array, unit.radio, 35);
|
||||
array = this.appendRadio(array, unit.generalSettings, 36);
|
||||
array = this.appendAmmo(array, unit.ammo, 37);
|
||||
array = this.appendContacts(array, unit.contacts, 38);
|
||||
array = this.appendActivePath(array, unit.activePath, 39);
|
||||
array = this.appendUint8(array, unit.isLeader, 40);
|
||||
array = this.appendUint8(array, unit.operateAs, 41);
|
||||
array = this.concat(array, this.uint8ToByteArray(255));
|
||||
}
|
||||
}
|
||||
res.end(Buffer.from(array, 'binary'));
|
||||
};
|
||||
|
||||
weapons(req, res){
|
||||
var array = new Uint8Array();
|
||||
var time = Date.now();
|
||||
array = this.concat(array, this.uint64ToByteArray(BigInt(time)));
|
||||
for (let idx in DEMO_WEAPONS_DATA) {
|
||||
const weapon = DEMO_WEAPONS_DATA[idx];
|
||||
array = this.concat(array, this.uint32ToByteArray(idx));
|
||||
array = this.appendString(array, weapon.category, 1);
|
||||
array = this.appendUint8(array, weapon.alive, 2);
|
||||
array = this.appendUint16(array, weapon.coalition, 5);
|
||||
array = this.appendString(array, weapon.name, 7);
|
||||
array = this.appendCoordinates(array, weapon.position, 13);
|
||||
array = this.appendDouble(array, weapon.speed, 14);
|
||||
array = this.appendDouble(array, weapon.heading, 15);
|
||||
array = this.concat(array, this.uint8ToByteArray(255));
|
||||
}
|
||||
res.end(Buffer.from(array, 'binary'));
|
||||
};
|
||||
|
||||
concat(array1, array2) {
|
||||
var mergedArray = new Uint8Array(array1.length + array2.length);
|
||||
mergedArray.set(array1);
|
||||
mergedArray.set(array2, array1.length);
|
||||
return mergedArray;
|
||||
}
|
||||
|
||||
uint8ToByteArray(number) {
|
||||
var buffer = new ArrayBuffer(1);
|
||||
var longNum = new Uint8Array(buffer);
|
||||
longNum[0] = number;
|
||||
return Array.from(new Uint8Array(buffer));
|
||||
}
|
||||
|
||||
uint16ToByteArray(number) {
|
||||
var buffer = new ArrayBuffer(2);
|
||||
var longNum = new Uint16Array(buffer);
|
||||
longNum[0] = number;
|
||||
return Array.from(new Uint8Array(buffer));
|
||||
}
|
||||
|
||||
uint32ToByteArray(number) {
|
||||
var buffer = new ArrayBuffer(4);
|
||||
var longNum = new Uint32Array(buffer);
|
||||
longNum[0] = number;
|
||||
return Array.from(new Uint8Array(buffer));
|
||||
}
|
||||
|
||||
uint64ToByteArray(number) {
|
||||
var buffer = new ArrayBuffer(8);
|
||||
var longNum = new BigUint64Array(buffer);
|
||||
longNum[0] = number;
|
||||
return Array.from(new Uint8Array(buffer));
|
||||
}
|
||||
|
||||
doubleToByteArray(number) {
|
||||
var buffer = new ArrayBuffer(8);
|
||||
var longNum = new Float64Array(buffer);
|
||||
longNum[0] = number;
|
||||
return Array.from(new Uint8Array(buffer));
|
||||
}
|
||||
|
||||
appendUint8(array, number, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.uint8ToByteArray(number));
|
||||
return array;
|
||||
}
|
||||
|
||||
appendUint16(array, number, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.uint16ToByteArray(number));
|
||||
return array;
|
||||
}
|
||||
|
||||
appendUint32(array, number, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.uint32ToByteArray(number));
|
||||
return array;
|
||||
}
|
||||
|
||||
appendDouble(array, number, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.doubleToByteArray(number));
|
||||
return array;
|
||||
}
|
||||
|
||||
appendCoordinates(array, coordinates, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.doubleToByteArray(coordinates.lat));
|
||||
array = this.concat(array, this.doubleToByteArray(coordinates.lng));
|
||||
array = this.concat(array, this.doubleToByteArray(coordinates.alt));
|
||||
return array;
|
||||
}
|
||||
|
||||
appendOffset(array, offset, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.doubleToByteArray(offset.x));
|
||||
array = this.concat(array, this.doubleToByteArray(offset.y));
|
||||
array = this.concat(array, this.doubleToByteArray(offset.z));
|
||||
return array;
|
||||
}
|
||||
|
||||
appendString(array, string, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.uint16ToByteArray(string.length));
|
||||
array = this.concat(array, enc.encode(string));
|
||||
return array;
|
||||
}
|
||||
|
||||
padString(string, length) {
|
||||
while (string.length < length)
|
||||
string += " ";
|
||||
return string.substring(0, length);
|
||||
}
|
||||
|
||||
appendTACAN(array, TACAN, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.uint8ToByteArray(TACAN.isOn));
|
||||
array = this.concat(array, this.uint8ToByteArray(TACAN.channel));
|
||||
array = this.concat(array, enc.encode(TACAN.XY));
|
||||
array = this.concat(array, enc.encode(this.padString(TACAN.callsign, 4)));
|
||||
return array;
|
||||
}
|
||||
|
||||
appendRadio(array, radio, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.uint32ToByteArray(radio.frequency));
|
||||
array = this.concat(array, this.uint8ToByteArray(radio.callsign));
|
||||
array = this.concat(array, this.uint8ToByteArray(radio.callsignNumber));
|
||||
return array;
|
||||
}
|
||||
|
||||
appendGeneralSettings(array, generalSettings, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.uint8ToByteArray(generalSettings.prohibitAA));
|
||||
array = this.concat(array, this.uint8ToByteArray(generalSettings.prohibitAfterburner));
|
||||
array = this.concat(array, this.uint8ToByteArray(generalSettings.prohibitAG));
|
||||
array = this.concat(array, this.uint8ToByteArray(generalSettings.prohibitAirWpn));
|
||||
array = this.concat(array, this.uint8ToByteArray(generalSettings.prohibitJettison));
|
||||
return array;
|
||||
}
|
||||
|
||||
appendAmmo(array, ammo, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.uint16ToByteArray(ammo.length));
|
||||
ammo.forEach((element) => {
|
||||
array = this.concat(array, this.uint16ToByteArray(element.quantity));
|
||||
array = this.concat(array, enc.encode(this.padString(element.name, 33)));
|
||||
array = this.concat(array, this.uint8ToByteArray(element.guidance));
|
||||
array = this.concat(array, this.uint8ToByteArray(element.category));
|
||||
array = this.concat(array, this.uint8ToByteArray(element.missileCategory));
|
||||
})
|
||||
return array;
|
||||
}
|
||||
|
||||
appendContacts(array, contacts, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.uint16ToByteArray(contacts.length));
|
||||
contacts.forEach((element) => {
|
||||
array = this.concat(array, this.uint32ToByteArray(element.ID));
|
||||
array = this.concat(array, this.uint8ToByteArray(element.detectionMethod));
|
||||
})
|
||||
return array;
|
||||
}
|
||||
|
||||
appendActivePath(array, activePath, datumIndex) {
|
||||
array = this.concat(array, this.uint8ToByteArray(datumIndex));
|
||||
array = this.concat(array, this.uint16ToByteArray(activePath.length));
|
||||
activePath.forEach((element) => {
|
||||
array = this.concat(array, this.doubleToByteArray(element.lat));
|
||||
array = this.concat(array, this.doubleToByteArray(element.lng));
|
||||
array = this.concat(array, this.doubleToByteArray(element.alt));
|
||||
})
|
||||
return array;
|
||||
}
|
||||
|
||||
logs(req, res){
|
||||
var ret = {logs: {"1": "I'm a log!", "2": "I'm a different log!"}};
|
||||
ret.time = Date.now();
|
||||
ret.frameRate = 60;
|
||||
ret.load = 0;
|
||||
res.send(JSON.stringify(ret));
|
||||
};
|
||||
|
||||
airbases(req, res){
|
||||
var ret = {airbases: {
|
||||
["0"]: {
|
||||
callsign: "Nellis",
|
||||
latitude: 37.3,
|
||||
longitude: -115.8,
|
||||
coalition: "neutral"
|
||||
},
|
||||
["1"]: {
|
||||
callsign: "Red",
|
||||
latitude: 37.3,
|
||||
longitude: -115.75,
|
||||
coalition: "red"
|
||||
},
|
||||
["2"]: {
|
||||
callsign: "Blue",
|
||||
latitude: 37.3,
|
||||
longitude: -115.7,
|
||||
coalition: "blue"
|
||||
}
|
||||
}};
|
||||
ret.time = Date.now();
|
||||
res.send(JSON.stringify(ret));
|
||||
};
|
||||
|
||||
bullseyes(req, res){
|
||||
var ret = {bullseyes: {
|
||||
"0": {
|
||||
latitude: 37.25,
|
||||
longitude: -115.8,
|
||||
coalition: "neutral"
|
||||
},
|
||||
"1": {
|
||||
latitude: 37.25,
|
||||
longitude: -115.75,
|
||||
coalition: "red"
|
||||
},
|
||||
"2": {
|
||||
latitude: 37.25,
|
||||
longitude: -115.7,
|
||||
coalition: "blue"
|
||||
}
|
||||
}};
|
||||
ret.time = Date.now();
|
||||
res.send(JSON.stringify(ret));
|
||||
};
|
||||
|
||||
mission(req, res){
|
||||
var ret = {mission: {theatre: "Nevada"}};
|
||||
ret.time = Date.now();
|
||||
|
||||
ret.mission.dateAndTime = {
|
||||
time: { h: 10, m: 15, s: 34 },
|
||||
date: "",
|
||||
elapsedTime: (Date.now() - this.startTime) / 1000,
|
||||
startTime: 0
|
||||
}
|
||||
|
||||
ret.mission.coalitions = {
|
||||
red: [
|
||||
'RUSSIA',
|
||||
'CHINA'
|
||||
],
|
||||
blue: [
|
||||
'UK',
|
||||
'USA'
|
||||
],
|
||||
neutral: [
|
||||
'ITALY'
|
||||
]
|
||||
}
|
||||
|
||||
ret.mission.commandModeOptions = {
|
||||
restrictSpawns: true,
|
||||
restrictToCoalition: true,
|
||||
setupTime: 0,
|
||||
spawnPoints: {
|
||||
red: 400,
|
||||
blue: 400
|
||||
},
|
||||
eras: ["WW2", "Early Cold War", "Late Cold War", "Modern"]
|
||||
}
|
||||
|
||||
var auth = req.get("Authorization");
|
||||
if (auth) {
|
||||
var username = Buffer.from(auth.replace("Basic ", ""), 'base64').toString('binary').split(":")[0];
|
||||
switch (username) {
|
||||
case "admin":
|
||||
ret.mission.commandModeOptions.commandMode = "Game master";
|
||||
break
|
||||
case "blue":
|
||||
ret.mission.commandModeOptions.commandMode = "Blue commander";
|
||||
break;
|
||||
case "red":
|
||||
ret.mission.commandModeOptions.commandMode = "Red commander";
|
||||
break;
|
||||
}
|
||||
}
|
||||
res.send(JSON.stringify(ret));
|
||||
}
|
||||
|
||||
command(req, res) {
|
||||
var ret = {commandExecuted: Math.random() > 0.5};
|
||||
res.send(JSON.stringify(ret));
|
||||
}
|
||||
|
||||
put(req, res) {
|
||||
var ret = {commandHash: Math.random().toString(36).slice(2, 19)}
|
||||
res.send(JSON.stringify(ret));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = DemoDataGenerator;
|
||||
8140
client/package-lock.json
generated
8140
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,59 +0,0 @@
|
||||
{
|
||||
"name": "DCSOlympus",
|
||||
"node-main": "./bin/www",
|
||||
"main": "http://localhost:3000",
|
||||
"version": "v0.4.6-alpha",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "browserify .\\src\\index.ts --debug -o .\\public\\javascripts\\bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ] && copy.bat",
|
||||
"emit-declarations": "tsc --project tsconfig.json --declaration --emitDeclarationOnly --outfile ./@types/olympus/index.d.ts",
|
||||
"copy": "copy.bat",
|
||||
"start": "node ./bin/www",
|
||||
"debug": "npm run copy & concurrently --kill-others \"npm run watch\" \"nodemon --ignore ./public/databases/ ./bin/www\"",
|
||||
"watch": "watchify .\\src\\index.ts --debug -o .\\public\\javascripts\\bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ]"
|
||||
},
|
||||
"dependencies": {
|
||||
"@turf/turf": "^6.5.0",
|
||||
"body-parser": "^1.20.2",
|
||||
"cookie-parser": "~1.4.4",
|
||||
"debug": "~2.6.9",
|
||||
"ejs": "^3.1.8",
|
||||
"express": "~4.16.1",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
"leaflet-gesture-handling": "^1.2.2",
|
||||
"morgan": "~1.9.1",
|
||||
"save": "^2.9.0",
|
||||
"srtm-elevation": "^2.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.21.4",
|
||||
"@tanem/svg-injector": "^10.1.55",
|
||||
"@types/formatcoords": "^1.1.0",
|
||||
"@types/geojson": "^7946.0.10",
|
||||
"@types/leaflet": "^1.9.0",
|
||||
"@types/node": "^18.16.1",
|
||||
"@types/sortablejs": "^1.15.0",
|
||||
"@types/svg-injector": "^0.0.29",
|
||||
"babelify": "^10.0.0",
|
||||
"browserify": "^17.0.0",
|
||||
"concurrently": "^7.6.0",
|
||||
"cp": "^0.2.0",
|
||||
"esmify": "^2.1.1",
|
||||
"formatcoords": "^1.1.3",
|
||||
"geodesy": "^1.1.2",
|
||||
"leaflet": "^1.9.3",
|
||||
"leaflet-control-mini-map": "^0.4.0",
|
||||
"leaflet-path-drag": "*",
|
||||
"leaflet.nauticscale": "^1.1.0",
|
||||
"nodemon": "^2.0.20",
|
||||
"requirejs": "^2.3.6",
|
||||
"sortablejs": "^1.15.0",
|
||||
"tsify": "^5.0.4",
|
||||
"tslib": "latest",
|
||||
"typedoc": "^0.24.8",
|
||||
"typedoc-umlclass": "^0.7.1",
|
||||
"typescript": "^4.9.4",
|
||||
"usng.js": "^0.4.5",
|
||||
"watchify": "^4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
mkdir .\\..\\..\\public\\plugins\\controltipsplugin
|
||||
|
||||
copy .\\index.js .\\..\\..\\public\\plugins\\controltipsplugin\\index.js
|
||||
copy .\\plugin.json .\\..\\..\\public\\plugins\\controltipsplugin\\plugin.json
|
||||
copy .\\style.css .\\..\\..\\public\\plugins\\controltipsplugin\\style.css
|
||||
@@ -1,384 +0,0 @@
|
||||
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
||||
"use strict";
|
||||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
||||
if (kind === "m") throw new TypeError("Private method is not writable");
|
||||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
||||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
||||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
||||
};
|
||||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
||||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
||||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
||||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
||||
};
|
||||
var _ControlTipsPlugin_instances, _ControlTipsPlugin_element, _ControlTipsPlugin_app, _ControlTipsPlugin_shortcutManager, _ControlTipsPlugin_cursorIsHoveringOverUnit, _ControlTipsPlugin_cursorIsHoveringOverAirbase, _ControlTipsPlugin_mouseoverElement, _ControlTipsPlugin_updateTips;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ControlTipsPlugin = void 0;
|
||||
const SHOW_CONTROL_TIPS = "Show control tips";
|
||||
class ControlTipsPlugin {
|
||||
constructor() {
|
||||
_ControlTipsPlugin_instances.add(this);
|
||||
_ControlTipsPlugin_element.set(this, void 0);
|
||||
_ControlTipsPlugin_app.set(this, void 0);
|
||||
_ControlTipsPlugin_shortcutManager.set(this, void 0);
|
||||
_ControlTipsPlugin_cursorIsHoveringOverUnit.set(this, false);
|
||||
_ControlTipsPlugin_cursorIsHoveringOverAirbase.set(this, false);
|
||||
_ControlTipsPlugin_mouseoverElement.set(this, void 0);
|
||||
__classPrivateFieldSet(this, _ControlTipsPlugin_element, document.createElement("div"), "f");
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_element, "f").id = "control-tips-panel";
|
||||
document.body.appendChild(__classPrivateFieldGet(this, _ControlTipsPlugin_element, "f"));
|
||||
}
|
||||
getName() {
|
||||
return "Control Tips Plugin";
|
||||
}
|
||||
initialize(app) {
|
||||
__classPrivateFieldSet(this, _ControlTipsPlugin_app, app, "f");
|
||||
__classPrivateFieldSet(this, _ControlTipsPlugin_shortcutManager, __classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getShortcutManager(), "f");
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_shortcutManager, "f").onKeyDown(() => {
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
|
||||
});
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_shortcutManager, "f").onKeyUp(() => {
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
|
||||
});
|
||||
document.addEventListener("airbaseMouseover", (ev) => {
|
||||
__classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverAirbase, true, "f");
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
|
||||
});
|
||||
document.addEventListener("airbaseMouseout", (ev) => {
|
||||
__classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverAirbase, false, "f");
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
|
||||
});
|
||||
document.addEventListener("unitDeselection", (ev) => {
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
|
||||
});
|
||||
document.addEventListener("unitMouseover", (ev) => {
|
||||
__classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverUnit, true, "f");
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
|
||||
});
|
||||
document.addEventListener("unitMouseout", (ev) => {
|
||||
__classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverUnit, false, "f");
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
|
||||
});
|
||||
document.addEventListener("unitsSelection", (ev) => {
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
|
||||
});
|
||||
document.addEventListener("mapVisibilityOptionsChanged", () => {
|
||||
this.toggle(!__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getMap().getVisibilityOptions()[SHOW_CONTROL_TIPS]);
|
||||
});
|
||||
document.addEventListener("mouseover", (ev) => {
|
||||
if (ev.target instanceof HTMLElement) {
|
||||
__classPrivateFieldSet(this, _ControlTipsPlugin_mouseoverElement, ev.target, "f");
|
||||
}
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
|
||||
});
|
||||
document.addEventListener("mouseup", (ev) => {
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
|
||||
});
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
|
||||
__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getMap().addVisibilityOption(SHOW_CONTROL_TIPS, true);
|
||||
return true;
|
||||
}
|
||||
getElement() {
|
||||
return __classPrivateFieldGet(this, _ControlTipsPlugin_element, "f");
|
||||
}
|
||||
toggle(bool) {
|
||||
this.getElement().classList.toggle("hide", bool);
|
||||
}
|
||||
}
|
||||
exports.ControlTipsPlugin = ControlTipsPlugin;
|
||||
_ControlTipsPlugin_element = new WeakMap(), _ControlTipsPlugin_app = new WeakMap(), _ControlTipsPlugin_shortcutManager = new WeakMap(), _ControlTipsPlugin_cursorIsHoveringOverUnit = new WeakMap(), _ControlTipsPlugin_cursorIsHoveringOverAirbase = new WeakMap(), _ControlTipsPlugin_mouseoverElement = new WeakMap(), _ControlTipsPlugin_instances = new WeakSet(), _ControlTipsPlugin_updateTips = function _ControlTipsPlugin_updateTips() {
|
||||
const combos = [
|
||||
{
|
||||
"keys": [],
|
||||
"tips": [
|
||||
{
|
||||
"key": `SHIFT`,
|
||||
"action": `Box select`,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false,
|
||||
"showIfUnitSelected": false
|
||||
},
|
||||
{
|
||||
"key": `Mouse1`,
|
||||
"action": `Deselect`,
|
||||
"showIfUnitSelected": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse1+drag`,
|
||||
"action": `Move map`,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false,
|
||||
"showIfUnitSelected": false
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Spawn menu`,
|
||||
"showIfUnitSelected": false,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Quick options`,
|
||||
"showIfUnitSelected": false,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Airbase menu`,
|
||||
"showIfUnitSelected": false,
|
||||
"showIfHoveringOverAirbase": true,
|
||||
"showIfHoveringOverUnit": false
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Set first waypoint`,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfUnitSelected": true,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse2 (hold)`,
|
||||
"action": `Interact (ground)`,
|
||||
"showIfUnitSelected": true,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": `Shift`,
|
||||
"action": "<em> in formation...</em>",
|
||||
"showIfUnitSelected": true,
|
||||
"minSelectedUnits": 2
|
||||
},
|
||||
{
|
||||
"key": "CTRL",
|
||||
"action": "<em> ... more</em>",
|
||||
"showIfUnitSelected": true,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": "CTRL",
|
||||
"action": " Pin tool",
|
||||
"showIfUnitSelected": false,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": "CTRL+Mouse2",
|
||||
"action": " Airbase menu",
|
||||
"showIfUnitSelected": true,
|
||||
"showIfHoveringOverAirbase": true,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse1`,
|
||||
"action": "Toggle Blue/Red",
|
||||
"mouseoverSelector": "#coalition-switch .ol-switch-fill"
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": "Set Neutral",
|
||||
"mouseoverSelector": "#coalition-switch .ol-switch-fill"
|
||||
},
|
||||
{
|
||||
"key": `Mouse1`,
|
||||
"action": "Toggle time display",
|
||||
"mouseoverSelector": "#connection-status-panel[data-is-connected] #connection-status-message abbr"
|
||||
},
|
||||
{
|
||||
"key": `Mouse1 or Z`,
|
||||
"action": "Change location system",
|
||||
"mouseoverSelector": "#coordinates-tool, #coordinates-tool *"
|
||||
},
|
||||
{
|
||||
"key": `Comma`,
|
||||
"action": "Decrease precision",
|
||||
"mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *`
|
||||
},
|
||||
{
|
||||
"key": `Period`,
|
||||
"action": "Increase precision",
|
||||
"mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *`
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"keys": ["ControlLeft"],
|
||||
"tips": [
|
||||
{
|
||||
"key": `Mouse1`,
|
||||
"action": "Toggle pin",
|
||||
"showIfUnitSelected": false,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false
|
||||
},
|
||||
{
|
||||
"key": `Mouse1`,
|
||||
"action": "Toggle selection",
|
||||
"showIfUnitSelected": true,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Add waypoint`,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false,
|
||||
"showIfUnitSelected": true,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Interact (airbase)`,
|
||||
"showIfHoveringOverAirbase": true,
|
||||
"showIfUnitSelected": true,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Interact (unit)`,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": true,
|
||||
"showIfUnitSelected": true,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": `Shift`,
|
||||
"action": "<em> in formation...</em>",
|
||||
"showIfUnitSelected": true,
|
||||
"minSelectedUnits": 2
|
||||
},
|
||||
{
|
||||
"key": `[Num 1-9]`,
|
||||
"action": "Set hotgroup",
|
||||
"showIfUnitSelected": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"keys": ["ShiftLeft"],
|
||||
"tips": [
|
||||
{
|
||||
"key": `Mouse1+drag`,
|
||||
"action": "Box select",
|
||||
"showIfUnitSelected": false
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": "Set first formation waypoint",
|
||||
"showIfUnitSelected": true,
|
||||
"minSelectedUnits": 2
|
||||
},
|
||||
{
|
||||
"key": `[Num 1-9]`,
|
||||
"action": "Add to hotgroup",
|
||||
"showIfUnitSelected": true
|
||||
},
|
||||
{
|
||||
"key": "CTRL",
|
||||
"action": "<em> ... more</em>",
|
||||
"minSelectedUnits": 2,
|
||||
"showIfUnitSelected": true,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"unitsMustBeControlled": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"keys": ["ControlLeft", "ShiftLeft"],
|
||||
"tips": [
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": "Add formation waypoint",
|
||||
"showIfUnitSelected": true,
|
||||
"minSelectedUnits": 2,
|
||||
"unitsMustBeControlled": true
|
||||
}, {
|
||||
"key": `[Num 1-9]`,
|
||||
"action": "Add hotgroup to selection",
|
||||
"callback": (tip) => {
|
||||
return (Object.values(__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getUnitsManager().getUnits()).some((unit) => {
|
||||
return unit.getHotgroup();
|
||||
}));
|
||||
},
|
||||
"showIfUnitSelected": true,
|
||||
"minSelectedUnits": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
const currentCombo = combos.find((combo) => __classPrivateFieldGet(this, _ControlTipsPlugin_shortcutManager, "f").keyComboMatches(combo.keys)) || combos[0];
|
||||
const element = this.getElement();
|
||||
element.innerHTML = "";
|
||||
let numSelectedUnits = 0;
|
||||
let numSelectedControlledUnits = 0;
|
||||
let unitSelectionContainsControlled = false;
|
||||
if (__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getUnitsManager()) {
|
||||
let selectedUnits = Object.values(__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getUnitsManager().getSelectedUnits());
|
||||
numSelectedUnits = selectedUnits.length;
|
||||
numSelectedControlledUnits = selectedUnits.filter((unit) => unit.getControlled()).length;
|
||||
unitSelectionContainsControlled = numSelectedControlledUnits > 0;
|
||||
}
|
||||
const tipsIncludesActiveMouseover = (currentCombo.tips.some((tip) => {
|
||||
if (!tip.mouseoverSelector) {
|
||||
return false;
|
||||
}
|
||||
if (__classPrivateFieldGet(this, _ControlTipsPlugin_mouseoverElement, "f") instanceof HTMLElement === false) {
|
||||
return false;
|
||||
}
|
||||
if (!__classPrivateFieldGet(this, _ControlTipsPlugin_mouseoverElement, "f").matches(tip.mouseoverSelector)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
currentCombo.tips.filter((tip) => {
|
||||
if (numSelectedUnits > 0) {
|
||||
if (tip.showIfUnitSelected === false) {
|
||||
return false;
|
||||
}
|
||||
if (tip.unitsMustBeControlled === true && unitSelectionContainsControlled === false) {
|
||||
return false;
|
||||
}
|
||||
if (typeof tip.minSelectedUnits === "number" && numSelectedControlledUnits < tip.minSelectedUnits) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (numSelectedUnits === 0 && tip.showIfUnitSelected === true) {
|
||||
return false;
|
||||
}
|
||||
if (typeof tip.showIfHoveringOverAirbase === "boolean") {
|
||||
if (tip.showIfHoveringOverAirbase !== __classPrivateFieldGet(this, _ControlTipsPlugin_cursorIsHoveringOverAirbase, "f")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (typeof tip.showIfHoveringOverUnit === "boolean") {
|
||||
if (tip.showIfHoveringOverUnit !== __classPrivateFieldGet(this, _ControlTipsPlugin_cursorIsHoveringOverUnit, "f")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (tipsIncludesActiveMouseover && (typeof tip.mouseoverSelector !== "string" || !__classPrivateFieldGet(this, _ControlTipsPlugin_mouseoverElement, "f").matches(tip.mouseoverSelector))) {
|
||||
return false;
|
||||
}
|
||||
if (!tipsIncludesActiveMouseover && typeof tip.mouseoverSelector === "string") {
|
||||
return false;
|
||||
}
|
||||
if (typeof tip.callback === "function" && !tip.callback(tip)) {
|
||||
return false;
|
||||
}
|
||||
element.innerHTML += `<div><span class="key">${tip.key}</span><span class="action">${tip.action}</span></div>`;
|
||||
});
|
||||
};
|
||||
|
||||
},{}],2:[function(require,module,exports){
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const controltipsplugin_1 = require("./controltipsplugin");
|
||||
globalThis.getOlympusPlugin = () => {
|
||||
return new controltipsplugin_1.ControlTipsPlugin();
|
||||
};
|
||||
|
||||
},{"./controltipsplugin":1}]},{},[2]);
|
||||
162
client/plugins/controltips/package-lock.json
generated
162
client/plugins/controltips/package-lock.json
generated
@@ -1,162 +0,0 @@
|
||||
{
|
||||
"name": "ControlTipsPlugin",
|
||||
"version": "v0.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"any-promise": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
||||
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
|
||||
},
|
||||
"convert-source-map": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
|
||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||
},
|
||||
"error-ex": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
||||
"requires": {
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
|
||||
},
|
||||
"is-utf8": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
|
||||
"integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q=="
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
|
||||
"integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==",
|
||||
"requires": {
|
||||
"error-ex": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"strip-bom": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
|
||||
"integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==",
|
||||
"requires": {
|
||||
"is-utf8": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="
|
||||
},
|
||||
"through2": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
|
||||
"integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
|
||||
"requires": {
|
||||
"readable-stream": "~2.3.6",
|
||||
"xtend": "~4.0.1"
|
||||
}
|
||||
},
|
||||
"tsconfig": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-5.0.3.tgz",
|
||||
"integrity": "sha512-Cq65A3kVp6BbsUgg9DRHafaGmbMb9EhAc7fjWvudNWKjkbWrt43FnrtZt6awshH1R0ocfF2Z0uxock3lVqEgOg==",
|
||||
"requires": {
|
||||
"any-promise": "^1.3.0",
|
||||
"parse-json": "^2.2.0",
|
||||
"strip-bom": "^2.0.0",
|
||||
"strip-json-comments": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"tsify": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/tsify/-/tsify-5.0.4.tgz",
|
||||
"integrity": "sha512-XAZtQ5OMPsJFclkZ9xMZWkSNyMhMxEPsz3D2zu79yoKorH9j/DT4xCloJeXk5+cDhosEibu4bseMVjyPOAyLJA==",
|
||||
"requires": {
|
||||
"convert-source-map": "^1.1.0",
|
||||
"fs.realpath": "^1.0.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"semver": "^6.1.0",
|
||||
"through2": "^2.0.0",
|
||||
"tsconfig": "^5.0.3"
|
||||
}
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "ControlTipsPlugin",
|
||||
"version": "v0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "browserify ./src/index.ts -p [ tsify --noImplicitAny] > index.js && copy.bat"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"name": "Control Tip Plugin",
|
||||
"version": "0.0.1",
|
||||
"description": "This plugin shows useful control tips on the right side of the screen. The tips change dynamically depending on what the user does",
|
||||
"author": "Peekaboo"
|
||||
}
|
||||
@@ -1,403 +0,0 @@
|
||||
import { OlympusPlugin } from "interfaces";
|
||||
import { OlympusApp } from "olympusapp";
|
||||
import { Unit } from "unit/unit";
|
||||
|
||||
|
||||
const SHOW_CONTROL_TIPS = "Show control tips"
|
||||
|
||||
export class ControlTipsPlugin implements OlympusPlugin {
|
||||
#element: HTMLElement;
|
||||
#app: any;
|
||||
#shortcutManager: any;
|
||||
#cursorIsHoveringOverUnit: boolean = false;
|
||||
#cursorIsHoveringOverAirbase: boolean = false;
|
||||
#mouseoverElement!: HTMLElement;
|
||||
|
||||
constructor() {
|
||||
this.#element = document.createElement("div");
|
||||
this.#element.id = "control-tips-panel";
|
||||
document.body.appendChild(this.#element);
|
||||
}
|
||||
|
||||
getName() {
|
||||
return "Control Tips Plugin"
|
||||
}
|
||||
|
||||
initialize(app: any) {
|
||||
this.#app = app;
|
||||
|
||||
this.#shortcutManager = this.#app.getShortcutManager();
|
||||
|
||||
this.#shortcutManager.onKeyDown(() => {
|
||||
this.#updateTips()
|
||||
});
|
||||
|
||||
this.#shortcutManager.onKeyUp(() => {
|
||||
this.#updateTips()
|
||||
});
|
||||
|
||||
document.addEventListener("airbaseMouseover", (ev: CustomEventInit) => {
|
||||
this.#cursorIsHoveringOverAirbase = true;
|
||||
this.#updateTips();
|
||||
});
|
||||
|
||||
document.addEventListener("airbaseMouseout", (ev: CustomEventInit) => {
|
||||
this.#cursorIsHoveringOverAirbase = false;
|
||||
this.#updateTips();
|
||||
});
|
||||
|
||||
document.addEventListener("unitDeselection", (ev: CustomEventInit ) => {
|
||||
this.#updateTips();
|
||||
});
|
||||
|
||||
document.addEventListener("unitMouseover", (ev: CustomEventInit) => {
|
||||
this.#cursorIsHoveringOverUnit = true;
|
||||
this.#updateTips();
|
||||
});
|
||||
|
||||
document.addEventListener("unitMouseout", (ev: CustomEventInit) => {
|
||||
this.#cursorIsHoveringOverUnit = false;
|
||||
this.#updateTips();
|
||||
});
|
||||
|
||||
document.addEventListener("unitsSelection", (ev: CustomEventInit ) => {
|
||||
this.#updateTips();
|
||||
});
|
||||
|
||||
document.addEventListener("mapVisibilityOptionsChanged", () => {
|
||||
this.toggle( !this.#app.getMap().getVisibilityOptions()[SHOW_CONTROL_TIPS] );
|
||||
});
|
||||
|
||||
document.addEventListener( "mouseover", ( ev: MouseEvent ) => {
|
||||
if ( ev.target instanceof HTMLElement ) {
|
||||
this.#mouseoverElement = <HTMLElement>ev.target;
|
||||
}
|
||||
this.#updateTips();
|
||||
});
|
||||
|
||||
document.addEventListener( "mouseup", ( ev: MouseEvent ) => {
|
||||
this.#updateTips();
|
||||
});
|
||||
|
||||
this.#updateTips();
|
||||
|
||||
this.#app.getMap().addVisibilityOption(SHOW_CONTROL_TIPS, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
getElement() {
|
||||
return this.#element;
|
||||
}
|
||||
|
||||
toggle(bool?: boolean) {
|
||||
this.getElement().classList.toggle("hide", bool);
|
||||
}
|
||||
|
||||
#updateTips() {
|
||||
const combos: Array<object> = [
|
||||
{
|
||||
"keys": [],
|
||||
"tips": [
|
||||
{
|
||||
"key": `SHIFT`,
|
||||
"action": `Box select`,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false,
|
||||
"showIfUnitSelected": false
|
||||
},
|
||||
{
|
||||
"key": `Mouse1`,
|
||||
"action": `Deselect`,
|
||||
"showIfUnitSelected": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse1+drag`,
|
||||
"action": `Move map`,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false,
|
||||
"showIfUnitSelected": false
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Spawn menu`,
|
||||
"showIfUnitSelected": false,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Quick options`,
|
||||
"showIfUnitSelected": false,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Airbase menu`,
|
||||
"showIfUnitSelected": false,
|
||||
"showIfHoveringOverAirbase": true,
|
||||
"showIfHoveringOverUnit": false
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Set first waypoint`,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfUnitSelected": true,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse2 (hold)`,
|
||||
"action": `Interact (ground)`,
|
||||
"showIfUnitSelected": true,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": `Shift`,
|
||||
"action": "<em> in formation...</em>",
|
||||
"showIfUnitSelected": true,
|
||||
"minSelectedUnits": 2
|
||||
},
|
||||
{
|
||||
"key": "CTRL",
|
||||
"action": "<em> ... more</em>",
|
||||
"showIfUnitSelected": true,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": "CTRL",
|
||||
"action": " Pin tool",
|
||||
"showIfUnitSelected": false,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": "CTRL+Mouse2",
|
||||
"action": " Airbase menu",
|
||||
"showIfUnitSelected": true,
|
||||
"showIfHoveringOverAirbase": true,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse1`,
|
||||
"action": "Toggle Blue/Red",
|
||||
"mouseoverSelector": "#coalition-switch .ol-switch-fill"
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": "Set Neutral",
|
||||
"mouseoverSelector": "#coalition-switch .ol-switch-fill"
|
||||
},
|
||||
{
|
||||
"key": `Mouse1`,
|
||||
"action": "Toggle time display",
|
||||
"mouseoverSelector": "#connection-status-panel[data-is-connected] #connection-status-message abbr"
|
||||
},
|
||||
{
|
||||
"key": `Mouse1 or Z`,
|
||||
"action": "Change location system",
|
||||
"mouseoverSelector": "#coordinates-tool, #coordinates-tool *"
|
||||
},
|
||||
{
|
||||
"key": `Comma`,
|
||||
"action": "Decrease precision",
|
||||
"mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *`
|
||||
},
|
||||
{
|
||||
"key": `Period`,
|
||||
"action": "Increase precision",
|
||||
"mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *`
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"keys": ["ControlLeft"],
|
||||
"tips": [
|
||||
{
|
||||
"key": `Mouse1`,
|
||||
"action": "Toggle pin",
|
||||
"showIfUnitSelected": false,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false
|
||||
},
|
||||
{
|
||||
"key": `Mouse1`,
|
||||
"action": "Toggle selection",
|
||||
"showIfUnitSelected": true,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Add waypoint`,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": false,
|
||||
"showIfUnitSelected": true,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Interact (airbase)`,
|
||||
"showIfHoveringOverAirbase": true,
|
||||
"showIfUnitSelected": true,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": `Interact (unit)`,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"showIfHoveringOverUnit": true,
|
||||
"showIfUnitSelected": true,
|
||||
"unitsMustBeControlled": true
|
||||
},
|
||||
{
|
||||
"key": `Shift`,
|
||||
"action": "<em> in formation...</em>",
|
||||
"showIfUnitSelected": true,
|
||||
"minSelectedUnits": 2
|
||||
},
|
||||
{
|
||||
"key": `[Num 1-9]`,
|
||||
"action": "Set hotgroup",
|
||||
"showIfUnitSelected": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"keys": ["ShiftLeft"],
|
||||
"tips": [
|
||||
{
|
||||
"key": `Mouse1+drag`,
|
||||
"action": "Box select",
|
||||
"showIfUnitSelected": false
|
||||
},
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": "Set first formation waypoint",
|
||||
"showIfUnitSelected": true,
|
||||
"minSelectedUnits": 2
|
||||
},
|
||||
{
|
||||
"key": `[Num 1-9]`,
|
||||
"action": "Add to hotgroup",
|
||||
"showIfUnitSelected": true
|
||||
},
|
||||
{
|
||||
"key": "CTRL",
|
||||
"action": "<em> ... more</em>",
|
||||
"minSelectedUnits": 2,
|
||||
"showIfUnitSelected": true,
|
||||
"showIfHoveringOverAirbase": false,
|
||||
"unitsMustBeControlled": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"keys": ["ControlLeft", "ShiftLeft"],
|
||||
"tips": [
|
||||
{
|
||||
"key": `Mouse2`,
|
||||
"action": "Add formation waypoint",
|
||||
"showIfUnitSelected": true,
|
||||
"minSelectedUnits": 2,
|
||||
"unitsMustBeControlled": true
|
||||
}, {
|
||||
"key": `[Num 1-9]`,
|
||||
"action": "Add hotgroup to selection",
|
||||
"callback": ( tip:object ) => {
|
||||
return (Object.values<Unit>( this.#app.getUnitsManager().getUnits() ).some( ( unit:Unit ) => {
|
||||
return unit.getAlive() && unit.getControlled() && unit.getHotgroup();
|
||||
}));
|
||||
},
|
||||
"showIfUnitSelected": true,
|
||||
"minSelectedUnits": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const currentCombo: any = combos.find((combo: any) => this.#shortcutManager.keyComboMatches(combo.keys)) || combos[0];
|
||||
|
||||
const element = this.getElement();
|
||||
|
||||
element.innerHTML = "";
|
||||
|
||||
let numSelectedUnits = 0;
|
||||
let numSelectedControlledUnits = 0;
|
||||
let unitSelectionContainsControlled = false;
|
||||
|
||||
if (this.#app.getUnitsManager()) {
|
||||
let selectedUnits = Object.values(this.#app.getUnitsManager().getSelectedUnits());
|
||||
numSelectedUnits = selectedUnits.length;
|
||||
numSelectedControlledUnits = selectedUnits.filter((unit: any) => unit.getControlled()).length;
|
||||
unitSelectionContainsControlled = numSelectedControlledUnits > 0;
|
||||
}
|
||||
|
||||
const tipsIncludesActiveMouseover = ( currentCombo.tips.some( ( tip:any ) => {
|
||||
if ( !tip.mouseoverSelector ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( this.#mouseoverElement instanceof HTMLElement === false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !this.#mouseoverElement.matches( tip.mouseoverSelector ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}));
|
||||
|
||||
currentCombo.tips.filter((tip: any) => {
|
||||
if (numSelectedUnits > 0) {
|
||||
if (tip.showIfUnitSelected === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tip.unitsMustBeControlled === true && unitSelectionContainsControlled === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( typeof tip.minSelectedUnits === "number" && numSelectedControlledUnits < tip.minSelectedUnits ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (numSelectedUnits === 0 && tip.showIfUnitSelected === true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof tip.showIfHoveringOverAirbase === "boolean") {
|
||||
if (tip.showIfHoveringOverAirbase !== this.#cursorIsHoveringOverAirbase) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof tip.showIfHoveringOverUnit === "boolean") {
|
||||
if (tip.showIfHoveringOverUnit !== this.#cursorIsHoveringOverUnit) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( tipsIncludesActiveMouseover && ( typeof tip.mouseoverSelector !== "string" || !this.#mouseoverElement.matches( tip.mouseoverSelector ) ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !tipsIncludesActiveMouseover && typeof tip.mouseoverSelector === "string" ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( typeof tip.callback === "function" && !tip.callback( tip ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
element.innerHTML += `<div><span class="key">${tip.key}</span><span class="action">${tip.action}</span></div>`;
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { ControlTipsPlugin } from "./controltipsplugin";
|
||||
|
||||
globalThis.getOlympusPlugin = () => {
|
||||
return new ControlTipsPlugin();
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#control-tips-panel {
|
||||
align-self: center;
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
font-size: 13px;
|
||||
justify-self: flex-end;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
row-gap: 20px;
|
||||
text-align: right;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
#control-tips-panel>* {
|
||||
align-items: center;
|
||||
align-self: end;
|
||||
background-color: var(--background-steel);
|
||||
border-radius: var(--border-radius-md);
|
||||
color: white;
|
||||
column-gap: 8px;
|
||||
display: flex;
|
||||
justify-items: right;
|
||||
opacity: .9;
|
||||
padding: 5px;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
#control-tips-panel>*>.key {
|
||||
background-color: var(--background-grey);
|
||||
border-radius: var(--border-radius-sm);
|
||||
color: white;
|
||||
padding: 1px 4px;
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
/* Language and Environment */
|
||||
"target": "ES2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
/* Modules */
|
||||
"module": "commonjs", /* Specify what module code is generated. */
|
||||
"rootDirs": ["./src", "../../@types"], /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"../../@types"
|
||||
], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
"types": [
|
||||
"olympus"
|
||||
], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
/* JavaScript Support */
|
||||
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
/* Type Checking */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
},
|
||||
"include": [
|
||||
"src/*.ts",
|
||||
"../../@types/olympus/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Attach to Chrome",
|
||||
"port": 9222,
|
||||
"urlFilter": "http://localhost:3000/*",
|
||||
"request": "attach",
|
||||
"type": "chrome",
|
||||
"webRoot": "${workspaceFolder}../../public/",
|
||||
"sourceMapPathOverrides": {
|
||||
"src/*": "src/*"
|
||||
},
|
||||
"preLaunchTask": "start"
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user