329 Commits

Author SHA1 Message Date
85706518fe Update to SHVDN nightly (#70) 2024-06-30 16:17:35 +08:00
49208371d1 Allow keyboard layout change in chat 2023-12-12 11:52:20 -03:00
761156a574 Avoid vehicle door break and repair loop 2023-11-27 10:24:35 -03:00
8bd6ea15a3 Remove global limits
world limits will be applied to all players instead
Fix explosions when remote and local vehicles exist at same position
Fix "floating corpses" issue when remote NPCs are killed
2023-11-20 11:32:18 -03:00
3c7f16f7a4 Add ped limit menu setting
Fix vehicle limit menu setting
Fix player blip disappearing after switching character
2023-11-12 10:50:37 -03:00
393a401860 Always sync vehicles with synced peds 2023-11-07 20:27:14 -03:00
4a54851c51 Update AssemblyInfo.cs 2023-10-23 10:36:57 -03:00
f0eefa575c Always sync player ped 2023-10-22 18:59:19 -03:00
3fc813b2d8 Fix bug disconnecting from server 2023-10-22 17:14:50 -03:00
fbff72ff14 Update LemonUI 2023-10-18 16:57:19 -03:00
4e52407591 Update nightly-build.yaml 2023-10-18 16:56:44 -03:00
4e6fde129d Add global limits 2023-10-18 10:41:34 -03:00
92e1a970a8 Show kill notification 2023-10-06 23:46:08 -03:00
d0eb0b7818 Bump version
Add kill message
2023-10-06 16:36:49 -03:00
14151d7b2c Add option to disable blip and nametag display 2023-08-14 14:08:30 -03:00
1f8d70a520 Fix player dying when switching characters in missions 2023-08-13 19:29:48 -03:00
2cb5baf5f7 Fix player dying when switching characters 2023-08-09 23:50:47 -03:00
9287aba0f9 Update README.md 2023-07-26 15:42:08 -03:00
99642fd40c Update SHVDN 2023-07-26 15:12:58 -03:00
2fbf06b504 Use Lidgren.Network release build 2023-07-24 10:40:33 -03:00
13b771ec9f Fix exception entering vehicle as passenger 2023-07-24 10:39:37 -03:00
3b987f59e0 Remove update menu 2023-07-14 09:43:00 -03:00
de96f29097 Don't delete peds in vehicle 2023-07-14 09:39:06 -03:00
6136cbfc14 Allow multiple servers on same address
with different ports
2023-07-14 09:38:02 -03:00
ed145aedd6 Update master server 2023-07-14 09:36:49 -03:00
3f3b5fd2d0 Closes #40 2022-09-30 23:40:14 +08:00
9173e9a99e Fix non-ambient peds get deleted 2022-09-30 23:27:37 +08:00
6e64c458df Merge branch 'dev-nightly' of https://github.com/RAGECOOP/RAGECOOP-V into dev-nightly 2022-09-09 11:24:02 +08:00
76f959abe9 Stuff 2022-09-09 11:23:46 +08:00
f2e85d66ab Update build-test.yaml 2022-09-09 11:15:27 +08:00
e30ef1f4bd Update actions 2022-09-08 20:09:52 -07:00
6e8f6e78f6 Add build test action 2022-09-08 20:05:26 -07:00
f28c83ccbd Merge pull request #38 from RAGECOOP/dev-nightly
Bump to 1.5.4
2022-09-07 22:44:48 -07:00
a83821b3d2 Version bump 2022-09-08 13:19:09 -07:00
3b5436064e Don't announce if already present in master server 2022-09-08 13:15:34 -07:00
c4b321324e Filter out white space for reload key parsing 2022-09-08 12:59:14 -07:00
ba8d525ddf Merge pull request #37 from RAGECOOP/dev-nightly
Rewrite packet system
2022-09-07 21:45:14 -07:00
884e2f39f0 Yet another code cleanup 2022-09-08 12:41:56 -07:00
76c529f1d1 Rewrote packet system to reduce heap allocation 2022-09-08 12:37:06 -07:00
df0064bd38 Update nightly-build.yaml 2022-09-07 21:01:22 -07:00
f1fc96bbd7 Fix weird projectile shooting 2022-09-07 11:08:25 +08:00
23e9326f5f Fix stuff, add listening address display and projectile shoot prediction 2022-09-07 09:52:40 +08:00
4621fb4987 Some code cleanup and formatting 2022-09-06 21:46:35 +08:00
6c82895fa7 code cleaned up 2022-09-05 13:02:09 +02:00
84b040766f Simplify GetBytesFromObject 2022-08-27 14:23:28 +08:00
f44558cd3b Add some client API 2022-08-27 14:17:10 +08:00
accdbbcbc6 blah 2022-08-27 13:53:03 +08:00
2d4107f35e Fix traffic 2022-08-27 12:40:47 +08:00
bac53fd769 Load scripts from main assembly only 2022-08-26 22:58:03 +08:00
8f63fee5b5 Delete temp directory 2022-08-25 22:34:54 +08:00
8d0ad0b600 Show runtime information 2022-08-25 22:32:01 +08:00
dc08c0c1f6 Added support for loading runtime-specific libraries 2022-08-25 21:51:09 +08:00
faaa856aa5 Instructional buttons for popup 2022-08-25 00:58:21 +08:00
eab64f9254 Check fixed data every 100 frames 2022-08-24 22:38:50 +08:00
6c936cb8f9 Show help in popup 2022-08-24 19:26:40 +08:00
83a37f8556 blah 2022-08-24 18:48:21 +08:00
bb4eacce26 Don't disable traffic if not on server 2022-08-24 18:47:59 +08:00
d5b71db5d4 💩 2022-08-23 23:21:35 +08:00
89ebd0305c Fix ped running not displayed 2022-08-23 18:10:52 +08:00
b209202292 Add option to show entity owner 2022-08-23 17:43:24 +08:00
f199241ed8 Time for a release 2022-08-23 16:29:43 +08:00
50229116a7 blah 2022-08-23 14:04:18 +08:00
f192caeae1 Add sdk 2022-08-23 14:03:33 +08:00
6005b2ba11 Add slipstreaming 2022-08-23 13:51:38 +08:00
6e213611cc Fix deluxo wing 2022-08-23 13:45:45 +08:00
347d65af62 Expose chat meesage API to client script 2022-08-23 13:34:12 +08:00
636ee3a33f Fix memory stream close on send 2022-08-23 13:22:14 +08:00
8ff08e0804 Add resource package support 2022-08-23 12:21:17 +08:00
6d7fe58719 Ped sync tweaks 2022-08-23 10:55:54 +08:00
c7e14ef191 Fix disable traffic not always work 2022-08-22 21:59:01 +08:00
39eb5ef80a Hmm... 2022-08-22 19:38:04 +08:00
d25c2539e0 Tweaks 2022-08-22 19:27:25 +08:00
eb31a33104 Fix vibration on stopped vehicle 2022-08-22 19:25:03 +08:00
8b3f8ffd9b Check ped weapon on full sync only 2022-08-22 19:13:52 +08:00
cca09c4178 Fixed ped weapon display after exiting vehicle 2022-08-22 19:08:09 +08:00
871bb7e64e ver 2022-08-22 17:57:43 +08:00
02da3ce8af Fix voice on P2P mode 2022-08-22 17:55:58 +08:00
711ba62fc2 Update installer 2022-08-22 17:30:15 +08:00
8f7d3135db Revert "Fix output path overlap"
This reverts commit 2af9482da9.
2022-08-22 17:27:35 +08:00
cb563a1bf8 Revert "Update nightly-build.yaml"
This reverts commit 6720636d48.
2022-08-22 17:27:29 +08:00
a84ab42a42 blah 2022-08-22 17:01:08 +08:00
b3e285f92f Wait ten minutes before updating 2022-08-22 16:59:00 +08:00
01433f0de6 Restore damage model for aircraft 2022-08-22 11:36:52 +08:00
c034cd8aa9 Fix traffic 2022-08-22 10:01:09 +08:00
363c2ccb00 Don't disable vehicle enter/exit key 2022-08-22 09:40:02 +08:00
7380c162be Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-08-22 09:34:52 +08:00
f1c7192029 Change kicking options 2022-08-22 09:33:54 +08:00
6720636d48 Update nightly-build.yaml 2022-08-22 00:46:46 +08:00
2af9482da9 Fix output path overlap 2022-08-22 00:36:43 +08:00
bf22c17bba Add AntiAsshole and host display 2022-08-22 00:23:46 +08:00
01492a0c55 Auto server update should work now 2022-08-21 19:56:59 +08:00
c17b234057 Update AssemblyInfo.cs 2022-08-21 19:41:25 +08:00
739577bbf1 Hmm... 2022-08-21 19:30:27 +08:00
2d2da624e4 Add automatic server update (need testing) 2022-08-21 19:13:12 +08:00
9e66762061 Add ZeroTier check to installer 2022-08-21 15:13:36 +08:00
84d578366a Fix installer 2022-08-21 14:28:37 +08:00
03bc3a7742 blah 2022-08-21 14:22:41 +08:00
5bfc7f836e Fix vehicle seat sync 2022-08-21 14:15:01 +08:00
54977c79f1 Fix unintended carjacking 2022-08-21 14:12:44 +08:00
0352bfa328 Add menyoo and directory check for installer 2022-08-21 13:42:28 +08:00
6fbc386b45 Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-08-21 12:37:47 +08:00
203e3b2528 Add Client.EntitiesCount 2022-08-21 12:37:37 +08:00
c9aa995224 Update README.md 2022-08-21 12:17:20 +08:00
c201b94897 Better vehicle rotation display 2022-08-20 22:36:48 +08:00
87f873d1a5 blah 2022-08-20 22:22:06 +08:00
6c355b109d Fix player blip (again) 2022-08-20 22:15:01 +08:00
2ef3012672 Fix installer not overwriting files 2022-08-20 17:27:05 +08:00
7229574ff4 Hmm 2022-08-20 17:17:49 +08:00
eff9fd50b1 Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-08-20 15:31:03 +08:00
e2cbf26360 Fix installer output 2022-08-20 15:30:54 +08:00
b0f448fd5f Fix insyaller output 2022-08-20 15:29:44 +08:00
721c4d3dee Add client installer 2022-08-20 15:20:25 +08:00
87dfc18d91 Smoother ped heading calibration 2022-08-20 12:33:55 +08:00
fa4fe2c10f Fix player blip 2022-08-20 11:32:35 +08:00
3a088ddbfc Fix blip duplication and name issue 2022-08-20 11:08:51 +08:00
52cc9b647c Vehicle duplication prevention 2022-08-19 22:31:13 +08:00
1aa23901d5 Update lidgren again 2022-08-19 22:10:01 +08:00
52584d5774 Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-08-19 21:43:34 +08:00
62bf15dede default LogLevel to 0 2022-08-19 21:43:23 +08:00
722ca16f57 Update README.md 2022-08-19 21:39:40 +08:00
3e61498366 Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-08-19 21:35:08 +08:00
1ff2fa5691 Update lidgren 2022-08-19 21:35:05 +08:00
5088973474 Update README.md 2022-08-19 21:29:24 +08:00
b63378f4d0 Update README.md 2022-08-19 21:28:44 +08:00
f234830c54 Fix stuff 2022-08-18 22:08:06 +08:00
5075289657 ? 2022-08-18 21:48:42 +08:00
c20118aac1 Vehicle cleanup 2022-08-18 20:44:39 +08:00
c4312faf4a blah 2022-08-18 18:59:38 +08:00
7566423889 Security tweaks 2022-08-18 17:45:08 +08:00
be13e0d102 Small projectile fix 2022-08-18 08:43:10 +08:00
490802862a Huh? 2022-08-18 08:26:41 +08:00
e369a50b89 Add vehicle parachute sync 2022-08-18 08:25:15 +08:00
13a6431248 Add rocket boost sync 2022-08-17 23:18:06 +08:00
cb73db7146 Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-08-17 22:56:27 +08:00
9dcd6bb363 Apply prediction on server entity update 2022-08-17 22:50:17 +08:00
842e1435f2 aargh..... 2022-08-17 01:54:14 +08:00
4d03f8e371 blahblahblah 2022-08-16 23:31:17 +08:00
e040d53cc2 blah 2022-08-16 23:18:34 +08:00
22bfa43ec5 Update version 2022-08-16 23:17:04 +08:00
7123bea8e5 Small fix 2022-08-16 22:23:32 +08:00
973f6873e4 Fix some control not being ignored on chat 2022-08-16 22:16:18 +08:00
efb759b9f9 blah 2022-08-16 20:07:25 +08:00
ad3ff96f61 This is it 2022-08-16 19:51:56 +08:00
e156b2195f Display ping (round-trip time) 2022-08-16 13:44:56 +08:00
73a99e033d Update DevTool 2022-08-15 22:43:32 +08:00
b44d722b5f Closes #24 2022-08-15 22:41:17 +08:00
307b6365f7 Closes #25 2022-08-15 22:38:31 +08:00
a49ee19d3d Closes #17 2022-08-15 22:36:43 +08:00
9c5c1da4c9 Add champion weapon, (closes #21) 2022-08-15 22:35:43 +08:00
0348296dc1 Add a bunch of vehicle weapons (closes #23) 2022-08-15 22:34:35 +08:00
adb9439226 Add BRUISER3, BRUTUS3, MONSTER5 weapon sync (closes #26) 2022-08-15 22:21:47 +08:00
ae10da874b Hmm... 2022-08-15 21:25:42 +08:00
cb91486848 Update SHVDN 2022-08-15 20:50:26 +08:00
3289c03fd2 Vehicle seat fix 2022-08-15 20:04:08 +08:00
d4ffb0c929 blah 2022-08-15 19:40:24 +08:00
3c089e2c47 Fix looking coordinate in first person 2022-08-15 19:39:36 +08:00
7a4e4182b5 Add drive-by weapon display
This still have some issues:
ped not aiming consistently
sometimes not working at all
doesn't work for throwable weapons
2022-08-15 18:25:43 +08:00
aa6c45b20d Voice tweaks 2022-08-15 16:13:53 +08:00
0943a7992f blah 2022-08-15 00:19:00 +02:00
d30e1f6bb3 Added mouth animation when speaking 2022-08-14 23:35:36 +02:00
0c71d4dbaa Assign Client.Player.Owner immediately 2022-08-15 00:12:07 +08:00
c78fbd89bc Update README.md 2022-08-14 19:10:45 +08:00
dc83cd5be9 Ped sync improvements 2022-08-14 19:06:51 +08:00
b5f6fc578d Projectile refactor 2022-08-14 17:08:43 +08:00
4acf964f0a Small ragdoll tweak 2022-08-14 13:56:10 +08:00
560f092304 Don't set heading when aiming 2022-08-14 13:21:13 +08:00
8305d9997a Better vehicle weapon handling and muzzle flash 2022-08-14 13:04:39 +08:00
d68941b3ac blah 2022-08-14 10:46:42 +08:00
67c4646198 Fix update not deleting old assemblies 2022-08-14 10:45:39 +08:00
a7dab1e0e1 Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-08-14 10:36:08 +08:00
2b8a3db6bf Retore traffic on disconnect 2022-08-14 10:35:59 +08:00
f9609afd8a Small update for voice chat 2022-08-14 02:26:59 +02:00
609fd90561 Small tweaks 2022-08-13 16:59:09 +08:00
a7d64d241d New vehicle seat sync and projectile fix 2022-08-13 16:14:18 +08:00
b436abf131 Some hint 2022-08-13 11:42:29 +08:00
c14221f1a3 Remove json attributes 2022-08-13 11:42:15 +08:00
abbc871d1a Small fix 2022-08-13 11:28:35 +08:00
edb8838455 Update libs 2022-08-13 11:05:03 +08:00
4cca75ee35 Merge pull request #32 from RAGECOOP/voice-chat
Add voice chat
2022-08-13 10:55:16 +08:00
669b457275 Don't send voice back 2022-08-13 10:54:39 +08:00
2ef0060037 Added ClearAll() for voice 2022-08-13 04:03:01 +02:00
55649f26ae Use ConcurrentDictionary for ServerEntities 2022-08-13 09:47:13 +08:00
6bb7d5d0fd Merge branch 'voice-chat' of https://github.com/RAGECOOP/RAGECOOP-V into voice-chat 2022-08-13 03:39:16 +02:00
8f5deaa33b More voice changes 2022-08-13 03:39:11 +02:00
91b0afb6ef Remove Acceleration 2022-08-13 09:31:09 +08:00
4dc3cc5c28 Fix voice and add Server.Forward() and Server.SendToAll() 2022-08-13 08:56:05 +08:00
f9a411833a small fix 2022-08-13 02:39:18 +02:00
d24d786fd3 Better packet reuse 2022-08-13 08:22:14 +08:00
edae7a075a blub 2022-08-13 02:19:40 +02:00
85b028e3e7 Added NAudio and first voice test 2022-08-13 00:52:34 +02:00
36de46a2ce Fixed warnings 2022-08-12 20:48:31 +02:00
6e5f72ee70 blah 2022-08-12 20:58:17 +08:00
8d450813e1 ZeroTier intergration 2022-08-12 20:40:50 +08:00
495e5dc6b0 Better server info handling 2022-08-12 18:10:56 +08:00
0bd1d2c2a7 Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-08-12 18:07:06 +08:00
339f817c7e ZeroTier helper 2022-08-12 18:02:43 +08:00
b583618e6c Merge pull request #31 from xEntenKoeniqx/main
Cleaned up (Client)
2022-08-11 21:27:18 +08:00
dc0fafbe9e Fixed failed build of github-actions 2022-08-11 15:22:36 +02:00
b9e22a880f Cleaned up (Client) 2022-08-11 14:59:09 +02:00
cb7f0290ec "Entities" cleaned up 2022-08-11 14:48:19 +02:00
d70c739208 Cleaned up 2022-08-11 14:29:18 +02:00
29202906e1 Fix stuff 2022-08-11 19:42:30 +08:00
1d3e53f734 Packet recycling 2022-08-11 18:25:01 +08:00
a26a799a9f Variables renaming 2022-08-11 16:29:29 +08:00
033d0a3f2e Move some stuff to core 2022-08-11 16:25:38 +08:00
95e302a698 Fix player disconnect 2022-08-11 15:38:19 +08:00
ff9e16bd5e Restore 2022-08-10 20:42:47 +08:00
01c668b159 blah 2022-08-08 18:07:22 +08:00
74e51c8070 Display remote blip 2022-08-08 17:47:09 +08:00
01524b1796 Move CurrentWeaponHash to full sync 2022-08-08 17:29:15 +08:00
83d79b0a17 Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-08-08 17:03:53 +08:00
c3d7c2b335 P2P connectivity 2022-08-08 17:03:41 +08:00
6b6125eb09 Update DownloadManager.cs 2022-08-08 10:19:48 +08:00
09bb121ffe blah 2022-08-06 12:33:05 +08:00
a50be5b869 Some stuff for the upcoming change 2022-08-06 12:32:04 +08:00
ca5ef8cf4c read packet with BinaryReader 2022-08-06 11:40:38 +08:00
4e33956acd Faster way to get client by username 2022-08-06 10:58:24 +08:00
9aae315e11 Simplify 2022-08-06 10:49:55 +08:00
742e7ea998 Packet refactor 2022-08-06 10:43:24 +08:00
69bd4c837c Delete dll when installing update 2022-08-05 17:24:51 +08:00
8c10d24842 Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-08-05 16:13:56 +08:00
6b681afdee Fix wheels 2022-08-05 16:13:40 +08:00
6186497999 blah 2022-08-04 19:18:22 +08:00
2571da594e Remove ResourceDomain 2022-08-04 19:13:39 +08:00
7c52cad569 Remove mscoree reference 2022-08-04 19:07:08 +08:00
303bc940f2 Move network info option to debug menu 2022-08-04 17:47:57 +08:00
eda903abde Sync every 30 ms 2022-08-04 17:38:28 +08:00
5d5bc668eb Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-08-04 17:14:11 +08:00
6e5653a168 Add latency simulation 2022-08-04 17:14:07 +08:00
87343b8255 Update README.md 2022-08-04 15:11:57 +08:00
cb21291983 Update README.md 2022-08-04 15:02:54 +08:00
8dd2241590 Update SyncedVehicle.cs 2022-08-04 08:33:18 +08:00
858fa81ea2 blah 2022-08-02 17:43:48 +08:00
8d6c70b75e Ok, this might look junky... 2022-08-02 17:43:18 +08:00
ffd6ce23c3 Add vehicle velocity prediction/acceleration 2022-08-02 16:42:40 +08:00
5a882d0bc8 Fix announce thread exception 2022-08-02 15:55:26 +08:00
cb1b4f4970 Update Program.cs 2022-08-01 23:20:22 +08:00
0de040548d Update FindScript() 2022-08-01 17:07:08 +08:00
40f4cf88c9 Back to velocity 2022-08-01 16:56:46 +08:00
275b39fb1e Add digits 2022-08-01 16:56:32 +08:00
fe5da3cf90 Check 2022-08-01 07:14:24 +08:00
4ed4e37604 Revert "Set client to null on disconnect"
This reverts commit 10552d119f.
2022-08-01 07:13:05 +08:00
10552d119f Set client to null on disconnect 2022-07-31 21:03:47 +08:00
d4e0e6f0ab Stricter username check 2022-07-31 20:56:51 +08:00
e2fce3cf9b Add some client API back 2022-07-31 20:47:04 +08:00
ad5ffc22ac blah 2022-07-30 21:55:57 +08:00
f980790bd7 blah 2022-07-30 21:54:45 +08:00
df8519961a blah 2022-07-30 21:53:42 +08:00
171a6be736 Revert "Squared"
This reverts commit 91035d9a3f.
2022-07-30 21:51:56 +08:00
91035d9a3f Squared 2022-07-30 21:37:15 +08:00
60e7d91409 Read ped speed 2022-07-30 15:45:27 +08:00
d05d1dac85 predict projectile positioin 2022-07-30 14:09:07 +08:00
8184b4d155 Predict projectile position 2022-07-30 13:43:54 +08:00
a0d5f9d2df stricter flip check 2022-07-30 12:50:04 +08:00
49f7f9e3e1 Calibrate position with force 2022-07-30 12:39:09 +08:00
911d8d5d64 Fix player PlayerInfoUpdate 2022-07-30 12:03:57 +08:00
3015ffe3ba Revert "flush"
This reverts commit 459cfccff5.
2022-07-30 11:44:14 +08:00
eb74bcf987 Update vehicle sync 2022-07-29 22:35:20 +08:00
b63898d8b9 Update vehicle sync 2022-07-29 22:26:19 +08:00
459cfccff5 flush 2022-07-29 21:53:26 +08:00
fdb66cba6d Fix chat message 2022-07-29 21:27:04 +08:00
93d705e402 Latency fix 2022-07-29 21:15:23 +08:00
c8bbdc69d0 Update latency detection method
Plus some server code refactoring
2022-07-29 20:35:39 +08:00
9b1587f334 Ignore API assemblies 2022-07-29 19:11:31 +08:00
3e67cc519e Ignore ready 2022-07-29 18:44:17 +08:00
eee6f614f1 Encrypt chat message 2022-07-29 18:17:45 +08:00
62e5bad6ac Resource interoperability 2022-07-29 17:44:02 +08:00
163f342d7a Change Sender to Client in EventArgs 2022-07-29 16:17:33 +08:00
370247eef2 Allow raising event when sending chat message wth API 2022-07-29 15:07:52 +08:00
f22ecb03f2 Fix welcome message 2022-07-29 14:51:52 +08:00
577857ab5a Hash password at server side 2022-07-29 14:51:17 +08:00
095d16a57e rix 2022-07-29 01:31:34 +08:00
862c2c0a71 Update Server.cs 2022-07-29 01:13:32 +08:00
d7e9ce8ff1 Don't invoke chat message if it's a command 2022-07-29 01:08:34 +08:00
e657a02f7a Update RageCoop.Client.csproj 2022-07-29 00:52:57 +08:00
182ff877f0 Update RageCoop.Client.csproj 2022-07-29 00:44:31 +08:00
521358abb5 Update README.md 2022-07-29 00:36:36 +08:00
b62aed5c5a Update RageCoop.Client.csproj 2022-07-29 00:30:33 +08:00
5c4e31806d cd /d 2022-07-28 18:00:13 +08:00
9f8d695d45 cd 2022-07-28 17:55:40 +08:00
e0e5f52d36 Send message back 2022-07-28 17:50:41 +08:00
9fda563438 Invoke constructor later 2022-07-28 17:46:34 +08:00
6d5bb285c9 Fix client copy 2022-07-28 17:03:29 +08:00
7ac405b8f9 Embed referenced assemblies 2022-07-28 15:46:15 +08:00
45d53bd38c Memory patch for weapon/radio slowdown/vignetting 2022-07-25 22:22:57 +08:00
cc52f66f5d Read quaternion and rotation directly from memory 2022-07-25 19:07:58 +08:00
e072c2aee8 Read entity position directly from memory 2022-07-23 23:45:20 +08:00
e52135c343 Allow sending chat message and command in console 2022-07-22 19:43:48 +08:00
cb53e8a664 Delay vehicle repair, fix vehicle if BodyHealth increased 2022-07-21 23:10:56 +08:00
44a8445b54 Delay vehicle repair 2022-07-21 22:42:29 +08:00
b0a197cd18 Back to old latency compensation 2022-07-21 09:53:07 +08:00
9ba52b332c Revert some vehicle sync change 2022-07-21 09:43:09 +08:00
ecfc77e57a Fix resource loading, add player died notification 2022-07-21 08:41:05 +08:00
2ba3e33d39 Don't follow position if velocity is greater than 3 2022-07-20 18:02:17 +08:00
71ecdbd5b9 code cleanup 2022-07-20 17:50:01 +08:00
bbe0b21aa4 Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-07-20 09:32:34 +08:00
51dd445a31 Fix resource duplication 2022-07-20 09:32:26 +08:00
264158957c Send response in same sequence channel 2022-07-20 09:11:07 +08:00
9d8963222c Update nightly-build.yaml 2022-07-20 07:50:03 +08:00
c1a35dbab3 Update nightly-build.yaml 2022-07-20 07:44:52 +08:00
d3931cc57c Update nightly-build.yaml 2022-07-20 07:37:26 +08:00
3795ced530 Update nightly-build.yaml 2022-07-20 07:35:02 +08:00
1372a5c33f Update release configuration 2022-07-20 07:34:53 +08:00
9527da9785 Add ability to share server file 2022-07-19 17:15:53 +08:00
3072db0e21 Only load top-level assembly 2022-07-18 17:27:06 +08:00
444e6d7ffa Unify resource file path 2022-07-18 17:24:31 +08:00
809c935d37 Fix entity fire 2022-07-17 20:12:25 +08:00
10bd54a785 remove testing code 2022-07-17 19:19:58 +08:00
ece899f2a1 Better vehicle movement sync 2022-07-17 19:19:23 +08:00
5d1a182e47 Better ragdoll sync (maybe) 2022-07-17 18:44:16 +08:00
228ab9e727 Ped movement change 2022-07-17 14:23:19 +08:00
2605aafc4f Vehicle flag fix 2022-07-17 12:22:11 +08:00
582bb2a7d7 Ahhh... 2022-07-17 12:00:26 +08:00
0a3dbb1f59 Merge vehicle sync packet, comment cleanup 2022-07-17 11:59:37 +08:00
5d1832fcef Merge ped packet
Back to old project family (for debugging)
Fix blip name
Delete newly spawned traffic if limit exceeded
2022-07-17 11:15:02 +08:00
30ed509c55 Prevent entity spawning from interfering Tick event 2022-07-15 13:45:43 +08:00
2ad91011c3 blah 2022-07-14 18:52:04 +08:00
e40d4695ea Add QueueAction overload 2022-07-14 18:50:15 +08:00
e4c03f8ccc Add in-game update feature 2022-07-14 17:59:41 +08:00
e10a0f5415 Add Logger property for resource script 2022-07-14 16:44:35 +08:00
2a29011015 Better projectile check 2022-07-14 15:28:03 +08:00
a37e8869ac Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-07-14 10:33:34 +08:00
038860f158 Update nametag drawing method 2022-07-14 10:33:24 +08:00
51e678d760 Update README.md 2022-07-13 20:13:29 +08:00
1e2a9992d8 Merge branch 'main' of https://github.com/RAGECOOP/RAGECOOP-V 2022-07-13 11:08:21 +08:00
5b7bb917ef add tls 2022-07-13 11:08:11 +08:00
72aff78718 Move logger 2022-07-13 11:08:04 +08:00
cdeef7279c coding style 2022-07-13 10:36:38 +08:00
9cb5c557c5 fix vehicle doors sync 2022-07-13 00:20:06 +08:00
143 changed files with 13379 additions and 7477 deletions

13
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,13 @@
# These are supported funding model platforms
github: [RAGECOOP] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
#patreon: # Replace with a single Patreon username
#open_collective: # Replace with a single Open Collective username
#ko_fi: # Replace with a single Ko-fi username
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
#liberapay: # Replace with a single Liberapay username
#issuehunt: # Replace with a single IssueHunt username
#otechie: # Replace with a single Otechie username
#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: ['https://www.buymeacoffee.com/xEntenKoeniqx', 'https://patreon.com/Sardelka']

48
.github/workflows/build-test.yaml vendored Normal file
View File

@ -0,0 +1,48 @@
name: Build test
on:
push:
branches:
- '*' # matches every branch that doesn't contain a '/'
- '*/*' # matches every branch containing a single '/'
- '**' # matches every branch
- '!main' # excludes main
- '!dev-nightly' # excludes nightly
pull_request:
branches: [ "main", "dev-nightly" ]
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
dotnet-version: ['6.0.x']
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: ${{ matrix.dotnet-version }}
- name: Restore dependencies
run: dotnet restore
- name: Restore nuget packages
run: nuget restore
- name: Build client and installer
run: dotnet build RageCoop.Client.Installer/RageCoop.Client.Installer.csproj --configuration Release -o bin/Release/Client/RageCoop
- name: Build server win-x64
run: dotnet build RageCoop.Server/RageCoop.Server.csproj -o bin/Release/Server
- name: Upload server
uses: actions/upload-artifact@v3
with:
name: RageCoop.Server
path: bin/Release/Server
- name: Upload Client
uses: actions/upload-artifact@v3
with:
name: RageCoop.Client
path: bin/Release/Client
- uses: actions/checkout@v2

View File

@ -2,9 +2,7 @@ name: Nightly-build
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
branches: [ "dev-nightly" ]
jobs:
build:
@ -22,35 +20,29 @@ jobs:
dotnet-version: ${{ matrix.dotnet-version }}
- name: Restore dependencies
run: dotnet restore
- name: Build client
run: dotnet publish RageCoop.Client/RageCoop.Client.csproj --no-restore --configuration Release -o RageCoop.Client/bin/RageCoop -f net48
- name: Restore nuget packages
run: nuget restore
- name: Build client and installer
run: dotnet build RageCoop.Client.Installer/RageCoop.Client.Installer.csproj --configuration Release -o bin/Release/Client/RageCoop
- name: Build server win-x64
run: dotnet publish RageCoop.Server/RageCoop.Server.csproj --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=false -r win-x64 -o RageCoop.Server/bin/win-x64 -c Release
run: dotnet publish RageCoop.Server/RageCoop.Server.csproj --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=false -r win-x64 -o bin/Release/Server/win-x64 -c Release
- name: Build server linux-x64
run: dotnet publish RageCoop.Server/RageCoop.Server.csproj --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=false -r linux-x64 -o RageCoop.Server/bin/linux-x64 -c Release
- name: Build server linux-arm
run: dotnet publish RageCoop.Server/RageCoop.Server.csproj --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=false -r linux-arm -o RageCoop.Server/bin/linux-arm -c Release
run: dotnet publish RageCoop.Server/RageCoop.Server.csproj --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=false -r linux-x64 -o bin/Release/Server/linux-x64 -c Release
- uses: vimtor/action-zip@v1
with:
files: RageCoop.Client/bin
files: bin/Release/Client
dest: RageCoop.Client.zip
- uses: vimtor/action-zip@v1
with:
files: RageCoop.Server/bin/win-x64
files: bin/Release/Server/win-x64
dest: RageCoop.Server-win-x64.zip
- uses: vimtor/action-zip@v1
with:
files: RageCoop.Server/bin/linux-x64
files: bin/Release/Server/linux-x64
dest: RageCoop.Server-linux-x64.zip
- uses: vimtor/action-zip@v1
with:
files: RageCoop.Server/bin/linux-arm
dest: RageCoop.Server-linux-arm.zip
- uses: WebFreak001/deploy-nightly@v1.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # automatically provided by github actions
@ -83,17 +75,3 @@ jobs:
asset_name: RageCoop.Server-linux-x64.zip
asset_content_type: application/zip
max_releases: 7
- uses: WebFreak001/deploy-nightly@v1.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # automatically provided by github actions
with:
upload_url: https://uploads.github.com/repos/RAGECOOP/RAGECOOP-V/releases/70603992/assets{?name,label}
release_id: 70603992
asset_path: RageCoop.Server-linux-arm.zip
asset_name: RageCoop.Server-linux-arm.zip
asset_content_type: application/zip
max_releases: 7
- uses: actions/checkout@v2

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
**/bin
**/obj
**/packages
**/.vs
**/.vs
**/.vscode

View File

@ -1,6 +1,8 @@
# 🌐 RAGECOOP
[![Downloads][downloads-shield]][downloads-url]
[![Contributors][contributors-shield]][contributors-url]
[![Forks][forks-shield]][forks-url]
[![Stargazers][stars-shield]][stars-url]
@ -8,51 +10,56 @@
# 🧠 That's it
RAGECOOP is a multiplayer mod to play story mode or some mods made for RAGECOOP or just drive around with your buddy.
_Old name: GTACOOP:R_
RAGECOOP brings multiplayer experience to the story mode, you can complete missions together with your friends, use mods without any restriction/getting banned, or just mess around with your fella!
# 📋 Requirements
- Visual Studio 2022
- .NET 6.0
- .NET Framework 4.8
# 👁 Requirements
- ScriptHookV
- ScriptHookVDotNet 3.6.0 or later
- .NET Framework 4.8 Runtime or SDK
# 📚 Libraries
- [ScriptHookVDotNet3](https://github.com/crosire/scripthookvdotnet/releases/tag/v3.4.0)
- [LemonUI.SHVDN3](https://github.com/justalemon/LemonUI/releases/tag/v1.6)
- Lidgren Network Custom (***PRIVATE***)
# 📋 Building the project
You'll need:
- .NET 6.0 SDK
- .NET Framework 4.8 SDK
Recommended IDE:
- Visual Studio Code
- Visul Studio 2022
Then run `dotnet build` in the solution directory, built binaries are in the `bin` folder
# 📚 Third-party libraries
- [ScriptHookVDotNet3](https://github.com/crosire/scripthookvdotnet)
- [LemonUI.SHVDN3](https://github.com/justalemon/LemonUI)
- Lidgren Network Custom
- - No new features (only improvements)
- [Newtonsoft.Json](https://www.nuget.org/packages/Newtonsoft.Json/13.0.1)
- [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json)
- [ClearScript](https://github.com/microsoft/ClearScript)
- [SharpZipLib](https://github.com/icsharpcode/SharpZipLib)
- [DotNetCorePlugins](https://github.com/natemcmaster/DotNetCorePlugins)
# Features
# 👋 Features
1. Synchronized bullets
2. Synchronized vehicle/player/NPC
3. Synchronized projectiles
4. Simple ragdoll sync
5. Smoother vehicle/ped movement.
6. Ownership based sync logic, carjacking is now working (sort of).
7. Introduced SyncEvents.
8. Code refactoring and namespace cleanup
9. Synchronized vehicle doors, brake and throttle.
10. Weaponized vehicle sync(WIP).
11. Other improvements
5. Decent compatibility with other mods, set up a private modded server to have some fun!
6. Weaponized vehicle sync(WIP).
7. Optimization for high-Ping condition, play with friends around the world!
8. Powerful scripting API and resource system, easily [add multiplayer functionality to your mod](HTTPS://docs.ragecoop.com).
# Known issues
# Known issues
1. Weapon sounds are missing.
2. Cover sync is still buggy.
3. Framerate drop with high number of synchronized entities.
5. Scripting API is screwed.(will be rewritten in the future)
See [Bugs](https://github.com/RAGECOOP/RAGECOOP-V/issues/33)
## Installation
# 🔫 Installation
Refer to the [wiki](https://github.com/RAGECOOP/RAGECOOP-V/wiki)
# Downloads
# 🧨 Downloads
Download latest release [here](https://github.com/RAGECOOP/RAGECOOP-V/releases/latest)
@ -61,11 +68,9 @@ You can also download nightly builds [here](https://github.com/RAGECOOP/RAGECOOP
Please note that this is incompatible with all previous versions of ragecoop, remove old files before installing.
# Support us
<a href="https://patreon.com/Sardelka"><img src="https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3DSardelka%26type%3Dpatrons&style=for-the-badge" /></a>
# 🦆 Special thanks to
- [Makinolo](https://github.com/Makinolo), [oldnapalm](https://github.com/oldnapalm)
- - For testing, ideas, contributions and the first modification with the API
- [crosire](https://github.com/crosire)
@ -74,8 +79,11 @@ Please note that this is incompatible with all previous versions of ragecoop, re
- - For the extensive work in LemonUI
# 📝 License
This project is licensed under [MIT license](https://github.com/RAGECOOP/RAGECOOP-V/blob/main/LICENSE)
[downloads-shield]: https://img.shields.io/github/downloads/RAGECOOP/RAGECOOP-V/total?style=for-the-badge
[downloads-url]: https://github.com/RAGECOOP/RAGECOOP-V/releases
[contributors-shield]: https://img.shields.io/github/contributors/RAGECOOP/RAGECOOP-V.svg?style=for-the-badge
[contributors-url]: https://github.com/RAGECOOP/RAGECOOP-V/graphs/contributors
[forks-shield]: https://img.shields.io/github/forks/RAGECOOP/RAGECOOP-V.svg?style=for-the-badge
@ -85,3 +93,4 @@ This project is licensed under [MIT license](https://github.com/RAGECOOP/RAGECOO
[issues-shield]: https://img.shields.io/github/issues/RAGECOOP/RAGECOOP-V.svg?style=for-the-badge
[issues-url]: https://github.com/RAGECOOP/RAGECOOP-V/issues

View File

@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Core", "RageCoop.C
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RageCoop.Client", "RageCoop.Client\RageCoop.Client.csproj", "{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Client.Installer", "RageCoop.Client.Installer\RageCoop.Client.Installer.csproj", "{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -41,6 +43,14 @@ Global
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|Any CPU.Build.0 = Release|Any CPU
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|x64.ActiveCfg = Release|Any CPU
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|x64.Build.0 = Release|Any CPU
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Debug|x64.ActiveCfg = Debug|Any CPU
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Debug|x64.Build.0 = Debug|Any CPU
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Release|Any CPU.Build.0 = Release|Any CPU
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Release|x64.ActiveCfg = Release|Any CPU
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,9 @@
<Application x:Class="RageCoop.Client.Installer.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RageCoop.Client.Installer"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

View File

@ -0,0 +1,11 @@
using System.Windows;
namespace RageCoop.Client.Installer
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

View File

@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@ -0,0 +1,15 @@
<Window x:Class="RageCoop.Client.Installer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:RageCoop.Client.Installer"
mc:Ignorable="d"
Title="MainWindow" Height="376" Width="617" Background="#FFBABABA">
<Grid>
<Grid.Background>
<ImageBrush ImageSource="/bg.png" Opacity="0.2"/>
</Grid.Background>
<Label x:Name="Status" FontSize="20" Foreground="#FF232323" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Window>

View File

@ -0,0 +1,213 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
using MessageBox = System.Windows.MessageBox;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
using Path = System.IO.Path;
using RageCoop.Core;
namespace RageCoop.Client.Installer
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Choose();
}
private void Choose()
{
var od = new OpenFileDialog()
{
Filter = "GTA 5 executable |GTA5.exe;PlayGTAV.exe",
Title = "Select you GTAV executable"
};
if (od.ShowDialog() ?? false == true)
{
Task.Run(() =>
{
try
{
Install(Directory.GetParent(od.FileName).FullName);
}
catch (Exception ex)
{
MessageBox.Show("Installation failed: " + ex.ToString());
Environment.Exit(1);
}
});
}
else
{
Environment.Exit(0);
}
}
private void Install(string root)
{
UpdateStatus("Checking requirements");
var shvPath = Path.Combine(root, "ScriptHookV.dll");
var shvdnPath = Path.Combine(root, "ScriptHookVDotNet3.dll");
var scriptsPath = Path.Combine(root, "Scripts");
var lemonPath = Path.Combine(scriptsPath, "LemonUI.SHVDN3.dll");
var installPath = Path.Combine(scriptsPath, "RageCoop");
if (Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName == installPath)
{
throw new InvalidOperationException("The installer is not meant to be run in the game folder, please extract the zip to somewhere else and run again.");
}
Directory.CreateDirectory(installPath);
if (!File.Exists(shvPath))
{
MessageBox.Show("Please install ScriptHookV first!");
Environment.Exit(1);
}
if (!File.Exists(shvdnPath))
{
MessageBox.Show("Please install ScriptHookVDotNet first!");
Environment.Exit(1);
}
var shvdnVer = GetVer(shvdnPath);
if (shvdnVer < new Version(3, 6, 0))
{
MessageBox.Show("Please update ScriptHookVDotNet to latest version!" +
$"\nCurrent version is {shvdnVer}, 3.6.0 or higher is required");
Environment.Exit(1);
}
if (File.Exists(lemonPath))
{
var lemonVer = GetVer(lemonPath);
if (lemonVer < new Version(1, 7))
{
UpdateStatus("Updating LemonUI");
File.WriteAllBytes(lemonPath, getLemon());
}
}
UpdateStatus("Removing old versions");
foreach (var f in Directory.GetFiles(scriptsPath, "RageCoop.*", SearchOption.AllDirectories))
{
if (f.EndsWith("RageCoop.Client.Settings.xml")) { continue; }
File.Delete(f);
}
foreach (var f in Directory.GetFiles(installPath, "*.dll", SearchOption.AllDirectories))
{
File.Delete(f);
}
if (File.Exists("RageCoop.Core.dll") && File.Exists("RageCoop.Client.dll"))
{
UpdateStatus("Installing...");
CoreUtils.CopyFilesRecursively(new DirectoryInfo(Directory.GetCurrentDirectory()), new DirectoryInfo(installPath));
Finish();
}
else
{
throw new Exception("Required files are missing, please re-download the zip from official website");
}
void Finish()
{
checkKeys:
UpdateStatus("Checking conflicts");
var menyooConfig = Path.Combine(root, @"menyooStuff\menyooConfig.ini");
var settingsPath = Path.Combine(installPath, @"Data\RageCoop.Client.Settings.xml");
Settings settings = null;
try
{
settings = Util.ReadSettings(settingsPath);
}
catch
{
settings = new Settings();
}
if (File.Exists(menyooConfig))
{
var lines = File.ReadAllLines(menyooConfig).Where(x => !x.StartsWith(";") && x.EndsWith(" = " + (int)settings.MenuKey));
if (lines.Any())
{
if (MessageBox.Show("Following menyoo config value will conflict with RAGECOOP menu key\n" +
string.Join("\n", lines)
+ "\nDo you wish to change the Menu Key?", "Warning!", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
var ae = new AutoResetEvent(false);
UpdateStatus("Press the key you wish to change to");
Dispatcher.BeginInvoke(new Action(() =>
KeyDown += (s, e) =>
{
settings.MenuKey = (Keys)KeyInterop.VirtualKeyFromKey(e.Key);
ae.Set();
}));
ae.WaitOne();
if (!Util.SaveSettings(settingsPath, settings))
{
MessageBox.Show("Error occurred when saving settings");
Environment.Exit(1);
}
MessageBox.Show("Menu key changed to " + settings.MenuKey);
goto checkKeys;
}
}
}
UpdateStatus("Checking ZeroTier");
try
{
ZeroTierHelper.Check();
}
catch
{
if (MessageBox.Show("You can't join ZeroTier server unless ZeroTier is installed, do you want to download and install it?", "Install ZeroTier", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
var url = "https://download.zerotier.com/dist/ZeroTier%20One.msi";
UpdateStatus("Downloading ZeroTier from " + url);
try
{
HttpHelper.DownloadFile(url, "ZeroTier.msi", (p) => UpdateStatus("Downloading ZeroTier " + p + "%"));
UpdateStatus("Installing ZeroTier");
Process.Start("ZeroTier.msi").WaitForExit();
}
catch
{
MessageBox.Show("Failed to download ZeroTier, please download it from officail website");
Process.Start(url);
}
}
}
UpdateStatus("Completed!");
MessageBox.Show("Installation sucessful!");
Environment.Exit(0);
}
}
private void UpdateStatus(string status)
{
Dispatcher.BeginInvoke(new Action(() => Status.Content = status));
}
private Version GetVer(string location)
{
return Version.Parse(FileVersionInfo.GetVersionInfo(location).FileVersion);
}
private byte[] getLemon()
{
return (byte[])Resource.ResourceManager.GetObject("LemonUI_SHVDN3");
}
}
}

View File

@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net48</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<None Remove="bg.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RageCoop.Client\RageCoop.Client.csproj" />
<ProjectReference Include="..\RageCoop.Core\RageCoop.Core.csproj" />
</ItemGroup>
<ItemGroup>
<Resource Include="bg.png" />
</ItemGroup>
<ItemGroup>
<Compile Update="Resource.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resource.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resource.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@ -0,0 +1,72 @@
<Project>
<PropertyGroup>
<AssemblyName>RageCoop.Client.Installer</AssemblyName>
<IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
<MSBuildProjectExtensionsPath>M:\SandBox-Shared\repos\RAGECOOP\RAGECOOP-V\RageCoop.Client.Installer\obj\</MSBuildProjectExtensionsPath>
<_TargetAssemblyProjectName>RageCoop.Client.Installer</_TargetAssemblyProjectName>
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net48</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<None Remove="bg.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RageCoop.Client\RageCoop.Client.csproj" />
<ProjectReference Include="..\RageCoop.Core\RageCoop.Core.csproj" />
</ItemGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup>
<Compile Update="Resource.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resource.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resource.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ReferencePath Include="C:\Users\Sardelka\.nuget\packages\sharpziplib\1.3.3\lib\net45\ICSharpCode.SharpZipLib.dll" />
<ReferencePath Include="C:\Users\Sardelka\.nuget\packages\microsoft.extensions.objectpool\6.0.8\lib\net461\Microsoft.Extensions.ObjectPool.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\mscorlib.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\PresentationCore.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\PresentationFramework.dll" />
<ReferencePath Include="M:\SandBox-Shared\repos\RAGECOOP\RAGECOOP-V\bin\Debug\Client\RageCoop.Client.dll" />
<ReferencePath Include="M:\SandBox-Shared\repos\RAGECOOP\RAGECOOP-V\bin\Debug\Core\RageCoop.Core.dll" />
<ReferencePath Include="C:\Users\Sardelka\.nuget\packages\system.buffers\4.5.1\ref\net45\System.Buffers.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Core.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Data.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Drawing.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.IO.Compression.FileSystem.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Numerics.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Runtime.Serialization.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Windows.Controls.Ribbon.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Windows.Forms.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Xaml.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Xml.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Xml.Linq.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\UIAutomationClient.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\UIAutomationClientsideProviders.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\UIAutomationProvider.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\UIAutomationTypes.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\WindowsBase.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\WindowsFormsIntegration.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\Facades\netstandard.dll" />
</ItemGroup>
<ItemGroup>
<Compile Include="M:\SandBox-Shared\repos\RAGECOOP\RAGECOOP-V\RageCoop.Client.Installer\obj\Debug\net48\MainWindow.g.cs" />
<Compile Include="M:\SandBox-Shared\repos\RAGECOOP\RAGECOOP-V\RageCoop.Client.Installer\obj\Debug\net48\App.g.cs" />
</ItemGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>

View File

@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace RageCoop.Client.Installer {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resource {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resource() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RageCoop.Client.Installer.Resource", typeof(Resource).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] LemonUI_SHVDN3 {
get {
object obj = ResourceManager.GetObject("LemonUI_SHVDN3", resourceCulture);
return ((byte[])(obj));
}
}
}
}

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="LemonUI_SHVDN3" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\LemonUI.SHVDN3.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

View File

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RageCoop.Client
{
@ -21,7 +18,7 @@ namespace RageCoop.Client
CheckProjectiles,
GetAllEntities,
Receive,
ProjectilesTotal,
}
internal static class Debug
{
@ -29,7 +26,7 @@ namespace RageCoop.Client
private static int _lastNfHandle;
static Debug()
{
foreach(TimeStamp t in Enum.GetValues(typeof(TimeStamp)))
foreach (TimeStamp t in Enum.GetValues(typeof(TimeStamp)))
{
TimeStamps.Add(t, 0);
}
@ -37,16 +34,16 @@ namespace RageCoop.Client
public static string Dump(this Dictionary<TimeStamp, long> d)
{
string s = "";
foreach(KeyValuePair<TimeStamp, long> kvp in d)
foreach (KeyValuePair<TimeStamp, long> kvp in d)
{
s+=kvp.Key+":"+kvp.Value+"\n";
s += kvp.Key + ":" + kvp.Value + "\n";
}
return s;
}
public static void ShowTimeStamps()
{
GTA.UI.Notification.Hide(_lastNfHandle);
_lastNfHandle=GTA.UI.Notification.Show(Debug.TimeStamps.Dump());
_lastNfHandle = GTA.UI.Notification.PostTicker(TimeStamps.Dump(), false).Handle;
}
}

View File

@ -1,33 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA;
using GTA;
using GTA.Math;
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.Windows.Forms;
namespace RageCoop.Client
{
internal class DevTool:Script
internal class DevTool : Script
{
public static Vehicle ToMark;
public static bool UseSecondary=false;
public static bool UseSecondary = false;
public static int Current = 0;
public static int Secondary = 0;
public static MuzzleDir Direction = MuzzleDir.Forward;
public DevTool()
{
Tick+=OnTick;
KeyDown+=OnKeyDown;
Tick += OnTick;
KeyDown += OnKeyDown;
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (ToMark==null||(!ToMark.Exists())) { return; }
if (DevToolMenu.Menu.SelectedItem==DevToolMenu.boneIndexItem) {
if (ToMark == null || (!ToMark.Exists())) { return; }
if (DevToolMenu.Menu.SelectedItem == DevToolMenu.boneIndexItem)
{
switch (e.KeyCode)
{
@ -39,7 +36,7 @@ namespace RageCoop.Client
break;
}
}
else if (DevToolMenu.Menu.SelectedItem==DevToolMenu.secondaryBoneIndexItem)
else if (DevToolMenu.Menu.SelectedItem == DevToolMenu.secondaryBoneIndexItem)
{
switch (e.KeyCode)
@ -57,28 +54,28 @@ namespace RageCoop.Client
private static void Update()
{
if (Current>ToMark.Bones.Count-1)
if (Current > ToMark.Bones.Count - 1)
{
Current=0;
Current = 0;
}
else if (Current< 0)
else if (Current < 0)
{
Current=ToMark.Bones.Count-1;
Current = ToMark.Bones.Count - 1;
}
DevToolMenu.boneIndexItem.AltTitle= Current.ToString();
if (Secondary>ToMark.Bones.Count-1)
DevToolMenu.boneIndexItem.AltTitle = Current.ToString();
if (Secondary > ToMark.Bones.Count - 1)
{
Secondary=0;
Secondary = 0;
}
else if (Secondary< 0)
else if (Secondary < 0)
{
Secondary=ToMark.Bones.Count-1;
Secondary = ToMark.Bones.Count - 1;
}
DevToolMenu.secondaryBoneIndexItem.AltTitle= Secondary.ToString();
DevToolMenu.secondaryBoneIndexItem.AltTitle = Secondary.ToString();
}
private static void OnTick(object sender, EventArgs e)
{
if(ToMark == null || !ToMark.Exists()){ return;}
if (ToMark == null || !ToMark.Exists()) { return; }
Update();
Draw(Current);
if (UseSecondary)
@ -90,95 +87,93 @@ namespace RageCoop.Client
private static void Draw(int boneindex)
{
var bone = ToMark.Bones[boneindex];
World.DrawLine(bone.Position, bone.Position+2*bone.ForwardVector, Color.Blue);
World.DrawLine(bone.Position, bone.Position+2*bone.UpVector, Color.Green);
World.DrawLine(bone.Position, bone.Position+2*bone.RightVector, Color.Yellow);
World.DrawLine(bone.Position, bone.Position + 2 * bone.ForwardVector, Color.Blue);
World.DrawLine(bone.Position, bone.Position + 2 * bone.UpVector, Color.Green);
World.DrawLine(bone.Position, bone.Position + 2 * bone.RightVector, Color.Yellow);
Vector3 todraw = bone.ForwardVector;
switch ((byte)Direction)
{
case 0:
todraw=bone.ForwardVector;
todraw = bone.ForwardVector;
break;
case 1:
todraw=bone.RightVector;
todraw = bone.RightVector;
break;
case 2:
todraw=bone.UpVector;
todraw = bone.UpVector;
break;
case 3:
todraw=bone.ForwardVector*-1;
todraw = bone.ForwardVector * -1;
break;
case 4:
todraw=bone.RightVector*-1;
todraw = bone.RightVector * -1;
break;
case 5:
todraw=bone.UpVector*-1;
todraw = bone.UpVector * -1;
break;
}
World.DrawLine(bone.Position, bone.Position+10*todraw, Color.Red);
World.DrawLine(bone.Position, bone.Position + 10 * todraw, Color.Red);
}
public static void CopyToClipboard(MuzzleDir dir)
{
if (ToMark!=null)
if (ToMark != null)
{
string s;
if (UseSecondary)
{
if ((byte)dir<3)
if ((byte)dir < 3)
{
s=$@"
s = $@"
// {ToMark.DisplayName}
case {ToMark.Model.Hash}:
i=BulletsShot%2==0 ? {Current} : {Secondary};
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].{dir}Vector);
return BulletsShot%2==0 ? {Current} : {Secondary};
";
}
else
{
s=$@"
s = $@"
// {ToMark.DisplayName}
case {ToMark.Model.Hash}:
i=BulletsShot%2==0 ? {Current} : {Secondary};
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].{((MuzzleDir)(dir-3)).ToString()}Vector*-1);
return BulletsShot%2==0 ? {Current} : {Secondary};
";
}
}
else
{
if ((byte)dir<3)
if ((byte)dir < 3)
{
s=$@"
s = $@"
// {ToMark.DisplayName}
case {ToMark.Model.Hash}:
return new MuzzleInfo(v.Bones[{Current}].Position, v.Bones[{Current}].{dir}Vector);
return {Current};
";
}
else
{
s=$@"
s = $@"
// {ToMark.DisplayName}
case {ToMark.Model.Hash}:
return new MuzzleInfo(v.Bones[{Current}].Position, v.Bones[{Current}].{((MuzzleDir)(dir-3)).ToString()}Vector*-1);
return {Current};
";
}
}
Thread thread = new Thread(() => Clipboard.SetText(s));
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
GTA.UI.Notification.Show("Copied to clipboard, please paste it on the GitHub issue page!");
GTA.UI.Notification.PostTicker("Copied to clipboard, please paste it on the GitHub issue page!", false);
}
}
}
internal enum MuzzleDir:byte
internal enum MuzzleDir : byte
{
Forward=0,
Forward = 0,
Right = 1,
Up=2,
Backward=3,
Up = 2,
Backward = 3,
Left = 4,
Down=5,
Down = 5,
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura ExcludeAssemblies="RageCoop.Core"/>
</Weavers>

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeReferences" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if runtime assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseRuntimeReferencePaths" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCompression" type="xs:boolean">
<xs:annotation>
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCleanup" type="xs:boolean">
<xs:annotation>
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -1,16 +1,16 @@
using System;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Diagnostics;
using GTA;
using GTA.Math;
using GTA.Native;
using RageCoop.Client.Menus;
using RageCoop.Core;
using GTA;
using GTA.Native;
using GTA.Math;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RageCoop.Client
{
@ -19,37 +19,49 @@ namespace RageCoop.Client
/// </summary>
internal class Main : Script
{
private bool _gameLoaded = false;
internal static readonly string CurrentVersion = "V0_5_0";
internal static Version Version = typeof(Main).Assembly.GetName().Version;
internal static int LocalPlayerID=0;
internal static int LocalPlayerID = 0;
internal static RelationshipGroup SyncedPedsGroup;
internal static new Settings Settings = null;
internal static Scripting.BaseScript BaseScript=new Scripting.BaseScript();
internal static Scripting.BaseScript BaseScript = new Scripting.BaseScript();
#if !NON_INTERACTIVE
#endif
internal static Chat MainChat = null;
internal static Stopwatch Counter = new Stopwatch();
internal static Logger Logger = null;
internal static ulong Ticked = 0;
internal static Scripting.Resources Resources=null;
private static List<Func<bool>> QueuedActions = new List<Func<bool>>();
internal static Vector3 PlayerPosition;
internal static Scripting.Resources Resources = null;
private static readonly List<Func<bool>> QueuedActions = new List<Func<bool>>();
public static Worker Worker;
/// <summary>
/// Don't use it!
/// </summary>
public Main()
{
Settings = Util.ReadSettings();
Directory.CreateDirectory(Settings.DataDirectory);
Logger=new Logger()
Worker = new Worker("RageCoop.Client.Main.Worker", Logger);
try
{
LogPath=$"{Settings.DataDirectory}\\RageCoop.Client.log",
UseConsole=false,
Settings = Util.ReadSettings();
}
catch
{
GTA.UI.Notification.PostTicker("Malformed configuration, overwriting with default values...", false);
Settings = new Settings();
Util.SaveSettings();
}
Directory.CreateDirectory(Settings.DataDirectory);
Logger = new Logger()
{
LogPath = $"{Settings.DataDirectory}\\RageCoop.Client.log",
UseConsole = false,
#if DEBUG
LogLevel = 0,
#else
@ -67,33 +79,37 @@ namespace RageCoop.Client
}
if (!_gameLoaded)
{
GTA.UI.Notification.Show("~r~Please update your GTA5 to v1.0.1290 or newer!", true);
GTA.UI.Notification.PostTicker("~r~Please update your GTA5 to v1.0.1290 or newer!", true);
_gameLoaded = true;
}
};
return;
}
BaseScript.OnStart();
SyncedPedsGroup=World.AddRelationshipGroup("SYNCPED");
SyncedPedsGroup = World.AddRelationshipGroup("SYNCPED");
Game.Player.Character.RelationshipGroup.SetRelationshipBetweenGroups(SyncedPedsGroup, Relationship.Neutral, true);
#if !NON_INTERACTIVE
#endif
MainChat = new Chat();
Tick += OnTick;
Tick += (s,e) => { Scripting.API.Events.InvokeTick(); };
Tick += (s, e) => { Scripting.API.Events.InvokeTick(); };
KeyDown += OnKeyDown;
KeyDown+=(s, e) => { Scripting.API.Events.InvokeKeyDown(s, e); };
KeyUp+=(s, e) => { Scripting.API.Events.InvokeKeyUp(s, e); };
Aborted += (object sender, EventArgs e) => CleanUp();
KeyDown += (s, e) => { Scripting.API.Events.InvokeKeyDown(s, e); };
KeyUp += (s, e) => { Scripting.API.Events.InvokeKeyUp(s, e); };
Aborted += (object sender, EventArgs e) => Disconnected("Abort");
Util.NativeMemory();
Counter.Restart();
}
#if DEBUG
#endif
public static Ped P;
public static float FPS;
private bool _lastDead;
private void OnTick(object sender, EventArgs e)
{
P = Game.Player.Character;
PlayerPosition = P.ReadPosition();
FPS = Game.FPS;
if (Game.IsLoading)
{
return;
@ -101,22 +117,23 @@ namespace RageCoop.Client
else if (!_gameLoaded && (_gameLoaded = true))
{
#if !NON_INTERACTIVE
GTA.UI.Notification.Show(GTA.UI.NotificationIcon.AllPlayersConf, "RAGECOOP","Welcome!", $"Press ~g~{Main.Settings.MenuKey}~s~ to open the menu.");
GTA.UI.Notification.PostMessageText($"Press ~g~{Settings.MenuKey}~s~ to open the menu.", new GTA.Graphics.TextureAsset("CHAR_ALL_PLAYERS_CONF", "CHAR_ALL_PLAYERS_CONF"), false, GTA.UI.FeedTextIcon.Message, "RAGECOOP", "Welcome!");
#endif
}
#if !NON_INTERACTIVE
CoopMenu.MenuPool.Process();
#endif
DoQueuedActions();
if (!Networking.IsOnServer)
{
return;
}
if (Game.TimeScale!=1)
if (Game.TimeScale != 1)
{
Game.TimeScale=1;
Game.TimeScale = 1;
}
try
{
@ -124,22 +141,17 @@ namespace RageCoop.Client
}
catch (Exception ex)
{
Main.Logger.Error(ex);
}
#if DEBUG
Main.Logger.Error(ex);
#endif
}
if (Networking.ShowNetworkInfo)
{
new LemonUI.Elements.ScaledText(new PointF(Screen.PrimaryScreen.Bounds.Width / 2, 0), $"L: {Networking.Latency * 1000:N0}ms", 0.5f) { Alignment = GTA.UI.Alignment.Center }.Draw();
new LemonUI.Elements.ScaledText(new PointF(Screen.PrimaryScreen.Bounds.Width / 2, 30), $"R: {Lidgren.Network.NetUtility.ToHumanReadable(Statistics.BytesDownPerSecond)}/s", 0.5f) { Alignment = GTA.UI.Alignment.Center }.Draw();
new LemonUI.Elements.ScaledText(new PointF(Screen.PrimaryScreen.Bounds.Width / 2, 60), $"S: {Lidgren.Network.NetUtility.ToHumanReadable(Statistics.BytesUpPerSecond)}/s", 0.5f) { Alignment = GTA.UI.Alignment.Center }.Draw();
}
#endif
MainChat.Tick();
PlayerList.Tick();
@ -147,33 +159,34 @@ namespace RageCoop.Client
{
Function.Call(Hash.PAUSE_DEATH_ARREST_RESTART, true);
Function.Call(Hash.IGNORE_NEXT_RESTART, true);
Function.Call(Hash.FORCE_GAME_STATE_PLAYING);
Function.Call(Hash.FORCE_GAME_STATE_PLAYING);
Function.Call(Hash.TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME, "respawn_controller");
var P = Game.Player.Character;
if (P.IsDead)
{
Function.Call(Hash.SET_FADE_OUT_AFTER_DEATH, false);
if (P.Health!=1)
if (P.Health != 1)
{
P.Health=1;
Game.Player.WantedLevel=0;
P.Health = 1;
Game.Player.WantedLevel = 0;
Main.Logger.Debug("Player died.");
Scripting.API.Events.InvokePlayerDied(KillMessage());
}
GTA.UI.Screen.StopEffects();
}
else
{
Function.Call(Hash.DISPLAY_HUD, true);
}
}
else if (P.IsDead && !_lastDead)
{
Scripting.API.Events.InvokePlayerDied(KillMessage());
}
_lastDead = P.IsDead;
Ticked++;
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (MainChat.Focused)
@ -183,12 +196,26 @@ namespace RageCoop.Client
}
if (Networking.IsOnServer)
{
if (Voice.WasInitialized())
{
if (Game.IsControlPressed(GTA.Control.PushToTalk))
{
Voice.StartRecording();
return;
}
else if (Voice.IsRecording())
{
Voice.StopRecording();
return;
}
}
if (Game.IsControlPressed(GTA.Control.FrontendPause))
{
Function.Call(Hash.ACTIVATE_FRONTEND_MENU, Function.Call<int>(Hash.GET_HASH_KEY, "FE_MENU_VERSION_SP_PAUSE"), false, 0);
return;
}
if (Game.IsControlPressed(GTA.Control.FrontendPauseAlternate)&&Settings.DisableAlternatePause)
if (Game.IsControlPressed(GTA.Control.FrontendPauseAlternate) && Settings.DisableAlternatePause)
{
Function.Call(Hash.ACTIVATE_FRONTEND_MENU, Function.Call<int>(Hash.GET_HASH_KEY, "FE_MENU_VERSION_SP_PAUSE"), false, 0);
return;
@ -202,8 +229,8 @@ namespace RageCoop.Client
{
if (x.Visible)
{
CoopMenu.LastMenu=x;
x.Visible=false;
CoopMenu.LastMenu = x;
x.Visible = false;
}
});
}
@ -212,14 +239,6 @@ namespace RageCoop.Client
CoopMenu.LastMenu.Visible = true;
}
}
else if (Game.IsControlJustPressed(GTA.Control.MultiplayerInfo))
{
if (Networking.IsOnServer)
{
ulong currentTimestamp = Util.GetTickCount64();
PlayerList.Pressed = (currentTimestamp - PlayerList.Pressed) < 5000 ? (currentTimestamp - 6000) : currentTimestamp;
}
}
else if (Game.IsControlJustPressed(GTA.Control.MpTextChatAll))
{
if (Networking.IsOnServer)
@ -227,10 +246,19 @@ namespace RageCoop.Client
MainChat.Focused = true;
}
}
else if (e.KeyCode==Settings.PassengerKey)
else if (MainChat.Focused) { return; }
else if (Game.IsControlJustPressed(GTA.Control.MultiplayerInfo))
{
if (Networking.IsOnServer)
{
ulong currentTimestamp = Util.GetTickCount64();
PlayerList.Pressed = (currentTimestamp - PlayerList.Pressed) < 5000 ? (currentTimestamp - 6000) : currentTimestamp;
}
}
else if (e.KeyCode == Settings.PassengerKey)
{
var P = Game.Player.Character;
if (!P.IsInVehicle())
{
if (P.IsTaskActive(TaskType.CTaskEnterVehicle))
@ -239,94 +267,74 @@ namespace RageCoop.Client
}
else
{
var V = World.GetClosestVehicle(P.Position, 50);
var V = World.GetClosestVehicle(P.ReadPosition(), 50);
if (V!=null)
if (V != null)
{
var seat = P.GetNearestSeat(V);
P.Task.EnterVehicle(V, seat);
var p = V.GetPedOnSeat(seat);
if (p != null && !p.IsDead)
{
for (int i = -1; i < V.PassengerCapacity; i++)
{
seat = (VehicleSeat)i;
p = V.GetPedOnSeat(seat);
if (p == null || p.IsDead)
{
break;
}
}
}
P.Task.EnterVehicle(V, seat, -1, 5, EnterVehicleFlags.None);
}
}
}
}
}
public static void CleanUp()
internal static void Connected()
{
MainChat.Clear();
EntityPool.Cleanup();
PlayerList.Cleanup();
Main.LocalPlayerID=default;
}
internal static readonly Dictionary<ulong, byte> CheckNativeHash = new Dictionary<ulong, byte>()
{
{ 0xD49F9B0955C367DE, 1 }, // Entities
{ 0xEF29A16337FACADB, 1 }, //
{ 0xB4AC7D0CF06BFE8F, 1 }, //
{ 0x9B62392B474F44A0, 1 }, //
{ 0x7DD959874C1FD534, 1 }, //
{ 0xAF35D0D2583051B0, 2 }, // Vehicles
{ 0x63C6CCA8E68AE8C8, 2 }, //
{ 0x509D5878EB39E842, 3 }, // Props
{ 0x9A294B2138ABB884, 3 }, //
{ 0x46818D79B1F7499A, 4 }, // Blips
{ 0x5CDE92C702A8FCE7, 4 }, //
{ 0xBE339365C863BD36, 4 }, //
{ 0x5A039BB0BCA604B6, 4 }, //
{ 0x0134F0835AB6BFCB, 5 } // Checkpoints
};
internal static Dictionary<int, byte> ServerItems = new Dictionary<int, byte>();
internal static void CleanUpWorld()
{
if (ServerItems.Count == 0)
Memory.ApplyPatches();
if (Settings.Voice && !Voice.WasInitialized())
{
return;
Voice.Init();
}
lock (ServerItems)
QueueAction(() =>
{
foreach (KeyValuePair<int, byte> item in ServerItems)
WorldThread.Traffic(!Settings.DisableTraffic);
Function.Call(Hash.SET_ENABLE_VEHICLE_SLIPSTREAMING, true);
CoopMenu.ConnectedMenuSetting();
MainChat.Init();
GTA.UI.Notification.PostTicker("~g~Connected!", false);
});
Logger.Info(">> Connected <<");
}
public static void Disconnected(string reason)
{
Logger.Info($">> Disconnected << reason: {reason}");
QueueAction(() =>
{
if (MainChat.Focused)
{
try
{
switch (item.Value)
{
case 1:
World.GetAllEntities().FirstOrDefault(x => x.Handle == item.Key)?.Delete();
break;
case 2:
World.GetAllVehicles().FirstOrDefault(x => x.Handle == item.Key)?.Delete();
break;
case 3:
World.GetAllProps().FirstOrDefault(x => x.Handle == item.Key)?.Delete();
break;
case 4:
Blip blip = new Blip(item.Key);
if (blip.Exists())
{
blip.Delete();
}
break;
case 5:
Checkpoint checkpoint = new Checkpoint(item.Key);
if (checkpoint.Exists())
{
checkpoint.Delete();
}
break;
}
}
catch
{
GTA.UI.Notification.Show("~r~~h~CleanUpWorld() Error");
Main.Logger.Error($"CleanUpWorld(): ~r~Item {item.Value} cannot be deleted!");
}
MainChat.Focused = false;
}
ServerItems.Clear();
}
PlayerList.Cleanup();
MainChat.Clear();
EntityPool.Cleanup();
WorldThread.Traffic(true);
Function.Call(Hash.SET_ENABLE_VEHICLE_SLIPSTREAMING, false);
CoopMenu.DisconnectedMenuSetting();
if (reason != "Abort")
GTA.UI.Notification.PostTicker("~r~Disconnected: " + reason, false);
LocalPlayerID = default;
});
Memory.RestorePatches();
DownloadManager.Cleanup();
Voice.ClearAll();
Resources.Unload();
}
private static void DoQueuedActions()
{
lock (QueuedActions)
@ -340,9 +348,11 @@ namespace RageCoop.Client
QueuedActions.Remove(action);
}
}
catch(Exception ex)
catch (Exception ex)
{
#if DEBUG
Logger.Error(ex);
#endif
QueuedActions.Remove(action);
}
}
@ -350,9 +360,9 @@ namespace RageCoop.Client
}
/// <summary>
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
/// </summary>
/// <param name="a"> The action to be executed, must return a bool indicating whether the action cane be removed after execution.</param>
/// <param name="a"> An action to be executed with a return value indicating whether the action can be removed after execution.</param>
internal static void QueueAction(Func<bool> a)
{
lock (QueuedActions)
@ -364,7 +374,7 @@ namespace RageCoop.Client
{
lock (QueuedActions)
{
QueuedActions.Add(() => { a(); return true; }) ;
QueuedActions.Add(() => { a(); return true; });
}
}
/// <summary>
@ -375,6 +385,24 @@ namespace RageCoop.Client
lock (QueuedActions) { QueuedActions.Clear(); }
}
public static void Delay(Action a, int time)
{
Task.Run(() =>
{
Thread.Sleep(time);
QueueAction(a);
});
}
private string KillMessage()
{
if (P.Killer != null)
{
var killer = EntityPool.GetPedByHandle(P.Killer.Handle);
if (killer != null && killer.ID == killer.Owner.ID)
return $"~h~{PlayerList.GetPlayer(LocalPlayerID).Username}~h~ was killed by ~h~{killer.Owner.Username}~h~ ({P.CauseOfDeath})";
}
return $"~h~{PlayerList.GetPlayer(LocalPlayerID).Username}~h~ died";
}
}
}

View File

@ -1,10 +1,9 @@
using GTA;
using System.Drawing;
using GTA.Native;
using LemonUI;
using LemonUI.Menus;
using LemonUI.Scaleform;
using System.Drawing;
namespace RageCoop.Client.Menus
{
@ -19,27 +18,28 @@ namespace RageCoop.Client.Menus
UseMouse = false,
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
};
public static PopUp PopUp=new PopUp()
public static PopUp PopUp = new PopUp()
{
Title="",
Prompt="",
Title = "",
Prompt = "",
Subtitle = "",
Error="",
Error = "",
ShowBackground = true,
Visible=false,
Visible = false,
};
public static NativeMenu LastMenu { get; set; } = Menu;
#region ITEMS
private static readonly NativeItem _usernameItem = new NativeItem("Username") { AltTitle = Main.Settings.Username };
private static readonly NativeItem _passwordItem = new NativeItem("Password") { AltTitle = new string('*',Main.Settings.Password.Length) };
private static readonly NativeItem _passwordItem = new NativeItem("Password") { AltTitle = new string('*', Main.Settings.Password.Length) };
public static readonly NativeItem ServerIpItem = new NativeItem("Server IP") { AltTitle = Main.Settings.LastServerAddress };
internal static readonly NativeItem _serverConnectItem = new NativeItem("Connect");
private static readonly NativeItem _aboutItem = new NativeItem("About", "~y~SOURCE~s~~n~" +
"https://github.com/RAGECOOP~n~" +
"~y~VERSION~s~~n~" +
Main.CurrentVersion.Replace("_", ".")) { LeftBadge = new LemonUI.Elements.ScaledTexture("commonmenu", "shop_new_star") };
Main.Version)
{ LeftBadge = new LemonUI.Elements.ScaledTexture("commonmenu", "shop_new_star") };
#endregion
@ -50,10 +50,10 @@ namespace RageCoop.Client.Menus
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
_usernameItem.Activated += UsernameActivated;
_passwordItem.Activated+=_passwordActivated;
_passwordItem.Activated += _passwordActivated;
ServerIpItem.Activated += ServerIpActivated;
_serverConnectItem.Activated += (sender, item) => { Networking.ToggleConnection(Main.Settings.LastServerAddress); };
@ -67,14 +67,17 @@ namespace RageCoop.Client.Menus
Menu.AddSubMenu(SettingsMenu.Menu);
Menu.AddSubMenu(DevToolMenu.Menu);
#if DEBUG
Menu.AddSubMenu(DebugMenu.Menu);
#endif
MenuPool.Add(Menu);
MenuPool.Add(SettingsMenu.Menu);
MenuPool.Add(DevToolMenu.Menu);
#if DEBUG
MenuPool.Add(DebugMenu.Menu);
MenuPool.Add(DebugMenu.DiagnosticMenu);
#endif
MenuPool.Add(ServersMenu.Menu);
MenuPool.Add(PopUp);
@ -82,21 +85,32 @@ namespace RageCoop.Client.Menus
}
public static bool ShowPopUp(string prompt, string title,string subtitle,string error,bool showbackground)
public static bool ShowPopUp(string prompt, string title, string subtitle, string error, bool showbackground)
{
PopUp.Prompt=prompt;
PopUp.Title=title;
PopUp.Subtitle=subtitle;
PopUp.Error=error;
PopUp.ShowBackground=showbackground;
PopUp.Visible=true;
PopUp.Prompt = prompt;
PopUp.Title = title;
PopUp.Subtitle = subtitle;
PopUp.Error = error;
PopUp.ShowBackground = showbackground;
PopUp.Visible = true;
Script.Yield();
while (true)
{
Game.DisableAllControlsThisFrame();
MenuPool.Process();
var scaleform = Scaleform.RequestMovie("instructional_buttons");
scaleform.CallFunction("CLEAR_ALL");
scaleform.CallFunction("TOGGLE_MOUSE_BUTTONS", 0);
scaleform.CallFunction("CREATE_CONTAINER");
scaleform.CallFunction("SET_DATA_SLOT", 0, Function.Call<string>((Hash)0x0499D7B09FC9B407, 2, (int)Control.FrontendAccept, 0), "Continue");
scaleform.CallFunction("SET_DATA_SLOT", 1, Function.Call<string>((Hash)0x0499D7B09FC9B407, 2, (int)Control.FrontendCancel, 0), "Cancel");
scaleform.CallFunction("DRAW_INSTRUCTIONAL_BUTTONS", -1);
scaleform.Render2D();
if (Game.IsControlJustPressed(Control.FrontendAccept))
{
PopUp.Visible=false;
PopUp.Visible = false;
return true;
}
else if (Game.IsControlJustPressed(Control.FrontendCancel))
@ -105,6 +119,8 @@ namespace RageCoop.Client.Menus
return false;
}
Script.Yield();
Game.DisableAllControlsThisFrame();
}
}
public static void UsernameActivated(object a, System.EventArgs b)
@ -122,12 +138,9 @@ namespace RageCoop.Client.Menus
private static void _passwordActivated(object sender, System.EventArgs e)
{
string newPass = Game.GetUserInput(WindowTitle.EnterMessage20, "", 20);
if (!string.IsNullOrWhiteSpace(newPass))
{
Main.Settings.Password = newPass;
Util.SaveSettings();
_passwordItem.AltTitle = new string('*', newPass.Length);
}
Main.Settings.Password = newPass;
Util.SaveSettings();
_passwordItem.AltTitle = new string('*', newPass.Length);
}
public static void ServerIpActivated(object a, System.EventArgs b)
{

View File

@ -1,18 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LemonUI;
using LemonUI.Menus;
#if DEBUG
using GTA;
using LemonUI.Menus;
using System;
using System.Drawing;
namespace RageCoop.Client
{
internal static class DebugMenu
{
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "Debug", "Debug settings") {
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "Debug", "Debug settings")
{
UseMouse = false,
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
};
@ -21,24 +18,17 @@ namespace RageCoop.Client
UseMouse = false,
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
};
private static NativeItem d1=new NativeItem("PositionPrediction");
public static NativeItem SimulatedLatencyItem = new NativeItem("Simulated network latency", "Simulated network latency in ms (one way)", "0");
public static NativeCheckboxItem ShowOwnerItem = new NativeCheckboxItem("Show entity owner", "Show the owner name of the entity you're aiming at", false);
private static readonly NativeCheckboxItem ShowNetworkInfoItem = new NativeCheckboxItem("Show Network Info", Networking.ShowNetworkInfo);
static DebugMenu()
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
d1.Activated+=(sender,e) =>
{
try{ SyncParameters.PositioinPredictionDefault =float.Parse(Game.GetUserInput(WindowTitle.EnterMessage20, SyncParameters.PositioinPredictionDefault.ToString(), 20));}
catch { }
Update();
};
Menu.Add(d1);
Menu.AddSubMenu(DiagnosticMenu);
Menu.Opening+=(sender, e) =>Update();
DiagnosticMenu.Opening+=(sender, e) =>
DiagnosticMenu.Opening += (sender, e) =>
{
DiagnosticMenu.Clear();
DiagnosticMenu.Add(new NativeItem("EntityPool", EntityPool.DumpDebug()));
@ -47,15 +37,24 @@ namespace RageCoop.Client
DiagnosticMenu.Add(new NativeItem(pair.Key.ToString(), pair.Value.ToString(), pair.Value.ToString()));
}
};
SimulatedLatencyItem.Activated += (s, e) =>
{
try
{
SimulatedLatencyItem.AltTitle = ((Networking.SimulatedLatency = int.Parse(Game.GetUserInput(SimulatedLatencyItem.AltTitle)) * 0.002f) * 500).ToString();
}
catch (Exception ex) { Main.Logger.Error(ex); }
};
ShowNetworkInfoItem.CheckboxChanged += (s, e) => { Networking.ShowNetworkInfo = ShowNetworkInfoItem.Checked; };
ShowOwnerItem.CheckboxChanged += (s, e) => { Main.Settings.ShowEntityOwnerName = ShowOwnerItem.Checked; Util.SaveSettings(); };
Menu.Add(SimulatedLatencyItem);
Menu.Add(ShowNetworkInfoItem);
Menu.Add(ShowOwnerItem);
Menu.AddSubMenu(DiagnosticMenu);
Update();
}
private static void Update()
{
d1.AltTitle = SyncParameters.PositioinPredictionDefault.ToString();
}
}
}
#endif

View File

@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA;
using LemonUI.Menus;
using GTA;
using System;
using System.Drawing;
namespace RageCoop.Client
@ -16,9 +12,9 @@ namespace RageCoop.Client
UseMouse = false,
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
};
private static NativeCheckboxItem enableItem = new NativeCheckboxItem("Enable");
private static readonly NativeCheckboxItem enableItem = new NativeCheckboxItem("Enable");
private static NativeCheckboxItem enableSecondaryItem = new NativeCheckboxItem("Secondary","Enable if this vehicle have two muzzles");
private static readonly NativeCheckboxItem enableSecondaryItem = new NativeCheckboxItem("Secondary", "Enable if this vehicle have two muzzles");
public static NativeItem boneIndexItem = new NativeItem("Current bone index");
public static NativeItem secondaryBoneIndexItem = new NativeItem("Secondary bone index");
public static NativeItem clipboardItem = new NativeItem("Copy to clipboard");
@ -26,20 +22,20 @@ namespace RageCoop.Client
static DevToolMenu()
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
enableItem.Activated+=enableItem_Activated;
enableItem.Checked=false;
enableSecondaryItem.CheckboxChanged+=EnableSecondaryItem_Changed;
enableItem.Activated += enableItem_Activated;
enableItem.Checked = false;
enableSecondaryItem.CheckboxChanged += EnableSecondaryItem_Changed;
secondaryBoneIndexItem.Enabled=false;
clipboardItem.Activated+=ClipboardItem_Activated;
dirItem.ItemChanged+=DirItem_ItemChanged;
secondaryBoneIndexItem.Enabled = false;
clipboardItem.Activated += ClipboardItem_Activated;
dirItem.ItemChanged += DirItem_ItemChanged;
foreach (var d in Enum.GetValues(typeof(MuzzleDir)))
{
dirItem.Items.Add((MuzzleDir)d);
}
dirItem.SelectedIndex=0;
dirItem.SelectedIndex = 0;
Menu.Add(enableItem);
Menu.Add(boneIndexItem);
@ -53,19 +49,19 @@ namespace RageCoop.Client
{
if (enableSecondaryItem.Checked)
{
DevTool.UseSecondary=true;
secondaryBoneIndexItem.Enabled=true;
DevTool.UseSecondary = true;
secondaryBoneIndexItem.Enabled = true;
}
else
{
DevTool.UseSecondary=false;
secondaryBoneIndexItem.Enabled=false;
DevTool.UseSecondary = false;
secondaryBoneIndexItem.Enabled = false;
}
}
private static void DirItem_ItemChanged(object sender, ItemChangedEventArgs<MuzzleDir> e)
{
DevTool.Direction=dirItem.SelectedItem;
DevTool.Direction = dirItem.SelectedItem;
}
private static void ClipboardItem_Activated(object sender, EventArgs e)
@ -77,11 +73,11 @@ namespace RageCoop.Client
{
if (enableItem.Checked)
{
DevTool.ToMark=Game.Player.Character.CurrentVehicle;
DevTool.ToMark = Game.Player.Character.CurrentVehicle;
}
else
{
DevTool.ToMark=null;
DevTool.ToMark = null;
}
}
}

View File

@ -1,36 +1,15 @@
using System;
using System.Net;
using System.Drawing;
using System.Collections.Generic;
using Newtonsoft.Json;
using GTA.UI;
using LemonUI.Menus;
using Newtonsoft.Json;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Net;
using System.Threading;
namespace RageCoop.Client.Menus
{
internal class ServerListClass
{
[JsonProperty("address")]
public string Address { get; set; }
[JsonProperty("port")]
public string Port { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("version")]
public string Version { get; set; }
[JsonProperty("players")]
public int Players { get; set; }
[JsonProperty("maxPlayers")]
public int MaxPlayers { get; set; }
[JsonProperty("country")]
public string Country { get; set; }
}
/// <summary>
/// Don't use it!
@ -51,7 +30,7 @@ namespace RageCoop.Client.Menus
static ServersMenu()
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
Menu.Opening += (object sender, System.ComponentModel.CancelEventArgs e) =>
{
@ -59,7 +38,7 @@ namespace RageCoop.Client.Menus
Menu.Add(ResultItem = new NativeItem("Loading..."));
// Prevent freezing
GetServersThread=new Thread(()=> GetAllServers());
GetServersThread = new Thread(() => GetAllServers());
GetServersThread.Start();
};
Menu.Closing += (object sender, System.ComponentModel.CancelEventArgs e) =>
@ -76,10 +55,10 @@ namespace RageCoop.Client.Menus
private static void GetAllServers()
{
List<ServerListClass> serverList = null;
List<ServerInfo> serverList = null;
var realUrl = Main.Settings.MasterServer;
serverList = JsonConvert.DeserializeObject<List<ServerListClass>>(DownloadString(realUrl));
serverList = JsonConvert.DeserializeObject<List<ServerInfo>>(DownloadString(realUrl));
// Need to be processed in main thread
Main.QueueAction(() =>
{
@ -94,17 +73,25 @@ namespace RageCoop.Client.Menus
return;
}
CleanUpList();
foreach (ServerListClass server in serverList)
foreach (ServerInfo server in serverList)
{
string address = $"{server.Address}:{server.Port}";
NativeItem tmpItem = new NativeItem($"[{server.Country}] {server.Name}", $"~b~{address}~s~~n~~g~Version {server.Version}.x~s~") { AltTitle = $"[{server.Players}/{server.MaxPlayers}]" };
string address = $"{server.address}:{server.port}";
NativeItem tmpItem = new NativeItem($"[{server.country}] {server.name}", $"~b~{address}~s~~n~~g~Version {server.version}~s~") { AltTitle = $"[{server.players}/{server.maxPlayers}]" };
tmpItem.Activated += (object sender, EventArgs e) =>
{
try
{
Menu.Visible = false;
Networking.ToggleConnection(address);
if (server.useZT)
{
address = $"{server.ztAddress}:{server.port}";
Notification.PostTicker($"~y~Joining ZeroTier network... {server.ztID}", false);
if (ZeroTierHelper.Join(server.ztID) == null)
{
throw new Exception("Failed to obtain ZeroTier network IP");
}
}
Networking.ToggleConnection(address, null, null, PublicKey.FromServerInfo(server));
#if !NON_INTERACTIVE
CoopMenu.ServerIpItem.AltTitle = address;
@ -115,7 +102,11 @@ namespace RageCoop.Client.Menus
}
catch (Exception ex)
{
GTA.UI.Notification.Show($"~r~{ex.Message}");
Notification.PostTicker($"~r~{ex.Message}", false);
if (server.useZT)
{
Notification.PostTicker($"Make sure ZeroTier is correctly installed, download it from https://www.zerotier.com/", false);
}
}
};
Menu.Add(tmpItem);

View File

@ -1,14 +1,11 @@
using System.Drawing;
using System;
using System.Windows.Forms;
using GTA;
using GTA;
using LemonUI.Menus;
using System;
using System.Drawing;
using System.Windows.Forms;
namespace RageCoop.Client.Menus
{
/// <summary>
/// Don't use it!
/// </summary>
internal static class SettingsMenu
{
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "Settings", "Go to the settings")
@ -19,54 +16,95 @@ namespace RageCoop.Client.Menus
private static readonly NativeCheckboxItem _disableTrafficItem = new NativeCheckboxItem("Disable Traffic (NPCs/Vehicles)", "Local traffic only", Main.Settings.DisableTraffic);
private static readonly NativeCheckboxItem _flipMenuItem = new NativeCheckboxItem("Flip menu", Main.Settings.FlipMenu);
private static readonly NativeCheckboxItem _disablePauseAlt = new NativeCheckboxItem("Disable Alternate Pause", "Don't freeze game time when Esc pressed", Main.Settings.DisableTraffic);
private static readonly NativeCheckboxItem _disablePauseAlt = new NativeCheckboxItem("Disable Alternate Pause", "Don't freeze game time when Esc pressed", Main.Settings.DisableAlternatePause);
private static readonly NativeCheckboxItem _showBlip = new NativeCheckboxItem("Show player blip", "Show other player's blip on map", Main.Settings.ShowPlayerBlip);
private static readonly NativeCheckboxItem _showNametag = new NativeCheckboxItem("Show player nametag", "Show other player's nametag on your screen", Main.Settings.ShowPlayerNameTag);
private static readonly NativeCheckboxItem _disableVoice = new NativeCheckboxItem("Enable voice", "Check your GTA:V settings to find the right key on your keyboard for PushToTalk and talk to your friends", Main.Settings.Voice);
private static readonly NativeCheckboxItem _showNetworkInfoItem = new NativeCheckboxItem("Show Network Info", Networking.ShowNetworkInfo);
private static NativeItem _menuKey = new NativeItem("Menu Key","The key to open menu", Main.Settings.MenuKey.ToString());
private static NativeItem _passengerKey = new NativeItem("Passenger Key", "The key to enter a vehicle as passenger", Main.Settings.PassengerKey.ToString());
private static NativeItem _vehicleSoftLimit = new NativeItem("Vehicle limit (soft)", "The game won't spawn more NPC traffic if the limit is exceeded. \n-1 for unlimited (not recommended).",Main.Settings.WorldVehicleSoftLimit.ToString());
private static readonly NativeItem _menuKey = new NativeItem("Menu Key", "The key to open menu", Main.Settings.MenuKey.ToString());
private static readonly NativeItem _passengerKey = new NativeItem("Passenger Key", "The key to enter a vehicle as passenger", Main.Settings.PassengerKey.ToString());
private static readonly NativeItem _vehicleSoftLimit = new NativeItem("Vehicle limit (soft)", "The game won't spawn more NPC traffic if the limit is exceeded. \n-1 for unlimited (not recommended).", Main.Settings.WorldVehicleSoftLimit.ToString());
private static readonly NativeItem _pedSoftLimit = new NativeItem("Ped limit (soft)", "The game won't spawn more NPCs if the limit is exceeded. \n-1 for unlimited (not recommended).", Main.Settings.WorldPedSoftLimit.ToString());
/// <summary>
/// Don't use it!
/// </summary>
static SettingsMenu()
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
_disableTrafficItem.CheckboxChanged += DisableTrafficCheckboxChanged;
_disablePauseAlt.CheckboxChanged+=_disablePauseAlt_CheckboxChanged;
_disablePauseAlt.CheckboxChanged += DisablePauseAltCheckboxChanged;
_disableVoice.CheckboxChanged += DisableVoiceCheckboxChanged;
_flipMenuItem.CheckboxChanged += FlipMenuCheckboxChanged;
_showNetworkInfoItem.CheckboxChanged += ShowNetworkInfoCheckboxChanged;
_menuKey.Activated+=ChaneMenuKey;
_passengerKey.Activated+=ChangePassengerKey;
_vehicleSoftLimit.Activated+=vehicleSoftLimit_Activated;
_menuKey.Activated += ChaneMenuKey;
_passengerKey.Activated += ChangePassengerKey;
_vehicleSoftLimit.Activated += VehicleSoftLimitActivated;
_pedSoftLimit.Activated += PedSoftLimitActivated;
_showBlip.Activated += (s, e) =>
{
Main.Settings.ShowPlayerBlip = _showBlip.Checked;
Util.SaveSettings();
};
_showNametag.Activated += (s, e) =>
{
Main.Settings.ShowPlayerNameTag = _showNametag.Checked;
Util.SaveSettings();
};
Menu.Add(_disableTrafficItem);
Menu.Add(_disablePauseAlt);
Menu.Add(_flipMenuItem);
Menu.Add(_showNetworkInfoItem);
Menu.Add(_disableVoice);
Menu.Add(_menuKey);
Menu.Add(_passengerKey);
Menu.Add(_vehicleSoftLimit);
Menu.Add(_pedSoftLimit);
Menu.Add(_showBlip);
Menu.Add(_showNametag);
}
private static void _disablePauseAlt_CheckboxChanged(object sender, EventArgs e)
private static void DisableVoiceCheckboxChanged(object sender, EventArgs e)
{
Main.Settings.DisableAlternatePause=_disablePauseAlt.Checked;
if (_disableVoice.Checked)
{
if (Networking.IsOnServer && !Voice.WasInitialized())
{
Voice.Init();
}
}
else
{
Voice.ClearAll();
}
Main.Settings.Voice = _disableVoice.Checked;
Util.SaveSettings();
}
private static void vehicleSoftLimit_Activated(object sender, EventArgs e)
private static void DisablePauseAltCheckboxChanged(object sender, EventArgs e)
{
Main.Settings.DisableAlternatePause = _disablePauseAlt.Checked;
Util.SaveSettings();
}
private static void VehicleSoftLimitActivated(object sender, EventArgs e)
{
try
{
Main.Settings.WorldVehicleSoftLimit =int.Parse(
Main.Settings.WorldVehicleSoftLimit = int.Parse(
Game.GetUserInput(WindowTitle.EnterMessage20,
Main.Settings.WorldVehicleSoftLimit.ToString(), 20));
_menuKey.AltTitle=Main.Settings.WorldVehicleSoftLimit.ToString();
_vehicleSoftLimit.AltTitle = Main.Settings.WorldVehicleSoftLimit.ToString();
Util.SaveSettings();
}
catch { }
}
private static void PedSoftLimitActivated(object sender, EventArgs e)
{
try
{
Main.Settings.WorldPedSoftLimit = int.Parse(
Game.GetUserInput(WindowTitle.EnterMessage20,
Main.Settings.WorldPedSoftLimit.ToString(), 20));
_pedSoftLimit.AltTitle = Main.Settings.WorldPedSoftLimit.ToString();
Util.SaveSettings();
}
catch { }
@ -75,11 +113,11 @@ namespace RageCoop.Client.Menus
{
try
{
Main.Settings.MenuKey =(Keys)Enum.Parse(
Main.Settings.MenuKey = (Keys)Enum.Parse(
typeof(Keys),
Game.GetUserInput(WindowTitle.EnterMessage20,
Main.Settings.MenuKey.ToString(), 20));
_menuKey.AltTitle=Main.Settings.MenuKey.ToString();
_menuKey.AltTitle = Main.Settings.MenuKey.ToString();
Util.SaveSettings();
}
catch { }
@ -89,11 +127,11 @@ namespace RageCoop.Client.Menus
{
try
{
Main.Settings.PassengerKey =(Keys)Enum.Parse(
Main.Settings.PassengerKey = (Keys)Enum.Parse(
typeof(Keys),
Game.GetUserInput(WindowTitle.EnterMessage20,
Main.Settings.PassengerKey.ToString(), 20));
_passengerKey.AltTitle=Main.Settings.PassengerKey.ToString();
_passengerKey.AltTitle = Main.Settings.PassengerKey.ToString();
Util.SaveSettings();
}
catch { }
@ -101,8 +139,9 @@ namespace RageCoop.Client.Menus
public static void DisableTrafficCheckboxChanged(object a, System.EventArgs b)
{
WorldThread.Traffic(!_disableTrafficItem.Checked);
Main.Settings.DisableTraffic = _disableTrafficItem.Checked;
Util.SaveSettings() ;
Util.SaveSettings();
}
public static void FlipMenuCheckboxChanged(object a, System.EventArgs b)
@ -113,11 +152,5 @@ namespace RageCoop.Client.Menus
Main.Settings.FlipMenu = _flipMenuItem.Checked;
Util.SaveSettings();
}
public static void ShowNetworkInfoCheckboxChanged(object a, System.EventArgs b)
{
Networking.ShowNetworkInfo = _showNetworkInfoItem.Checked;
}
}
}

View File

@ -1,10 +1,9 @@
using System;
using GTA;
using GTA.Native;
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using RageCoop.Core;
using GTA;
using GTA.Native;
namespace RageCoop.Client
{
@ -17,7 +16,7 @@ namespace RageCoop.Client
private bool CurrentFocused { get; set; }
public bool Focused
{
get { return CurrentFocused; }
get => CurrentFocused;
set
{
if (value && Hidden)
@ -32,11 +31,12 @@ namespace RageCoop.Client
}
private ulong LastMessageTime { get; set; }
private Keys LastKey { get; set; }
private bool CurrentHidden { get; set; }
private bool Hidden
{
get { return CurrentHidden; }
get => CurrentHidden;
set
{
if (value)
@ -57,7 +57,7 @@ namespace RageCoop.Client
public Chat()
{
MainScaleForm = new Scaleform("multiplayer_chat");
MainScaleForm = Scaleform.RequestMovie("multiplayer_chat");
}
public void Init()
@ -106,7 +106,7 @@ namespace RageCoop.Client
CurrentInput = "";
return;
}
if (key == Keys.PageUp)
{
MainScaleForm.CallFunction("PAGE_UP");
@ -116,6 +116,10 @@ namespace RageCoop.Client
MainScaleForm.CallFunction("PAGE_DOWN");
}
if (key == Keys.Menu && LastKey == Keys.ShiftKey)
ActivateKeyboardLayout(1, 0);
LastKey = key;
string keyChar = GetCharFromKey(key, Game.IsKeyPressed(Keys.ShiftKey), false);
if (keyChar.Length == 0)
@ -175,5 +179,8 @@ namespace RageCoop.Client
ToUnicodeEx((uint)key, 0, keyboardState, buf, 256, 0, InputLanguage.CurrentInputLanguage.Handle);
return buf.ToString();
}
[DllImport("user32.dll")]
public static extern int ActivateKeyboardLayout(int hkl, uint flags);
}
}

View File

@ -1,33 +1,34 @@
using System.IO;
using System.Linq;
using System.Collections.Generic;
using RageCoop.Core;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace RageCoop.Client
{
internal static class DownloadManager
{
public static event EventHandler<string> DownloadCompleted;
static DownloadManager()
{
Networking.RequestHandlers.Add(PacketType.FileTransferRequest, (data) =>
{
var fr = new Packets.FileTransferRequest();
fr.Unpack(data);
if (fr.Name.EndsWith(".zip"))
fr.Deserialize(data);
if (fr.Name.EndsWith(".res"))
{
_zips.Add(fr.Name);
_resources.Add(fr.Name);
}
return new Packets.FileTransferResponse()
{
ID= fr.ID,
Response=AddFile(fr.ID,fr.Name,fr.FileLength) ? FileResponse.NeedToDownload : FileResponse.AlreadyExists
ID = fr.ID,
Response = AddFile(fr.ID, fr.Name, fr.FileLength) ? FileResponse.NeedToDownload : FileResponse.AlreadyExists
};
});
Networking.RequestHandlers.Add(PacketType.FileTransferComplete, (data) =>
{
Packets.FileTransferComplete packet = new Packets.FileTransferComplete();
packet.Unpack(data);
packet.Deserialize(data);
Main.Logger.Debug($"Finalizing download:{packet.ID}");
Complete(packet.ID);
@ -35,52 +36,50 @@ namespace RageCoop.Client
// Inform the server that the download is completed
return new Packets.FileTransferResponse()
{
ID= packet.ID,
Response=FileResponse.Completed
ID = packet.ID,
Response = FileResponse.Completed
};
});
Networking.RequestHandlers.Add(PacketType.AllResourcesSent, (data) =>
{
try
{
Main.Resources.Load(ResourceFolder,_zips.ToArray());
return new Packets.FileTransferResponse() { ID=0, Response=FileResponse.Loaded };
Main.Resources.Load(ResourceFolder, _resources.ToArray());
return new Packets.FileTransferResponse() { ID = 0, Response = FileResponse.Loaded };
}
catch(Exception ex)
catch (Exception ex)
{
Main.Logger.Error("Error occurred when loading server resource:");
Main.Logger.Error(ex);
return new Packets.FileTransferResponse() { ID=0, Response=FileResponse.LoadFailed };
return new Packets.FileTransferResponse() { ID = 0, Response = FileResponse.LoadFailed };
}
});
}
public static string ResourceFolder {
get {
return Path.Combine(Main.Settings.DataDirectory,"Resources", Main.Settings.LastServerAddress.Replace(":", "."));
}
}
public static string ResourceFolder => Path.GetFullPath(Path.Combine(Main.Settings.DataDirectory, "Resources", Main.Settings.LastServerAddress.Replace(":", ".")));
private static readonly Dictionary<int, DownloadFile> InProgressDownloads = new Dictionary<int, DownloadFile>();
private static readonly List<string> _zips = new List<string>();
private static readonly HashSet<string> _resources = new HashSet<string>();
public static bool AddFile(int id, string name, long length)
{
Main.Logger.Debug($"Downloading file to {ResourceFolder}\\{name} , id:{id}");
if (!Directory.Exists(ResourceFolder))
var path = $"{ResourceFolder}\\{name}";
Main.Logger.Debug($"Downloading file to {path} , id:{id}");
if (!Directory.Exists(Directory.GetParent(path).FullName))
{
Directory.CreateDirectory(ResourceFolder);
Directory.CreateDirectory(Directory.GetParent(path).FullName);
}
if (FileAlreadyExists(ResourceFolder, name, length))
{
Main.Logger.Debug($"File already exists! canceling download:{name}");
DownloadCompleted?.Invoke(null, Path.Combine(ResourceFolder, name));
return false;
}
/*
if (!name.EndsWith(".zip"))
{
Main.Logger.Error($"File download blocked! [{name}]");
return false;
}
*/
lock (InProgressDownloads)
{
InProgressDownloads.Add(id, new DownloadFile()
@ -88,7 +87,7 @@ namespace RageCoop.Client
FileID = id,
FileName = name,
FileLength = length,
Stream = new FileStream($"{ResourceFolder}\\{name}", FileMode.CreateNew, FileAccess.Write, FileShare.ReadWrite)
Stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.ReadWrite)
});
}
return true;
@ -123,8 +122,7 @@ namespace RageCoop.Client
{
lock (InProgressDownloads)
{
DownloadFile file;
if (InProgressDownloads.TryGetValue(id, out file))
if (InProgressDownloads.TryGetValue(id, out DownloadFile file))
{
file.Stream.Write(chunk, 0, chunk.Length);
@ -134,22 +132,17 @@ namespace RageCoop.Client
Main.Logger.Trace($"Received unhandled file chunk:{id}");
}
}
}
public static void Complete(int id)
{
DownloadFile f;
if (InProgressDownloads.TryGetValue(id, out f))
if (InProgressDownloads.TryGetValue(id, out DownloadFile f))
{
InProgressDownloads.Remove(id);
f.Dispose();
if (f.FileName.EndsWith(".zip"))
{
_zips.Add(f.FileName);
}
Main.Logger.Info($"Download finished:{f.FileName}");
DownloadCompleted?.Invoke(null, Path.Combine(ResourceFolder, f.FileName));
}
else
{
@ -167,20 +160,12 @@ namespace RageCoop.Client
}
InProgressDownloads.Clear();
}
if (Directory.Exists(ResourceFolder))
{
foreach (var zip in Directory.GetDirectories(ResourceFolder, "*.zip"))
{
File.Delete(zip);
}
}
_zips.Clear();
_resources.Clear();
}
}
internal class DownloadFile: System.IDisposable
internal class DownloadFile : IDisposable
{
public int FileID { get; set; } = 0;
public string FileName { get; set; } = string.Empty;
@ -189,7 +174,7 @@ namespace RageCoop.Client
public FileStream Stream { get; set; }
public void Dispose()
{
if(Stream!= null)
if (Stream != null)
{
Stream.Flush();
Stream.Close();

View File

@ -0,0 +1,83 @@
using Lidgren.Network;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Timers;
namespace RageCoop.Client
{
internal static partial class HolePunch
{
static HolePunch()
{
// Periodically send hole punch message as needed
var timer = new Timer(1000);
timer.Elapsed += DoPunch;
timer.Enabled = true;
}
private static void DoPunch(object sender, ElapsedEventArgs e)
{
try
{
if (!Networking.IsOnServer) { return; }
foreach (var p in PlayerList.Players.Values.ToArray())
{
if (p.InternalEndPoint != null && p.ExternalEndPoint != null && (p.Connection == null || p.Connection.Status == NetConnectionStatus.Disconnected))
{
Main.Logger.Trace($"Sending HolePunch message to {p.InternalEndPoint},{p.ExternalEndPoint}. {p.Username}:{p.ID}");
var msg = Networking.Peer.CreateMessage();
new Packets.HolePunch
{
Puncher = Main.LocalPlayerID,
Status = p.HolePunchStatus
}.Pack(msg);
Networking.Peer.SendUnconnectedMessage(msg, new List<IPEndPoint> { p.InternalEndPoint, p.ExternalEndPoint });
}
}
}
catch (Exception ex)
{
Main.Logger.Error(ex);
}
}
public static void Add(Packets.HolePunchInit p)
{
if (PlayerList.Players.TryGetValue(p.TargetID, out var player))
{
Main.Logger.Debug($"{p.TargetID},{player.Username} added to HolePunch target");
player.InternalEndPoint = CoreUtils.StringToEndPoint(p.TargetInternal);
player.ExternalEndPoint = CoreUtils.StringToEndPoint(p.TargetExternal);
player.ConnectWhenPunched = p.Connect;
}
else
{
Main.Logger.Warning("No player with specified TargetID found for hole punching:" + p.TargetID);
}
}
public static void Punched(Packets.HolePunch p, IPEndPoint from)
{
Main.Logger.Debug($"HolePunch message received from:{from}, status:{p.Status}");
if (PlayerList.Players.TryGetValue(p.Puncher, out var puncher))
{
Main.Logger.Debug("Puncher identified as: " + puncher.Username);
puncher.HolePunchStatus = (byte)(p.Status + 1);
if (p.Status >= 3)
{
Main.Logger.Debug("HolePunch sucess: " + from + ", " + puncher.ID);
if (puncher.ConnectWhenPunched && (puncher.Connection == null || puncher.Connection.Status == NetConnectionStatus.Disconnected))
{
Main.Logger.Debug("Connecting to peer: " + from);
var msg = Networking.Peer.CreateMessage();
new Packets.P2PConnect { ID = Main.LocalPlayerID }.Pack(msg);
puncher.Connection = Networking.Peer.Connect(from, msg);
Networking.Peer.FlushSendQueue();
}
}
}
}
}
}

View File

@ -1,57 +1,68 @@
using System;
using GTA.UI;
using Lidgren.Network;
using RageCoop.Core;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Net;
using System.Security.Cryptography;
using System.Threading;
using System.IO;
using System.Threading.Tasks;
namespace RageCoop.Client
{
internal static partial class Networking
{
public static NetClient Client;
public static float Latency = 0;
public static CoopPeer Peer;
public static float Latency => ServerConnection.AverageRoundtripTime / 2;
public static bool ShowNetworkInfo = false;
public static Security Security;
public static NetConnection ServerConnection;
private static readonly Dictionary<int, Action<PacketType, NetIncomingMessage>> PendingResponses = new Dictionary<int, Action<PacketType, NetIncomingMessage>>();
internal static readonly Dictionary<PacketType, Func<NetIncomingMessage, Packet>> RequestHandlers = new Dictionary<PacketType, Func<NetIncomingMessage, Packet>>();
internal static float SimulatedLatency = 0;
public static bool IsConnecting { get; private set; }
public static IPEndPoint _targetServerEP;
static Networking()
{
Security=new Security(Main.Logger);
Task.Run(() =>
{
while (true)
{
if (Client!=null)
{
ProcessMessage(Client.WaitMessage(200));
Client.FlushSendQueue();
}
else
{
Thread.Sleep(20);
}
}
});
Security = new Security(Main.Logger);
}
public static void ToggleConnection(string address,string username=null,string password=null)
public static void ToggleConnection(string address, string username = null, string password = null, PublicKey publicKey = null)
{
if (IsOnServer)
Menus.CoopMenu.Menu.Visible = false;
if (IsConnecting)
{
Client.Disconnect("Bye!");
_publicKeyReceived.Set();
IsConnecting = false;
Main.QueueAction(() => Notification.PostTicker("Connection has been canceled", false));
Peer?.Shutdown("Bye");
}
else if (IsOnServer)
{
Peer?.Shutdown("Bye");
}
else
{
Peer?.Dispose();
IsConnecting = true;
password = password ?? Main.Settings.Password;
username=username ?? Main.Settings.Username;
username = username ?? Main.Settings.Username;
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
{
AutoFlushSendQueue = true
AutoFlushSendQueue = false,
AcceptIncomingConnections = true,
MaximumConnections = 32,
PingInterval = 5
};
config.EnableMessageType(NetIncomingMessageType.ConnectionLatencyUpdated);
#if DEBUG
config.SimulatedMinimumLatency = SimulatedLatency;
config.SimulatedRandomLatency = 0;
#endif
config.EnableMessageType(NetIncomingMessageType.UnconnectedData);
config.EnableMessageType(NetIncomingMessageType.NatIntroductionSuccess);
string[] ip = new string[2];
@ -67,87 +78,144 @@ namespace RageCoop.Client
throw new Exception("Malformed URL");
}
PlayerList.Cleanup();
EntityPool.AddPlayer();
if (publicKey == null && !string.IsNullOrEmpty(password) && !Menus.CoopMenu.ShowPopUp("", "WARNING", "Server's IP can be spoofed when using direct connection, do you wish to continue?", "", true))
{
IsConnecting = false;
return;
}
Task.Run(() =>
{
try
{
_targetServerEP = CoreUtils.StringToEndPoint(address);
// Ensure static constructor invocation
DownloadManager.Cleanup();
Client = new NetClient(config);
Client.Start();
Main.QueueAction(() => { GTA.UI.Notification.Show($"~y~Trying to connect..."); });
Menus.CoopMenu._serverConnectItem.Enabled=false;
Security.Regen();
if(!GetServerPublicKey(address))
Peer = new CoopPeer(config);
Peer.OnMessageReceived += (s, m) =>
{
Menus.CoopMenu._serverConnectItem.Enabled=true;
throw new TimeoutException("Failed to retrive server's public key");
try { ProcessMessage(m); }
catch (Exception ex)
{
#if DEBUG
Main.Logger.Error(ex);
#endif
}
};
Main.QueueAction(() => { Notification.PostTicker($"~y~Trying to connect...", false); });
Menus.CoopMenu._serverConnectItem.Enabled = false;
Security.Regen();
if (publicKey == null)
{
if (!GetServerPublicKey(ip[0], int.Parse(ip[1])))
{
Menus.CoopMenu._serverConnectItem.Enabled = true;
throw new TimeoutException("Failed to retrive server's public key");
}
}
// Send HandshakePacket
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
else
{
Security.SetServerPublicKey(publicKey.Modulus, publicKey.Exponent);
}
// Send handshake packet
NetOutgoingMessage outgoingMessage = Peer.CreateMessage();
var handshake = new Packets.Handshake()
{
PedID = Main.LocalPlayerID,
Username =username,
ModVersion = Main.CurrentVersion,
PassHashEncrypted=Security.Encrypt(password.GetHash())
PedID = Main.LocalPlayerID,
Username = username,
ModVersion = Main.Version.ToString(),
PasswordEncrypted = Security.Encrypt(password.GetBytes()),
InternalEndPoint = new System.Net.IPEndPoint(CoreUtils.GetLocalAddress(ip[0]), Peer.Port)
};
Security.GetSymmetricKeysCrypted(out handshake.AesKeyCrypted, out handshake.AesIVCrypted);
handshake.Pack(outgoingMessage);
Client.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
ServerConnection = Peer.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
}
catch(Exception ex)
catch (Exception ex)
{
Main.Logger.Error("Cannot connect to server: ", ex);
Main.QueueAction(() => GTA.UI.Notification.Show("Cannot connect to server: "+ex.Message));
Main.QueueAction(() => Notification.PostTicker("Cannot connect to server: " + ex.Message, false));
}
IsConnecting = false;
});
}
}
public static bool IsOnServer
{
get { return Client?.ConnectionStatus == NetConnectionStatus.Connected; }
}
#region -- GET --
public static bool IsOnServer { get => ServerConnection?.Status == NetConnectionStatus.Connected; }
#region -- PLAYER --
private static void PlayerConnect(Packets.PlayerConnect packet)
{
var p = new PlayerData
var p = new Player
{
PedID = packet.PedID,
Username= packet.Username,
ID = packet.PedID,
Username = packet.Username,
};
GTA.UI.Notification.Show($"{p.Username} connected.");
PlayerList.SetPlayer(packet.PedID, packet.Username);
Main.Logger.Debug($"player connected:{p.Username}");
Main.QueueAction(() =>
Notification.PostTicker($"~h~{p.Username}~h~ connected.", false));
}
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
{
var name=PlayerList.GetPlayer(packet.PedID).Username;
GTA.UI.Notification.Show($"{name} left.");
var player = PlayerList.GetPlayer(packet.PedID);
if (player == null) { return; }
PlayerList.RemovePlayer(packet.PedID);
EntityPool.RemoveAllFromPlayer(packet.PedID);
Main.QueueAction(() =>
{
EntityPool.RemoveAllFromPlayer(packet.PedID);
Notification.PostTicker($"~h~{player.Username}~h~ left.", false);
});
}
#endregion // -- PLAYER --
private static bool GetServerPublicKey(string address,int timeout=10000)
#region -- GET --
private static bool GetServerPublicKey(string host, int port, int timeout = 10000)
{
var msg=Client.CreateMessage();
new Packets.PublicKeyRequest().Pack(msg);
var adds =address.Split(':');
Client.SendUnconnectedMessage(msg,adds[0],int.Parse(adds[1]));
return PublicKeyReceived.WaitOne(timeout);
Security.ServerRSA = null;
var msg = Peer.CreateMessage();
new Packets.PublicKeyRequest().Pack(msg);
Peer.SendUnconnectedMessage(msg, host, port);
return _publicKeyReceived.WaitOne(timeout) && Security.ServerRSA != null;
}
public static void GetResponse<T>(Packet request, Action<T> callback, ConnectionChannel channel = ConnectionChannel.RequestResponse) where T : Packet, new()
{
var received = new AutoResetEvent(false);
var id = NewRequestID();
PendingResponses.Add(id, (type, p) =>
{
var result = new T();
result.Deserialize(p);
callback(result);
});
var msg = Peer.CreateMessage();
msg.Write((byte)PacketType.Request);
msg.Write(id);
request.Pack(msg);
Peer.SendMessage(msg, ServerConnection, NetDeliveryMethod.ReliableOrdered, (int)channel);
}
#endregion
private static int NewRequestID()
{
int ID = 0;
while ((ID == 0) || PendingResponses.ContainsKey(ID))
{
byte[] rngBytes = new byte[4];
RandomNumberGenerator.Create().GetBytes(rngBytes);
// Convert the bytes into an integer
ID = BitConverter.ToInt32(rngBytes, 0);
}
return ID;
}
}
}

View File

@ -1,101 +1,112 @@
using System;
using System.Collections.Generic;
using GTA;
using Lidgren.Network;
using RageCoop.Core;
using GTA;
using RageCoop.Client.Menus;
using RageCoop.Core;
using System;
using System.Linq;
using System.Threading;
namespace RageCoop.Client
{
internal static partial class Networking
{
private static Func<byte, BitReader, object> _resolveHandle = (t, reader) =>
/// <summary>
/// Reduce GC pressure by reusing frequently used packets
/// </summary>
private static class ReceivedPackets
{
public static Packets.PedSync PedPacket = new Packets.PedSync();
public static Packets.VehicleSync VehicelPacket = new Packets.VehicleSync();
public static Packets.ProjectileSync ProjectilePacket = new Packets.ProjectileSync();
}
/// <summary>
/// Used to reslove entity handle in a <see cref="Packets.CustomEvent"/>
/// </summary>
private static readonly Func<byte, NetIncomingMessage, object> _resolveHandle = (t, reader) =>
{
switch (t)
{
case 50:
return EntityPool.ServerProps[reader.ReadInt()].MainProp?.Handle;
return EntityPool.ServerProps[reader.ReadInt32()].MainProp?.Handle;
case 51:
return EntityPool.GetPedByID(reader.ReadInt())?.MainPed?.Handle;
return EntityPool.GetPedByID(reader.ReadInt32())?.MainPed?.Handle;
case 52:
return EntityPool.GetVehicleByID(reader.ReadInt())?.MainVehicle?.Handle;
return EntityPool.GetVehicleByID(reader.ReadInt32())?.MainVehicle?.Handle;
case 60:
return EntityPool.ServerBlips[reader.ReadInt()].Handle;
return EntityPool.ServerBlips[reader.ReadInt32()].Handle;
default:
throw new ArgumentException("Cannot resolve server side argument: "+t);
throw new ArgumentException("Cannot resolve server side argument: " + t);
}
};
private static AutoResetEvent PublicKeyReceived=new AutoResetEvent(false);
private static Dictionary<int, Action<PacketType, byte[]>> PendingResponses = new Dictionary<int, Action<PacketType, byte[]>>();
internal static Dictionary<PacketType, Func< byte[], Packet>> RequestHandlers = new Dictionary<PacketType, Func< byte[], Packet>>();
private static readonly AutoResetEvent _publicKeyReceived = new AutoResetEvent(false);
private static bool _recycle;
public static void ProcessMessage(NetIncomingMessage message)
{
if(message == null) { return; }
if (message == null) { return; }
_recycle = true;
switch (message.MessageType)
{
case NetIncomingMessageType.StatusChanged:
NetConnectionStatus status = (NetConnectionStatus)message.ReadByte();
string reason = message.ReadString();
switch (status)
{
case NetConnectionStatus.InitiatedConnect:
#if !NON_INTERACTIVE
CoopMenu.InitiateConnectionMenuSetting();
#endif
if (message.SenderConnection == ServerConnection)
{
CoopMenu.InitiateConnectionMenuSetting();
}
break;
case NetConnectionStatus.Connected:
Main.QueueAction(() => {
CoopMenu.ConnectedMenuSetting();
Main.MainChat.Init();
PlayerList.Cleanup();
GTA.UI.Notification.Show("~g~Connected!");
});
if (message.SenderConnection == ServerConnection)
{
var response = message.SenderConnection.RemoteHailMessage;
if ((PacketType)response.ReadByte() != PacketType.HandshakeSuccess)
{
throw new Exception("Invalid handshake response!");
}
var p = new Packets.HandshakeSuccess();
p.Deserialize(response);
foreach (var player in p.Players)
{
PlayerList.SetPlayer(player.ID, player.Username);
}
Main.Connected();
}
else
{
// Self-initiated connection
if (message.SenderConnection.RemoteHailMessage == null) { return; }
Main.Logger.Info(">> Connected <<");
var p = message.SenderConnection.RemoteHailMessage.GetPacket<Packets.P2PConnect>();
if (PlayerList.Players.TryGetValue(p.ID, out var player))
{
player.Connection = message.SenderConnection;
Main.Logger.Debug($"Direct connection to {player.Username} established");
}
else
{
Main.Logger.Info($"Unidentified peer connection from {message.SenderEndPoint} was rejected.");
message.SenderConnection.Disconnect("eat poop");
}
}
break;
case NetConnectionStatus.Disconnected:
DownloadManager.Cleanup();
// Reset all values
Latency = 0;
Main.QueueAction(() => Main.CleanUpWorld());
if (Main.MainChat.Focused)
if (message.SenderConnection == ServerConnection)
{
Main.MainChat.Focused = false;
Main.Disconnected(reason);
}
Main.QueueAction(() => Main.CleanUp());
#if !NON_INTERACTIVE
CoopMenu.DisconnectedMenuSetting();
#endif
Main.QueueAction(() =>
GTA.UI.Notification.Show("~r~Disconnected: " + reason));
Main.Resources.Unload();
Main.Logger.Info($">> Disconnected << reason: {reason}");
break;
}
break;
case NetIncomingMessageType.Data:
{
if (message.LengthBytes==0) { break; }
if (message.LengthBytes == 0) { break; }
var packetType = PacketType.Unknown;
try
{
// Get packet type
packetType = (PacketType)message.ReadByte();
switch (packetType)
@ -105,7 +116,7 @@ namespace RageCoop.Client
int id = message.ReadInt32();
if (PendingResponses.TryGetValue(id, out var callback))
{
callback((PacketType)message.ReadByte(), message.ReadBytes(message.ReadInt32()));
callback((PacketType)message.ReadByte(), message);
PendingResponses.Remove(id);
}
break;
@ -114,184 +125,177 @@ namespace RageCoop.Client
{
int id = message.ReadInt32();
var realType = (PacketType)message.ReadByte();
int len = message.ReadInt32();
Main.Logger.Debug($"{id},{realType},{len}");
if (RequestHandlers.TryGetValue(realType, out var handler))
{
var response = Client.CreateMessage();
var response = Peer.CreateMessage();
response.Write((byte)PacketType.Response);
response.Write(id);
handler(message.ReadBytes(len)).Pack(response);
Client.SendMessage(response, NetDeliveryMethod.ReliableOrdered);
handler(message).Pack(response);
Peer.SendMessage(response, ServerConnection, NetDeliveryMethod.ReliableOrdered, message.SequenceChannel);
Peer.FlushSendQueue();
}
else
{
Main.Logger.Debug("Did not find a request handler of type: " + realType);
}
break;
}
default:
{
byte[] data = message.ReadBytes(message.ReadInt32());
HandlePacket(packetType, data);
HandlePacket(packetType, message, message.SenderConnection, ref _recycle);
break;
}
}
}
catch (Exception ex)
{
Main.QueueAction(() => {
GTA.UI.Notification.Show("~r~~h~Packet Error");
#if DEBUG
Main.QueueAction(() =>
{
GTA.UI.Notification.Show($"~r~~h~Packet Error {ex.Message}");
return true;
});
Main.Logger.Error($"[{packetType}] {ex.Message}");
Main.Logger.Error(ex);
Client.Disconnect($"Packet Error [{packetType}]");
Peer.Shutdown($"Packet Error [{packetType}]");
#endif
_recycle = false;
}
break;
}
case NetIncomingMessageType.ConnectionLatencyUpdated:
Latency = message.ReadFloat();
break;
case NetIncomingMessageType.UnconnectedData:
{
var packetType = (PacketType)message.ReadByte();
int len = message.ReadInt32();
byte[] data = message.ReadBytes(len);
if (packetType==PacketType.PublicKeyResponse)
switch (packetType)
{
var packet=new Packets.PublicKeyResponse();
packet.Unpack(data);
Security.SetServerPublicKey(packet.Modulus,packet.Exponent);
PublicKeyReceived.Set();
case PacketType.HolePunch:
{
HolePunch.Punched(message.GetPacket<Packets.HolePunch>(), message.SenderEndPoint);
break;
}
case PacketType.PublicKeyResponse:
{
if (message.SenderEndPoint.ToString() != _targetServerEP.ToString() || !IsConnecting) { break; }
var packet = message.GetPacket<Packets.PublicKeyResponse>();
Security.SetServerPublicKey(packet.Modulus, packet.Exponent);
_publicKeyReceived.Set();
break;
}
}
break;
}
case NetIncomingMessageType.DebugMessage:
case NetIncomingMessageType.ErrorMessage:
case NetIncomingMessageType.WarningMessage:
case NetIncomingMessageType.VerboseDebugMessage:
Main.Logger.Trace(message.ReadString());
break;
default:
break;
}
Client.Recycle(message);
if (_recycle)
{
Peer.Recycle(message);
}
}
private static void HandlePacket(PacketType packetType, byte[] data)
private static void HandlePacket(PacketType packetType, NetIncomingMessage msg, NetConnection senderConnection, ref bool recycle)
{
switch (packetType)
{
case PacketType.HolePunchInit:
HolePunch.Add(msg.GetPacket<Packets.HolePunchInit>());
break;
case PacketType.PlayerConnect:
{
Packets.PlayerConnect packet = new Packets.PlayerConnect();
packet.Unpack(data);
Main.QueueAction(() => PlayerConnect(packet));
}
PlayerConnect(msg.GetPacket<Packets.PlayerConnect>());
break;
case PacketType.PlayerDisconnect:
{
Packets.PlayerDisconnect packet = new Packets.PlayerDisconnect();
packet.Unpack(data);
Main.QueueAction(() => PlayerDisconnect(packet));
}
PlayerDisconnect(msg.GetPacket<Packets.PlayerDisconnect>());
break;
case PacketType.PlayerInfoUpdate:
{
var packet = new Packets.PlayerInfoUpdate();
packet.Unpack(data);
PlayerList.UpdatePlayer(packet);
break;
}
#region ENTITY SYNC
PlayerList.UpdatePlayer(msg.GetPacket<Packets.PlayerInfoUpdate>());
break;
case PacketType.VehicleSync:
{
Packets.VehicleSync packet = new Packets.VehicleSync();
packet.Unpack(data);
VehicleSync(packet);
}
ReceivedPackets.VehicelPacket.Deserialize(msg);
VehicleSync(ReceivedPackets.VehicelPacket);
break;
case PacketType.PedSync:
{
Packets.PedSync packet = new Packets.PedSync();
packet.Unpack(data);
PedSync(packet);
}
break;
case PacketType.VehicleStateSync:
{
Packets.VehicleStateSync packet = new Packets.VehicleStateSync();
packet.Unpack(data);
VehicleStateSync(packet);
}
break;
case PacketType.PedStateSync:
{
Packets.PedStateSync packet = new Packets.PedStateSync();
packet.Unpack(data);
PedStateSync(packet);
}
ReceivedPackets.PedPacket.Deserialize(msg);
PedSync(ReceivedPackets.PedPacket);
break;
case PacketType.ProjectileSync:
{
Packets.ProjectileSync packet = new Packets.ProjectileSync();
packet.Unpack(data);
ProjectileSync(packet);
break;
}
#endregion
ReceivedPackets.ProjectilePacket.Deserialize(msg);
ProjectileSync(ReceivedPackets.ProjectilePacket);
break;
case PacketType.ChatMessage:
{
Packets.ChatMessage packet = new Packets.ChatMessage();
packet.Unpack(data);
Packets.ChatMessage packet = new Packets.ChatMessage((b) => Security.Decrypt(b));
packet.Deserialize(msg);
Main.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message); return true; });
}
break;
case PacketType.Voice:
{
if (Main.Settings.Voice)
{
Packets.Voice packet = new Packets.Voice();
packet.Deserialize(msg);
SyncedPed player = EntityPool.GetPedByID(packet.ID);
player.IsSpeaking = true;
player.LastSpeakingTime = Main.Ticked;
Voice.AddVoiceData(packet.Buffer, packet.Recorded);
}
}
break;
case PacketType.CustomEvent:
{
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
packet.Unpack(data);
packet.Deserialize(msg);
Scripting.API.Events.InvokeCustomEventReceived(packet);
}
break;
case PacketType.CustomEventQueued:
{
recycle = false;
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
Main.QueueAction(() =>
{
packet.Unpack(data);
packet.Deserialize(msg);
Scripting.API.Events.InvokeCustomEventReceived(packet);
Peer.Recycle(msg);
});
}
break;
case PacketType.FileTransferChunk:
{
Packets.FileTransferChunk packet = new Packets.FileTransferChunk();
packet.Unpack(data);
packet.Deserialize(msg);
DownloadManager.Write(packet.ID, packet.FileChunk);
}
break;
default:
if (packetType.IsSyncEvent())
{
// Dispatch to main thread
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, data); return true; });
recycle = false;
// Dispatch to script thread
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, msg); return true; });
}
break;
}
@ -300,130 +304,118 @@ namespace RageCoop.Client
private static void PedSync(Packets.PedSync packet)
{
SyncedPed c = EntityPool.GetPedByID(packet.ID);
if (c==null)
if (c == null)
{
// Main.Logger.Debug($"Creating character for incoming sync:{packet.ID}");
EntityPool.ThreadSafe.Add(c=new SyncedPed(packet.ID));
if (EntityPool.PedsByID.Count(x => x.Value.OwnerID == packet.OwnerID) < Main.Settings.WorldPedSoftLimit / PlayerList.Players.Count ||
/*EntityPool.VehiclesByID.Any(x => x.Value.Position.DistanceTo(packet.Position) < 2) ||*/ // allows players to exceed the peds limit
packet.ID == packet.OwnerID)
{
// Main.Logger.Debug($"Creating character for incoming sync:{packet.ID}");
EntityPool.ThreadSafe.Add(c = new SyncedPed(packet.ID));
}
else return;
}
PedDataFlags flags = packet.Flag;
c.ID=packet.ID;
//c.OwnerID=packet.OwnerID;
c.ID = packet.ID;
c.OwnerID = packet.OwnerID;
c.Health = packet.Health;
c.Position = packet.Position;
c.Rotation = packet.Rotation;
c.Velocity = packet.Velocity;
c.Speed = packet.Speed;
c.CurrentWeaponHash = packet.CurrentWeaponHash;
c.IsAiming = flags.HasPedFlag(PedDataFlags.IsAiming);
c.IsReloading = flags.HasPedFlag(PedDataFlags.IsReloading);
c.IsJumping = flags.HasPedFlag(PedDataFlags.IsJumping);
c.IsRagdoll = flags.HasPedFlag(PedDataFlags.IsRagdoll);
c.IsOnFire = flags.HasPedFlag(PedDataFlags.IsOnFire);
c.IsInParachuteFreeFall = flags.HasPedFlag(PedDataFlags.IsInParachuteFreeFall);
c.IsParachuteOpen = flags.HasPedFlag(PedDataFlags.IsParachuteOpen);
c.IsOnLadder = flags.HasPedFlag(PedDataFlags.IsOnLadder);
c.IsVaulting = flags.HasPedFlag(PedDataFlags.IsVaulting);
c.IsInCover = flags.HasPedFlag(PedDataFlags.IsInCover);
c.IsInStealthMode = flags.HasPedFlag(PedDataFlags.IsInStealthMode);
c.Heading=packet.Heading;
c.LastSynced = Main.Ticked;
c.Flags = packet.Flags;
c.Heading = packet.Heading;
c.Position = packet.Position;
c.LastSyncedStopWatch.Restart();
if (c.IsRagdoll)
{
c.HeadPosition = packet.HeadPosition;
c.RightFootPosition = packet.RightFootPosition;
c.LeftFootPosition = packet.LeftFootPosition;
}
else if (c.Speed >= 4)
{
c.VehicleID = packet.VehicleID;
c.Seat = packet.Seat;
}
c.LastSynced = Main.Ticked;
if (c.IsAiming)
{
c.AimCoords = packet.AimCoords;
}
if (c.IsRagdoll)
if (packet.Flags.HasPedFlag(PedDataFlags.IsFullSync))
{
c.RotationVelocity=packet.RotationVelocity;
c.CurrentWeaponHash = packet.CurrentWeaponHash;
c.Clothes = packet.Clothes;
c.WeaponComponents = packet.WeaponComponents;
c.WeaponTint = packet.WeaponTint;
c.Model = packet.ModelHash;
c.BlipColor = packet.BlipColor;
c.BlipSprite = packet.BlipSprite;
c.BlipScale = packet.BlipScale;
c.LastFullSynced = Main.Ticked;
}
}
private static void PedStateSync(Packets.PedStateSync packet)
{
SyncedPed c = EntityPool.GetPedByID(packet.ID);
if (c==null) { return; }
c.ID=packet.ID;
c.OwnerID=packet.OwnerID;
c.Clothes=packet.Clothes;
c.WeaponComponents=packet.WeaponComponents;
c.WeaponTint=packet.WeaponTint;
c.ModelHash=packet.ModelHash;
c.LastStateSynced = Main.Ticked;
c.BlipColor=packet.BlipColor;
c.BlipSprite=packet.BlipSprite;
c.BlipScale=packet.BlipScale;
}
private static void VehicleSync(Packets.VehicleSync packet)
{
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
if (v==null)
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
if (v == null)
{
EntityPool.ThreadSafe.Add(v=new SyncedVehicle(packet.ID));
if (EntityPool.VehiclesByID.Count(x => x.Value.OwnerID == packet.OwnerID) < Main.Settings.WorldVehicleSoftLimit / PlayerList.Players.Count ||
EntityPool.PedsByID.Any(x => x.Value.VehicleID == packet.ID || x.Value.Position.DistanceTo(packet.Position) < 2))
{
// Main.Logger.Debug($"Creating vehicle for incoming sync:{packet.ID}");
EntityPool.ThreadSafe.Add(v = new SyncedVehicle(packet.ID));
}
else return;
}
if (v.IsLocal) { return; }
v.ID= packet.ID;
v.Position=packet.Position;
v.Quaternion=packet.Quaternion;
v.SteeringAngle=packet.SteeringAngle;
v.ThrottlePower=packet.ThrottlePower;
v.BrakePower=packet.BrakePower;
v.Velocity=packet.Velocity;
v.RotationVelocity=packet.RotationVelocity;
v.DeluxoWingRatio=packet.DeluxoWingRatio;
v.LastSynced=Main.Ticked;
}
private static void VehicleStateSync(Packets.VehicleStateSync packet)
{
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
if (v==null||v.IsLocal) { return; }
v.ID= packet.ID;
v.OwnerID= packet.OwnerID;
v.DamageModel=packet.DamageModel;
v.EngineHealth=packet.EngineHealth;
v.OwnerID=packet.OwnerID;
v.Mods=packet.Mods;
v.ModelHash=packet.ModelHash;
v.Colors=packet.Colors;
v.LandingGear=packet.LandingGear;
v.RoofState=(VehicleRoofState)packet.RoofState;
v.EngineRunning = packet.Flag.HasVehFlag(VehicleDataFlags.IsEngineRunning);
v.LightsOn = packet.Flag.HasVehFlag(VehicleDataFlags.AreLightsOn);
v.BrakeLightsOn = packet.Flag.HasVehFlag(VehicleDataFlags.AreBrakeLightsOn);
v.HighBeamsOn = packet.Flag.HasVehFlag(VehicleDataFlags.AreHighBeamsOn);
v.SireneActive = packet.Flag.HasVehFlag(VehicleDataFlags.IsSirenActive);
v.IsDead = packet.Flag.HasVehFlag(VehicleDataFlags.IsDead);
v.HornActive = packet.Flag.HasVehFlag(VehicleDataFlags.IsHornActive);
v.Transformed = packet.Flag.HasVehFlag(VehicleDataFlags.IsTransformed);
v.Passengers=new Dictionary<VehicleSeat, SyncedPed>();
v.LockStatus=packet.LockStatus;
v.RadioStation=packet.RadioStation;
v.LicensePlate=packet.LicensePlate;
v.Livery=packet.Livery;
v.Flags=packet.Flag;
foreach (KeyValuePair<int, int> pair in packet.Passengers)
v.ID = packet.ID;
v.OwnerID = packet.OwnerID;
v.Flags = packet.Flags;
v.Position = packet.Position;
v.Quaternion = packet.Quaternion;
v.SteeringAngle = packet.SteeringAngle;
v.ThrottlePower = packet.ThrottlePower;
v.BrakePower = packet.BrakePower;
v.Velocity = packet.Velocity;
v.RotationVelocity = packet.RotationVelocity;
v.DeluxoWingRatio = packet.DeluxoWingRatio;
v.LastSynced = Main.Ticked;
v.LastSyncedStopWatch.Restart();
if (packet.Flags.HasVehFlag(VehicleDataFlags.IsFullSync))
{
if (EntityPool.PedExists(pair.Value))
{
v.Passengers.Add((VehicleSeat)pair.Key, EntityPool.GetPedByID(pair.Value));
}
v.DamageModel = packet.DamageModel;
v.EngineHealth = packet.EngineHealth;
v.Mods = packet.Mods;
v.Model = packet.ModelHash;
v.Colors = packet.Colors;
v.LandingGear = packet.LandingGear;
v.RoofState = (VehicleRoofState)packet.RoofState;
v.LockStatus = packet.LockStatus;
v.RadioStation = packet.RadioStation;
v.LicensePlate = packet.LicensePlate;
v.Livery = packet.Livery;
v.LastFullSynced = Main.Ticked;
}
v.LastStateSynced= Main.Ticked;
}
private static void ProjectileSync(Packets.ProjectileSync packet)
{
var p = EntityPool.GetProjectileByID(packet.ID);
if (p==null)
if (p == null)
{
if (packet.Exploded) { return; }
if (packet.Flags.HasProjDataFlag(ProjectileDataFlags.Exploded)) { return; }
// Main.Logger.Debug($"Creating new projectile: {(WeaponHash)packet.WeaponHash}");
EntityPool.ThreadSafe.Add(p=new SyncedProjectile(packet.ID));
EntityPool.ThreadSafe.Add(p = new SyncedProjectile(packet.ID));
}
p.Position=packet.Position;
p.Rotation=packet.Rotation;
p.Velocity=packet.Velocity;
p.Hash=(WeaponHash)packet.WeaponHash;
p.ShooterID=packet.ShooterID;
p.Exploded=packet.Exploded;
p.LastSynced=Main.Ticked;
p.Flags = packet.Flags;
p.Position = packet.Position;
p.Rotation = packet.Rotation;
p.Velocity = packet.Velocity;
p.WeaponHash = (WeaponHash)packet.WeaponHash;
p.Shooter = packet.Flags.HasProjDataFlag(ProjectileDataFlags.IsShotByVehicle) ?
(SyncedEntity)EntityPool.GetVehicleByID(packet.ShooterID) : EntityPool.GetPedByID(packet.ShooterID);
p.LastSynced = Main.Ticked;
p.LastSyncedStopWatch.Restart();
}
}
}

View File

@ -1,178 +1,207 @@
using Lidgren.Network;
using RageCoop.Core;
using GTA;
using GTA.Native;
using GTA;
using GTA.Math;
using GTA.Native;
using Lidgren.Network;
using RageCoop.Core;
using System;
using System.Collections.Generic;
namespace RageCoop.Client
{
internal static partial class Networking
{
#region -- SEND --
/// <summary>
/// Pack the packet then send to server.
/// Reduce GC pressure by reusing frequently used packets
/// </summary>
/// <param name="p"></param>
/// <param name="channel"></param>
/// <param name="method"></param>
public static void Send(Packet p, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
private static class SendPackets
{
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
p.Pack(outgoingMessage);
Client.SendMessage(outgoingMessage, method, (int)channel);
public static Packets.PedSync PedPacket = new Packets.PedSync();
public static Packets.VehicleSync VehicelPacket = new Packets.VehicleSync();
public static Packets.ProjectileSync ProjectilePacket = new Packets.ProjectileSync();
}
public static int SyncInterval = 30;
public static List<NetConnection> Targets = new List<NetConnection>();
public static void SendSync(Packet p, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
{
Peer.SendTo(p, Targets, channel, method);
}
public static void SendPed(SyncedPed c)
public static void SendPed(SyncedPed sp, bool full)
{
Ped p = c.MainPed;
var packet=new Packets.PedSync()
if (sp.LastSentStopWatch.ElapsedMilliseconds < SyncInterval)
{
ID =c.ID,
Health = p.Health,
Position = p.Position,
Rotation = p.Rotation,
Velocity = p.Velocity,
Speed = p.GetPedSpeed(),
CurrentWeaponHash = (uint)p.Weapons.Current.Hash,
Flag = p.GetPedFlags(),
Heading=p.Heading,
};
if (packet.Flag.HasPedFlag(PedDataFlags.IsAiming))
{
packet.AimCoords = p.GetAimCoord();
return;
}
if (packet.Flag.HasPedFlag(PedDataFlags.IsRagdoll))
Ped ped = sp.MainPed;
var p = SendPackets.PedPacket;
p.ID = sp.ID;
p.OwnerID = sp.OwnerID;
p.Health = ped.Health;
p.Rotation = ped.ReadRotation();
p.Velocity = ped.ReadVelocity();
p.Speed = ped.GetPedSpeed();
p.Flags = ped.GetPedFlags();
p.Heading = ped.Heading;
if (p.Flags.HasPedFlag(PedDataFlags.IsAiming))
{
packet.RotationVelocity=p.RotationVelocity;
p.AimCoords = ped.GetAimCoord();
}
Send(packet, ConnectionChannel.PedSync);
}
public static void SendPedState(SyncedPed c)
{
Ped p = c.MainPed;
var packet = new Packets.PedStateSync()
if (p.Flags.HasPedFlag(PedDataFlags.IsRagdoll))
{
ID = c.ID,
OwnerID=c.OwnerID,
Clothes=p.GetPedClothes(),
ModelHash=p.Model.Hash,
WeaponComponents=p.Weapons.Current.GetWeaponComponents(),
WeaponTint=(byte)Function.Call<int>(Hash.GET_PED_WEAPON_TINT_INDEX, p, p.Weapons.Current.Hash),
};
Blip b;
if (c.IsPlayer)
{
packet.BlipColor=Scripting.API.Config.BlipColor;
packet.BlipSprite=Scripting.API.Config.BlipSprite;
packet.BlipScale=Scripting.API.Config.BlipScale;
p.HeadPosition = ped.Bones[Bone.SkelHead].Position;
p.RightFootPosition = ped.Bones[Bone.SkelRightFoot].Position;
p.LeftFootPosition = ped.Bones[Bone.SkelLeftFoot].Position;
}
else if ((b = p.AttachedBlip) !=null)
else
{
packet.BlipColor=b.Color;
packet.BlipSprite=b.Sprite;
if (packet.BlipSprite==BlipSprite.PoliceOfficer || packet.BlipSprite==BlipSprite.PoliceOfficer2)
// Seat sync
if (p.Speed >= 4)
{
packet.BlipScale=0.5f;
var veh = ped.CurrentVehicle?.GetSyncEntity() ?? ped.VehicleTryingToEnter?.GetSyncEntity() ?? ped.LastVehicle?.GetSyncEntity();
p.VehicleID = veh?.ID ?? 0;
if (p.VehicleID == 0) { Main.Logger.Error("Invalid vehicle"); }
if (p.Speed == 5)
{
p.Seat = ped.GetSeatTryingToEnter();
}
else
{
p.Seat = ped.SeatIndex;
}
if (!veh.IsLocal && p.Speed == 4 && p.Seat == VehicleSeat.Driver)
{
veh.OwnerID = Main.LocalPlayerID;
SyncEvents.TriggerChangeOwner(veh.ID, Main.LocalPlayerID);
}
}
p.Position = ped.ReadPosition();
}
sp.LastSentStopWatch.Restart();
if (full)
{
var w = ped.VehicleWeapon;
p.CurrentWeaponHash = (w != VehicleWeaponHash.Invalid) ? (uint)w : (uint)ped.Weapons.Current.Hash;
p.Flags |= PedDataFlags.IsFullSync;
p.Clothes = ped.GetPedClothes();
p.ModelHash = ped.Model.Hash;
p.WeaponComponents = ped.Weapons.Current.GetWeaponComponents();
p.WeaponTint = (byte)Function.Call<int>(Hash.GET_PED_WEAPON_TINT_INDEX, ped, ped.Weapons.Current.Hash);
Blip b;
if (sp.IsPlayer)
{
p.BlipColor = Scripting.API.Config.BlipColor;
p.BlipSprite = Scripting.API.Config.BlipSprite;
p.BlipScale = Scripting.API.Config.BlipScale;
}
else if ((b = ped.AttachedBlip) != null)
{
p.BlipColor = b.Color;
p.BlipSprite = b.Sprite;
if (p.BlipSprite == BlipSprite.PoliceOfficer || p.BlipSprite == BlipSprite.PoliceOfficer2)
{
p.BlipScale = 0.5f;
}
}
else
{
p.BlipColor = (BlipColor)255;
}
}
Send(packet, ConnectionChannel.PedSync);
SendSync(p, ConnectionChannel.PedSync);
}
public static void SendVehicle(SyncedVehicle v)
public static void SendVehicle(SyncedVehicle v, bool full)
{
Vehicle veh = v.MainVehicle;
var packet = new Packets.VehicleSync()
if (v.LastSentStopWatch.ElapsedMilliseconds < SyncInterval)
{
ID =v.ID,
SteeringAngle = veh.SteeringAngle,
Position = veh.PredictPosition(),
Quaternion=veh.Quaternion,
// Rotation = veh.Rotation,
Velocity = veh.Velocity,
RotationVelocity=veh.RotationVelocity,
ThrottlePower = veh.ThrottlePower,
BrakePower = veh.BrakePower,
};
if (v.MainVehicle.Model.Hash==1483171323) { packet.DeluxoWingRatio=v.MainVehicle.GetDeluxoWingRatio(); }
Send(packet,ConnectionChannel.VehicleSync);
}
public static void SendVehicleState(SyncedVehicle v)
{
Vehicle veh = v.MainVehicle;
byte primaryColor = 0;
byte secondaryColor = 0;
unsafe
{
Function.Call<byte>(Hash.GET_VEHICLE_COLOURS, veh, &primaryColor, &secondaryColor);
return;
}
var packet = new Packets.VehicleStateSync()
Vehicle veh = v.MainVehicle;
var packet = SendPackets.VehicelPacket;
packet.ID = v.ID;
packet.OwnerID = v.OwnerID;
packet.Flags = v.GetVehicleFlags();
packet.SteeringAngle = veh.SteeringAngle;
packet.Position = veh.ReadPosition();
packet.Velocity = veh.Velocity;
packet.Quaternion = veh.ReadQuaternion();
packet.RotationVelocity = veh.LocalRotationVelocity;
packet.ThrottlePower = veh.ThrottlePower;
packet.BrakePower = veh.BrakePower;
v.LastSentStopWatch.Restart();
if (packet.Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering)) { packet.DeluxoWingRatio = v.MainVehicle.GetDeluxoWingRatio(); }
if (full)
{
ID =v.ID,
OwnerID = v.OwnerID,
Flag = veh.GetVehicleFlags(),
Colors=new byte[] { primaryColor, secondaryColor },
DamageModel=veh.GetVehicleDamageModel(),
LandingGear = veh.IsAircraft ? (byte)veh.LandingGearState : (byte)0,
RoofState=(byte)veh.RoofState,
Mods = veh.Mods.GetVehicleMods(),
ModelHash=veh.Model.Hash,
EngineHealth=veh.EngineHealth,
Passengers=veh.GetPassengers(),
LockStatus=veh.LockStatus,
LicensePlate=Function.Call<string>(Hash.GET_VEHICLE_NUMBER_PLATE_TEXT, veh),
Livery=Function.Call<int>(Hash.GET_VEHICLE_LIVERY, veh)
};
if (v.MainVehicle==Game.Player.LastVehicle)
{
packet.RadioStation=Util.GetPlayerRadioIndex();
byte primaryColor = 0;
byte secondaryColor = 0;
unsafe
{
Function.Call<byte>(Hash.GET_VEHICLE_COLOURS, veh, &primaryColor, &secondaryColor);
}
packet.Flags |= VehicleDataFlags.IsFullSync;
packet.Colors = new byte[] { primaryColor, secondaryColor };
packet.DamageModel = veh.GetVehicleDamageModel();
packet.LandingGear = veh.IsAircraft ? (byte)veh.LandingGearState : (byte)0;
packet.RoofState = (byte)veh.RoofState;
packet.Mods = veh.Mods.GetVehicleMods();
packet.ModelHash = veh.Model.Hash;
packet.EngineHealth = veh.EngineHealth;
packet.LockStatus = veh.LockStatus;
packet.LicensePlate = Function.Call<string>(Hash.GET_VEHICLE_NUMBER_PLATE_TEXT, veh);
packet.Livery = Function.Call<int>(Hash.GET_VEHICLE_LIVERY, veh);
if (v.MainVehicle == Game.Player.LastVehicle)
{
packet.RadioStation = Util.GetPlayerRadioIndex();
}
if (packet.EngineHealth > v.LastEngineHealth)
{
packet.Flags |= VehicleDataFlags.Repaired;
}
v.LastEngineHealth = packet.EngineHealth;
}
Send(packet, ConnectionChannel.VehicleSync);
SendSync(packet, ConnectionChannel.VehicleSync);
}
public static void SendProjectile(SyncedProjectile sp)
{
var p = sp.MainProjectile;
var packet = new Packets.ProjectileSync()
{
ID =sp.ID,
ShooterID=sp.ShooterID,
Position=p.Position,
Rotation=p.Rotation,
Velocity=p.Velocity,
WeaponHash=(uint)p.WeaponHash,
Exploded=p.IsDead
};
if (p.IsDead) { EntityPool.RemoveProjectile(sp.ID,"Dead"); }
Send(packet, ConnectionChannel.ProjectileSync);
sp.ExtractData(ref SendPackets.ProjectilePacket);
if (sp.MainProjectile.IsDead) { EntityPool.RemoveProjectile(sp.ID, "Dead"); }
SendSync(SendPackets.ProjectilePacket, ConnectionChannel.ProjectileSync);
}
#region SYNC EVENTS
public static void SendBulletShot(Vector3 start,Vector3 end,uint weapon,int ownerID)
public static void SendBullet(Vector3 start, Vector3 end, uint weapon, int ownerID)
{
Send(new Packets.BulletShot()
SendSync(new Packets.BulletShot()
{
StartPosition = start,
EndPosition = end,
OwnerID = ownerID,
WeaponHash=weapon,
WeaponHash = weapon,
}, ConnectionChannel.SyncEvents);
}
public static void SendVehicleBullet(uint hash, SyncedPed owner, EntityBone b)
{
SendSync(new Packets.VehicleBulletShot
{
StartPosition = b.Position,
EndPosition = b.Position + b.ForwardVector,
OwnerID = owner.ID,
Bone = (ushort)b.Index,
WeaponHash = hash
});
}
#endregion
public static void SendChatMessage(string message)
{
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
new Packets.ChatMessage() { Username = Main.Settings.Username, Message = message }.Pack(outgoingMessage);
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Chat);
Client.FlushSendQueue();
#if DEBUG
#endif
Peer.SendTo(new Packets.ChatMessage(new Func<string, byte[]>((s) => Security.Encrypt(s.GetBytes())))
{ Username = Main.Settings.Username, Message = message }, ServerConnection, ConnectionChannel.Chat, NetDeliveryMethod.ReliableOrdered);
Peer.FlushSendQueue();
}
public static void SendVoiceMessage(byte[] buffer, int recorded)
{
SendSync(new Packets.Voice() { ID = Main.LocalPlayerID, Buffer = buffer, Recorded = recorded }, ConnectionChannel.Voice, NetDeliveryMethod.ReliableOrdered);
}
#endregion
}
}

View File

@ -1,15 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading;
using System.Threading.Tasks;
namespace RageCoop.Client
{
internal static class Statistics
{
public static int BytesDownPerSecond{ get; private set; }
public static int BytesDownPerSecond { get; private set; }
public static int BytesUpPerSecond { get; private set; }
static Statistics()
{
@ -17,11 +13,11 @@ namespace RageCoop.Client
{
while (true)
{
var bu=Networking.Client.Statistics.SentBytes;
var bd = Networking.Client.Statistics.ReceivedBytes;
var bu = Networking.Peer.Statistics.SentBytes;
var bd = Networking.Peer.Statistics.ReceivedBytes;
Thread.Sleep(1000);
BytesUpPerSecond=Networking.Client.Statistics.SentBytes-bu;
BytesDownPerSecond=Networking.Client.Statistics.ReceivedBytes-bd;
BytesUpPerSecond = Networking.Peer.Statistics.SentBytes - bu;
BytesDownPerSecond = Networking.Peer.Statistics.ReceivedBytes - bd;
}
});
}

View File

@ -1,9 +1,11 @@
using System.Collections.Generic;
using System.Linq;
using GTA;
using GTA;
using GTA.Math;
using RageCoop.Core;
using GTA.Native;
using Lidgren.Network;
using RageCoop.Core;
using System.Collections.Generic;
using System.Linq;
using System.Net;
namespace RageCoop.Client
{
@ -11,12 +13,12 @@ namespace RageCoop.Client
{
private const float LEFT_POSITION = 0.122f;
private const float RIGHT_POSITION = 0.9f;
private static readonly Scaleform _mainScaleform = new Scaleform("mp_mm_card_freemode");
private static readonly Scaleform _mainScaleform = Scaleform.RequestMovie("mp_mm_card_freemode");
private static ulong _lastUpdate = Util.GetTickCount64();
public static ulong Pressed { get; set; }
public static bool LeftAlign = true;
public static Dictionary<int,PlayerData> Players=new Dictionary<int, PlayerData> { };
public static Dictionary<int, Player> Players = new Dictionary<int, Player> { };
public static void Tick()
{
if (!Networking.IsOnServer)
@ -26,7 +28,7 @@ namespace RageCoop.Client
if ((Util.GetTickCount64() - _lastUpdate) >= 1000)
{
Update( Main.Settings.Username);
Update();
}
if ((Util.GetTickCount64() - Pressed) < 5000 && !Main.MainChat.Focused
@ -35,100 +37,132 @@ namespace RageCoop.Client
#endif
)
{
Function.Call(Hash.DRAW_SCALEFORM_MOVIE, _mainScaleform.Handle,
Function.Call(Hash.DRAW_SCALEFORM_MOVIE, _mainScaleform.Handle,
LeftAlign ? LEFT_POSITION : RIGHT_POSITION, 0.3f,
0.28f, 0.6f,
255, 255, 255, 255, 0);
}
}
private static void Update( string localUsername)
private static void Update()
{
_lastUpdate = Util.GetTickCount64();
_mainScaleform.CallFunction("SET_DATA_SLOT_EMPTY", 0);
_mainScaleform.CallFunction("SET_DATA_SLOT", 0, $"{Networking.Latency * 1000:N0}ms", localUsername, 116, 0, 0, "", "", 2, "", "", ' ');
int i = 1;
foreach (var player in Players)
int i = 0;
foreach (var player in Players.Values)
{
_mainScaleform.CallFunction("SET_DATA_SLOT", i++, $"{player.Value.Latency * 1000:N0}ms", player.Value.Username, 116, 0, i - 1, "", "", 2, "", "", ' ');
_mainScaleform.CallFunction("SET_DATA_SLOT", i++, $"{player.Ping * 1000:N0}ms", player.Username + (player.IsHost ? " (Host)" : ""), 116, 0, i - 1, "", "", 2, "", "", ' ');
}
_mainScaleform.CallFunction("SET_TITLE", "Player list", $"{Players.Count+1} players");
_mainScaleform.CallFunction("SET_TITLE", "Player list", $"{Players.Count} players");
_mainScaleform.CallFunction("DISPLAY_VIEW");
}
public static void SetPlayer(int id, string username,float latency=0)
public static void SetPlayer(int id, string username, float latency = 0)
{
PlayerData p;
if (Players.TryGetValue(id,out p))
Main.Logger.Debug($"{id},{username},{latency}");
if (Players.TryGetValue(id, out Player p))
{
p.Username=username;
p.PedID=id;
p.Latency=latency;
p.Username = username;
p.ID = id;
p._latencyToServer = latency;
}
else
{
p = new PlayerData { PedID=id, Username=username,Latency=latency };
Players.Add(id,p);
p = new Player { ID = id, Username = username, _latencyToServer = latency };
Players.Add(id, p);
}
}
public static void UpdatePlayer(Packets.PlayerInfoUpdate packet)
{
var p = GetPlayer(packet.PedID);
if(p?.Character != null)
if (p != null)
{
p.Latency= packet.Latency;
p._latencyToServer = packet.Latency;
p.Position = packet.Position;
p.IsHost = packet.IsHost;
Main.QueueAction(() =>
{
if (p.FakeBlip?.Exists() != true)
{
p.FakeBlip = World.CreateBlip(p.Position);
}
if (EntityPool.PedExists(p.ID))
{
p.FakeBlip.DisplayType = BlipDisplayType.NoDisplay;
}
else
{
p.FakeBlip.Color = Scripting.API.Config.BlipColor;
p.FakeBlip.Scale = Scripting.API.Config.BlipScale;
p.FakeBlip.Sprite = Scripting.API.Config.BlipSprite;
p.FakeBlip.DisplayType = BlipDisplayType.Default;
p.FakeBlip.Position = p.Position;
}
});
}
}
public static PlayerData GetPlayer(int id)
public static Player GetPlayer(int id)
{
PlayerData p;
Players.TryGetValue(id, out p);
Players.TryGetValue(id, out Player p);
return p;
}
public static PlayerData GetPlayer(SyncedPed p)
public static Player GetPlayer(SyncedPed p)
{
var player = GetPlayer(p.ID);
if (player!=null)
if (player != null)
{
player.Character=p;
player.Character = p;
}
return player;
}
public static void RemovePlayer(int id)
{
if (Players.ContainsKey(id))
if (Players.TryGetValue(id, out var player))
{
Players.Remove(id);
Main.QueueAction(() => player.FakeBlip?.Delete());
}
}
public static void Cleanup()
{
Players=new Dictionary<int, PlayerData>{ };
foreach (var p in Players.Values.ToArray())
{
p.FakeBlip?.Delete();
}
Players = new Dictionary<int, Player> { };
}
}
internal class PlayerData
public class Player
{
public byte HolePunchStatus { get; internal set; } = 1;
public bool IsHost { get; internal set; }
public string Username { get; internal set; }
/// <summary>
/// Universal character ID.
/// Universal ped ID.
/// </summary>
public int PedID
public int ID
{
get; internal set;
}
public SyncedPed Character { get; set; }
public IPEndPoint InternalEndPoint { get; internal set; }
public IPEndPoint ExternalEndPoint { get; internal set; }
internal bool ConnectWhenPunched { get; set; }
public Blip FakeBlip { get; internal set; }
public Vector3 Position { get; internal set; }
public SyncedPed Character { get; internal set; }
/// <summary>
/// Player Latency in second.
/// Player round-trip time in seconds, will be the rtt to server if not using P2P connection.
/// </summary>
public float Latency { get; set; }
public float Ping => Main.LocalPlayerID == ID ? Networking.Latency * 2 : (HasDirectConnection ? Connection.AverageRoundtripTime : _latencyToServer * 2);
public float PacketTravelTime => HasDirectConnection ? Connection.AverageRoundtripTime / 2 : Networking.Latency + _latencyToServer;
internal float _latencyToServer = 0;
public bool DisplayNameTag { get; set; } = true;
public NetConnection Connection { get; internal set; }
public bool HasDirectConnection => Connection?.Status == NetConnectionStatus.Connected;
}
}

View File

@ -0,0 +1,22 @@

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Resources;
// General Information
[assembly: AssemblyTitle("RageCoop.Client")]
[assembly: AssemblyDescription("RageCoop.Client")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("RAGECOOP")]
[assembly: AssemblyProduct("RageCoop.Client")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("RAGECOOP")]
[assembly: AssemblyCulture("")]
// Version information
[assembly: AssemblyVersion("1.5.4.7")]
[assembly: AssemblyFileVersion("1.5.4.7")]
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]

View File

@ -0,0 +1,46 @@
<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#
string output = File.ReadAllText(this.Host.ResolvePath("AssemblyInfo.cs"));
Regex pattern = new Regex("AssemblyVersion\\(\"(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<revision>\\d+)\\.(?<build>\\d+)\"\\)");
MatchCollection matches = pattern.Matches(output);
if( matches.Count == 1 )
{
major = Convert.ToInt32(matches[0].Groups["major"].Value);
minor = Convert.ToInt32(matches[0].Groups["minor"].Value);
build = Convert.ToInt32(matches[0].Groups["build"].Value) + 1;
revision = Convert.ToInt32(matches[0].Groups["revision"].Value);
if( this.Host.ResolveParameterValue("-","-","BuildConfiguration") == "Release" )
revision++;
}
#>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Resources;
// General Information
[assembly: AssemblyTitle("RageCoop.Client")]
[assembly: AssemblyDescription("RageCoop.Client")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("RAGECOOP")]
[assembly: AssemblyProduct("RageCoop.Client")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("RAGECOOP")]
[assembly: AssemblyCulture("")]
// Version informationr(
[assembly: AssemblyVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")]
[assembly: AssemblyFileVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")]
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
<#+
int major = 1;
int minor = 0;
int revision = 0;
int build = 0;
#>

View File

@ -1,55 +1,138 @@
<Project Sdk="Microsoft.NET.Sdk">
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Costura.Fody.5.7.0\build\Costura.Fody.props" Condition="Exists('..\packages\Costura.Fody.5.7.0\build\Costura.Fody.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<UseWindowsForms>True</UseWindowsForms>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<DocumentationFile></DocumentationFile>
<DebugType>portable</DebugType>
<AssemblyVersion>0.5.0</AssemblyVersion>
<FileVersion>0.5.0</FileVersion>
<Version>0.5.0</Version>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<Authors>RAGECOOP</Authors>
<Description>An API reference for developing client-side resource for RAGECOOP</Description>
<PackageProjectUrl>https://ragecoop.online/</PackageProjectUrl>
<RepositoryUrl>https://github.com/RAGECOOP/RAGECOOP-V</RepositoryUrl>
<ApplicationIcon>icon.ico</ApplicationIcon>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<DefineConstants>SHVDN3</DefineConstants>
<TargetFrameworks>net48</TargetFrameworks>
<UseWindowsForms>true</UseWindowsForms>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>RageCoop.Client</RootNamespace>
<AssemblyName>RageCoop.Client</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<OutPutPath>..\bin\Debug\Client</OutPutPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>DEBUG</DefineConstants>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<OutPutPath>..\bin\Release\Client</OutPutPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<OutDir>..\bin\Debug\Client</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<OutDir>..\bin\Release\Client</OutDir>
</PropertyGroup>
<ItemGroup>
<Content Include="icon.ico" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SharpZipLib" Version="1.3.3" />
<Compile Include="Debug.cs" />
<Compile Include="DevTools\DevTool.cs" />
<Compile Include="Main.cs" />
<Compile Include="Menus\CoopMenu.cs" />
<Compile Include="Menus\Sub\DebugMenu.cs" />
<Compile Include="Menus\Sub\DevToolMenu.cs" />
<Compile Include="Menus\Sub\ServersMenu.cs" />
<Compile Include="Menus\Sub\SettingsMenu.cs" />
<Compile Include="Networking\Chat.cs" />
<Compile Include="Networking\DownloadManager.cs" />
<Compile Include="Networking\HolePunch.cs" />
<Compile Include="Networking\Networking.cs" />
<Compile Include="Networking\Receive.cs" />
<Compile Include="Networking\Send.cs" />
<Compile Include="Networking\Statistics.cs" />
<Compile Include="PlayerList.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AssemblyInfo.tt</DependentUpon>
</Compile>
<Compile Include="Scripting\API.cs" />
<Compile Include="Scripting\BaseScript.cs" />
<Compile Include="Scripting\ClientScript.cs" />
<Compile Include="Scripting\Resources.cs" />
<Compile Include="Security.cs" />
<Compile Include="Settings.cs" />
<Compile Include="Sync\Entities\Ped\SyncedPed.Members.cs" />
<Compile Include="Sync\Entities\Ped\SyncedPed.Animations.cs" />
<Compile Include="Sync\Entities\SyncedEntity.cs" />
<Compile Include="Sync\Entities\Ped\SyncedPed.cs" />
<Compile Include="Sync\Entities\SyncedProjectile.cs" />
<Compile Include="Sync\Entities\SyncedProp.cs" />
<Compile Include="Sync\Entities\Vehicle\SyncedVehicle.cs" />
<Compile Include="Sync\Entities\Vehicle\SyncedVehicle.Members.cs" />
<Compile Include="Sync\EntityPool.cs" />
<Compile Include="Sync\SyncEvents.cs" />
<Compile Include="Sync\Voice.cs" />
<Compile Include="Util\AddOnDataProvider.cs" />
<Compile Include="Util\Memory.cs" />
<Compile Include="Util\NativeCaller.cs" />
<Compile Include="Util\PedConfigFlags.cs" />
<Compile Include="Util\PedExtensions.cs" />
<Compile Include="Util\TaskType.cs" />
<Compile Include="Util\Util.cs" />
<Compile Include="Util\VehicleExtensions.cs" />
<Compile Include="Util\WeaponUtil.cs" />
<Compile Include="WorldThread.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RageCoop.Core\RageCoop.Core.csproj" />
<ProjectReference Include="..\RageCoop.Core\RageCoop.Core.csproj">
<Project>{cc2e8102-e568-4524-aa1f-f8e0f1cfe58a}</Project>
<Name>RageCoop.Core</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="LemonUI.SHVDN3">
<Reference Include="Costura, Version=5.7.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Costura.Fody.5.7.0\lib\netstandard1.0\Costura.dll</HintPath>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=1.3.3.11, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.1.3.3\lib\net45\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="LemonUI.SHVDN3, Version=1.10.0.0, Culture=neutral, processorArchitecture=AMD64">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\libs\LemonUI.SHVDN3.dll</HintPath>
</Reference>
<Reference Include="Lidgren.Network">
<Reference Include="Lidgren.Network, Version=2012.1.7.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\libs\Lidgren.Network.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Extensions.ObjectPool, Version=6.0.8.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.ObjectPool.6.0.8\lib\net461\Microsoft.Extensions.ObjectPool.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Win32.Registry, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Win32.Registry.4.7.0\lib\net461\Microsoft.Win32.Registry.dll</HintPath>
</Reference>
<Reference Include="NAudio, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
<HintPath>..\packages\NAudio.2.1.0\lib\net472\NAudio.dll</HintPath>
</Reference>
<Reference Include="NAudio.Asio, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
<HintPath>..\packages\NAudio.Asio.2.1.0\lib\netstandard2.0\NAudio.Asio.dll</HintPath>
</Reference>
<Reference Include="NAudio.Core, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
<HintPath>..\packages\NAudio.Core.2.1.0\lib\netstandard2.0\NAudio.Core.dll</HintPath>
</Reference>
<Reference Include="NAudio.Midi, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
<HintPath>..\packages\NAudio.Midi.2.1.0\lib\netstandard2.0\NAudio.Midi.dll</HintPath>
</Reference>
<Reference Include="NAudio.Wasapi, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
<HintPath>..\packages\NAudio.Wasapi.2.1.0\lib\netstandard2.0\NAudio.Wasapi.dll</HintPath>
</Reference>
<Reference Include="NAudio.WinForms, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
<HintPath>..\packages\NAudio.WinForms.2.1.0\lib\net472\NAudio.WinForms.dll</HintPath>
</Reference>
<Reference Include="NAudio.WinMM, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
<HintPath>..\packages\NAudio.WinMM.2.1.0\lib\netstandard2.0\NAudio.WinMM.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\libs\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="ScriptHookVDotNet">
@ -58,6 +141,170 @@
<Reference Include="ScriptHookVDotNet3">
<HintPath>..\libs\ScriptHookVDotNet3.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.AppContext, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Console.4.3.0\lib\net46\System.Console.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.Tracing, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Globalization.Calendars, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.IO, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.4.3.0\lib\net462\System.IO.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Linq, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Linq.4.3.0\lib\net463\System.Linq.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Linq.Expressions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Sockets, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Reflection, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime.InteropServices, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.AccessControl, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.AccessControl.4.7.0\lib\net461\System.Security.AccessControl.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Principal.Windows, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Principal.Windows.4.7.0\lib\net461\System.Security.Principal.Windows.dll</HintPath>
</Reference>
<Reference Include="System.Text.RegularExpressions, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.RegularExpressions.4.3.0\lib\net463\System.Text.RegularExpressions.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Serialization" />
</ItemGroup>
</Project>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Content Include="FodyWeavers.xml" />
<Content Include="Properties\AssemblyInfo.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>AssemblyInfo.cs</LastGenOutput>
</Content>
</ItemGroup>
<ItemGroup>
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Fody.6.6.3\build\Fody.targets" Condition="Exists('..\packages\Fody.6.6.3\build\Fody.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Fody.6.6.3\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.6.6.3\build\Fody.targets'))" />
<Error Condition="!Exists('..\packages\Costura.Fody.5.7.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.5.7.0\build\Costura.Fody.props'))" />
<Error Condition="!Exists('..\packages\Costura.Fody.5.7.0\build\Costura.Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.5.7.0\build\Costura.Fody.targets'))" />
</Target>
<Import Project="..\packages\Costura.Fody.5.7.0\build\Costura.Fody.targets" Condition="Exists('..\packages\Costura.Fody.5.7.0\build\Costura.Fody.targets')" />
<PropertyGroup Condition=" '$(DevEnvDir)' != '*Undefined*'">
<PostBuildEvent>"$(DevEnvDir)TextTransform.exe" -a !!BuildConfiguration!$(Configuration) "$(ProjectDir)Properties\AssemblyInfo.tt"</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_LastSelectedProfileId>M:\SandBox-Shared\repo\RageCoop\RageCoop-V\RageCoop.Client\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
</PropertyGroup>
</Project>

View File

@ -1,10 +1,10 @@
#undef DEBUG
using System.Collections.Generic;
using System;
using System.Linq;
using RageCoop.Core;
using System.Windows.Forms;
using GTA;
using Newtonsoft.Json;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace RageCoop.Client.Scripting
{
@ -25,7 +25,7 @@ namespace RageCoop.Client.Scripting
/// <summary>
/// Provides vital functionality to interact with RAGECOOP
/// </summary>
public static class API
public class API
{
#region INTERNAL
internal static Dictionary<int, List<Action<CustomEventReceivedArgs>>> CustomEventHandlers = new Dictionary<int, List<Action<CustomEventReceivedArgs>>>();
@ -40,7 +40,7 @@ namespace RageCoop.Client.Scripting
/// </summary>
public static string Username
{
get { return Main.Settings.Username; }
get => Main.Settings.Username;
set
{
if (Networking.IsOnServer || string.IsNullOrEmpty(value))
@ -64,7 +64,7 @@ namespace RageCoop.Client.Scripting
/// Get or set player's blip sprite
/// </summary>
public static BlipSprite BlipSprite { get; set; } = BlipSprite.Standard;
/// <summary>
/// Get or set scale of player's blip
/// </summary>
@ -91,7 +91,7 @@ namespace RageCoop.Client.Scripting
/// <summary>
/// The local player is dead
/// </summary>
public static event EmptyEvent OnPlayerDied;
public static event EventHandler<string> OnPlayerDied;
/// <summary>
/// A local vehicle is spawned
@ -133,21 +133,20 @@ namespace RageCoop.Client.Scripting
internal static void InvokeVehicleDeleted(SyncedVehicle v) { OnVehicleDeleted?.Invoke(null, v); }
internal static void InvokePedSpawned(SyncedPed p) { OnPedSpawned?.Invoke(null, p); }
internal static void InvokePedDeleted(SyncedPed p) { OnPedDeleted?.Invoke(null, p); }
internal static void InvokePlayerDied() { OnPlayerDied?.Invoke(); }
internal static void InvokePlayerDied(string m) { OnPlayerDied?.Invoke(null, m); }
internal static void InvokeTick() { OnTick?.Invoke(); }
internal static void InvokeKeyDown(object s,KeyEventArgs e) { OnKeyDown?.Invoke(s,e); }
internal static void InvokeKeyDown(object s, KeyEventArgs e) { OnKeyDown?.Invoke(s, e); }
internal static void InvokeKeyUp(object s, KeyEventArgs e) { OnKeyUp?.Invoke(s, e); }
internal static void InvokeCustomEventReceived(Packets.CustomEvent p)
{
var args = new CustomEventReceivedArgs() { Hash=p.Hash, Args=p.Args};
var args = new CustomEventReceivedArgs() { Hash = p.Hash, Args = p.Args };
// Main.Logger.Debug($"CustomEvent:\n"+args.Args.DumpWithType());
List<Action<CustomEventReceivedArgs>> handlers;
if (CustomEventHandlers.TryGetValue(p.Hash, out handlers))
if (CustomEventHandlers.TryGetValue(p.Hash, out List<Action<CustomEventReceivedArgs>> handlers))
{
handlers.ForEach((x) => { x.Invoke(args); });
}
@ -161,58 +160,84 @@ namespace RageCoop.Client.Scripting
/// Get the local player's ID
/// </summary>
/// <returns>PlayerID</returns>
public static int LocalPlayerID
{
get { return Main.LocalPlayerID; }
}
public static int LocalPlayerID => Main.LocalPlayerID;
/// <summary>
/// Check if player is connected to a server
/// </summary>
public static bool IsOnServer => Networking.IsOnServer;
/// <summary>
/// Get an <see cref="System.Net.IPEndPoint"/> that the player is currently connected to, or null if not connected to the server
/// </summary>
public static System.Net.IPEndPoint ServerEndPoint => Networking.IsOnServer ? Networking.ServerConnection?.RemoteEndPoint : null;
/// <summary>
/// Check if a RAGECOOP menu is visible
/// </summary>
public static bool IsMenuVisible
{
get { return Menus.CoopMenu.MenuPool.AreAnyVisible; }
}
public static bool IsMenuVisible => Menus.CoopMenu.MenuPool.AreAnyVisible;
/// <summary>
/// Check if the RAGECOOP chat is visible
/// </summary>
public static bool IsChatFocused
{
get { return Main.MainChat.Focused; }
}
public static bool IsChatFocused => Main.MainChat.Focused;
/// <summary>
/// Check if the RAGECOOP list of players is visible
/// </summary>
public static bool IsPlayerListVisible
{
get { return Util.GetTickCount64() - PlayerList.Pressed < 5000; }
}
public static bool IsPlayerListVisible => Util.GetTickCount64() - PlayerList.Pressed < 5000;
/// <summary>
/// Get the version of RAGECOOP
/// </summary>
public static string CurrentVersion
{
get { return Main.CurrentVersion; }
}
public static Version CurrentVersion => Main.Version;
/// <summary>
/// Get a <see cref="Core.Logger"/> that RAGECOOP is currently using.
/// </summary>
/// <returns></returns>
public static Logger Logger
{
get
{
return Main.Logger;
}
}
public static Logger Logger => Main.Logger;
/// <summary>
/// Get all players indexed by their ID
/// </summary>
public static Dictionary<int, Player> Players => new Dictionary<int, Player>(PlayerList.Players);
#endregion
#region FUNCTIONS
/// <summary>
/// Connect to a server
/// </summary>
/// <param name="address">Address of the server, e.g. 127.0.0.1:4499</param>
/// <exception cref="InvalidOperationException">When a connection is active or being established</exception>
public static void Connect(string address)
{
if (Networking.IsOnServer || Networking.IsConnecting)
{
throw new InvalidOperationException("Cannot connect to server when another connection is active");
}
Networking.ToggleConnection(address);
}
/// <summary>
/// Disconnect from current server or cancel the connection attempt.
/// </summary>
public static void Disconnect()
{
if (Networking.IsOnServer || Networking.IsConnecting)
{
Networking.ToggleConnection(null);
}
}
/// <summary>
/// List all servers from master server address
/// </summary>
/// <returns></returns>
public static List<ServerInfo> ListServers()
{
return JsonConvert.DeserializeObject<List<ServerInfo>>(HttpHelper.DownloadString(Main.Settings.MasterServer));
}
/// <summary>
/// Send a local chat message to this player
/// </summary>
@ -223,6 +248,15 @@ namespace RageCoop.Client.Scripting
Main.MainChat.AddMessage(from, message);
}
/// <summary>
/// Send a chat message or command to server/other players
/// </summary>
/// <param name="message"></param>
public static void SendChatMessage(string message)
{
Networking.SendChatMessage(message);
}
/// <summary>
/// Queue an action to be executed on next tick.
/// </summary>
@ -231,12 +265,14 @@ namespace RageCoop.Client.Scripting
{
Main.QueueAction(a);
}
/// <summary>
/// Disconnect from the server
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
/// </summary>
public static void Disconnect()
/// <param name="a"> An <see cref="Func{T, TResult}"/> to be executed with a return value indicating whether it can be removed after execution.</param>
public static void QueueAction(Func<bool> a)
{
Networking.ToggleConnection(null);
Main.QueueAction(a);
}
/// <summary>
@ -246,12 +282,12 @@ namespace RageCoop.Client.Scripting
/// <param name="args">The objects conataing your data, see <see cref="CustomEventReceivedArgs"/> for a list of supported types</param>
public static void SendCustomEvent(int eventHash, params object[] args)
{
var p = new Packets.CustomEvent()
Networking.Peer.SendTo(new Packets.CustomEvent()
{
Args=args,
Hash=eventHash
};
Networking.Send(p, ConnectionChannel.Event, Lidgren.Network.NetDeliveryMethod.ReliableOrdered);
Args = args,
Hash = eventHash
}, Networking.ServerConnection, ConnectionChannel.Event, Lidgren.Network.NetDeliveryMethod.ReliableOrdered);
}
/// <summary>
@ -270,6 +306,34 @@ namespace RageCoop.Client.Scripting
handlers.Add(handler);
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static void RequestSharedFile(string name, Action<string> callback)
{
EventHandler<string> handler = (s, e) =>
{
if (e.EndsWith(name))
{
callback(e);
}
};
DownloadManager.DownloadCompleted += handler;
Networking.GetResponse<Packets.FileTransferResponse>(new Packets.FileTransferRequest()
{
Name = name,
},
(p) =>
{
if (p.Response != FileResponse.Loaded)
{
DownloadManager.DownloadCompleted -= handler;
throw new ArgumentException("Requested file was not found on the server: " + name);
}
});
}
#endregion
}
}

View File

@ -1,27 +1,26 @@
using System;
using System.Collections.Generic;
using GTA.Native;
using GTA;
using GTA.Math;
using GTA;
using RageCoop.Core;
using GTA.Native;
using RageCoop.Core.Scripting;
using System.Linq;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace RageCoop.Client.Scripting
{
internal class BaseScript : ClientScript
{
private bool _isHost=false;
private bool _isHost = false;
public override void OnStart()
{
API.Events.OnPedDeleted+=(s, p) => { API.SendCustomEvent(CustomEvents.OnPedDeleted, p.ID); };
API.Events.OnVehicleDeleted+=(s, p) => { API.SendCustomEvent(CustomEvents.OnVehicleDeleted, p.ID); };
API.Events.OnPedDeleted += (s, p) => { API.SendCustomEvent(CustomEvents.OnPedDeleted, p.ID); };
API.Events.OnVehicleDeleted += (s, p) => { API.SendCustomEvent(CustomEvents.OnVehicleDeleted, p.ID); };
API.Events.OnPlayerDied += (s, m) => { API.SendCustomEvent(CustomEvents.OnPlayerDied, m); };
API.RegisterCustomEventHandler(CustomEvents.SetAutoRespawn,SetAutoRespawn);
API.RegisterCustomEventHandler(CustomEvents.SetDisplayNameTag,SetDisplayNameTag);
API.RegisterCustomEventHandler(CustomEvents.NativeCall,NativeCall);
API.RegisterCustomEventHandler(CustomEvents.SetAutoRespawn, SetAutoRespawn);
API.RegisterCustomEventHandler(CustomEvents.SetDisplayNameTag, SetDisplayNameTag);
API.RegisterCustomEventHandler(CustomEvents.NativeCall, NativeCall);
API.RegisterCustomEventHandler(CustomEvents.ServerPropSync, ServerObjectSync);
API.RegisterCustomEventHandler(CustomEvents.DeleteServerProp, DeleteServerProp);
API.RegisterCustomEventHandler(CustomEvents.DeleteEntity, DeleteEntity);
@ -30,8 +29,9 @@ namespace RageCoop.Client.Scripting
API.RegisterCustomEventHandler(CustomEvents.DeleteServerBlip, DeleteServerBlip);
API.RegisterCustomEventHandler(CustomEvents.CreateVehicle, CreateVehicle);
API.RegisterCustomEventHandler(CustomEvents.UpdatePedBlip, UpdatePedBlip);
API.RegisterCustomEventHandler(CustomEvents.IsHost, (e) => { _isHost=(bool)e.Args[0]; });
API.RegisterCustomEventHandler(CustomEvents.IsHost, (e) => { _isHost = (bool)e.Args[0]; });
API.RegisterCustomEventHandler(CustomEvents.WeatherTimeSync, WeatherTimeSync);
API.RegisterCustomEventHandler(CustomEvents.OnPlayerDied, (e) => { GTA.UI.Notification.PostTicker((string)e.Args[0], false); });
Task.Run(() =>
{
while (true)
@ -42,12 +42,11 @@ namespace RageCoop.Client.Scripting
{
unsafe
{
var time = World.CurrentTimeOfDay;
int weather1 = default(int);
int weather2 = default(int);
float percent2 = default(float);
Function.Call(Hash._GET_WEATHER_TYPE_TRANSITION, &weather1, &weather2, &percent2);
API.SendCustomEvent(CustomEvents.WeatherTimeSync, time.Hours, time.Minutes, time.Seconds, weather1, weather2, percent2);
Function.Call(Hash.GET_CURR_WEATHER_STATE, &weather1, &weather2, &percent2);
API.SendCustomEvent(CustomEvents.WeatherTimeSync, GTA.Chrono.GameClock.Hour, GTA.Chrono.GameClock.Minute, GTA.Chrono.GameClock.Second, weather1, weather2, percent2);
}
});
}
@ -59,33 +58,35 @@ namespace RageCoop.Client.Scripting
private void WeatherTimeSync(CustomEventReceivedArgs e)
{
World.CurrentTimeOfDay=new TimeSpan((int)e.Args[0], (int)e.Args[1], (int)e.Args[2]);
Function.Call(Hash._SET_WEATHER_TYPE_TRANSITION, (int)e.Args[3], (int)e.Args[4], (float)e.Args[5]);
GTA.Chrono.GameClock.Hour = (int)e.Args[0];
GTA.Chrono.GameClock.Minute = (int)e.Args[1];
GTA.Chrono.GameClock.Second = (int)e.Args[2];
Function.Call(Hash.SET_CURR_WEATHER_STATE, (int)e.Args[3], (int)e.Args[4], (float)e.Args[5]);
}
private void SetDisplayNameTag(CustomEventReceivedArgs e)
{
var p = PlayerList.GetPlayer((int)e.Args[0]);
if(p != null) { p.DisplayNameTag=(bool)e.Args[1]; }
if (p != null) { p.DisplayNameTag = (bool)e.Args[1]; }
}
private void UpdatePedBlip(CustomEventReceivedArgs e)
{
var p = Entity.FromHandle((int)e.Args[0]);
if (p == null) { return; }
if (p.Handle==Game.Player.Character.Handle)
if (p.Handle == Game.Player.Character.Handle)
{
API.Config.BlipColor=(BlipColor)(byte)e.Args[1];
API.Config.BlipSprite=(BlipSprite)(ushort)e.Args[2];
API.Config.BlipScale=(float)e.Args[3];
API.Config.BlipColor = (BlipColor)(byte)e.Args[1];
API.Config.BlipSprite = (BlipSprite)(ushort)e.Args[2];
API.Config.BlipScale = (float)e.Args[3];
}
else
{
var b = p.AttachedBlip;
if (b == null) { b=p.AddBlip(); }
b.Color=(BlipColor)(byte)e.Args[1];
b.Sprite=(BlipSprite)(ushort)e.Args[2];
b.Scale=(float)e.Args[3];
if (b == null) { b = p.AddBlip(); }
b.Color = (BlipColor)(byte)e.Args[1];
b.Sprite = (BlipSprite)(ushort)e.Args[2];
b.Scale = (float)e.Args[3];
}
}
@ -93,18 +94,18 @@ namespace RageCoop.Client.Scripting
{
var vehicleModel = (Model)e.Args[1];
vehicleModel.Request(1000);
Vehicle veh= World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3]);
while (veh==null)
Vehicle veh = World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3]);
while (veh == null)
{
veh = World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3]);
veh = World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3]);
Thread.Sleep(10);
}
veh.CanPretendOccupants=false;
veh.CanPretendOccupants = false;
var v = new SyncedVehicle()
{
ID=(int)e.Args[0],
MainVehicle=veh,
OwnerID=Main.LocalPlayerID,
ID = (int)e.Args[0],
MainVehicle = veh,
OwnerID = Main.LocalPlayerID,
};
EntityPool.Add(v);
}
@ -120,17 +121,16 @@ namespace RageCoop.Client.Scripting
private void ServerBlipSync(CustomEventReceivedArgs obj)
{
int id= (int)obj.Args[0];
var sprite=(BlipSprite)(ushort)obj.Args[1];
int id = (int)obj.Args[0];
var sprite = (BlipSprite)(ushort)obj.Args[1];
var color = (BlipColor)(byte)obj.Args[2];
var scale=(float)obj.Args[3];
var pos=(Vector3)obj.Args[4];
int rot= (int)obj.Args[5];
var name=(string)obj.Args[6];
Blip blip;
if (!EntityPool.ServerBlips.TryGetValue(id, out blip))
var scale = (float)obj.Args[3];
var pos = (Vector3)obj.Args[4];
int rot = (int)obj.Args[5];
var name = (string)obj.Args[6];
if (!EntityPool.ServerBlips.TryGetValue(id, out Blip blip))
{
EntityPool.ServerBlips.Add(id, blip=World.CreateBlip(pos));
EntityPool.ServerBlips.Add(id, blip = World.CreateBlip(pos));
}
blip.Sprite = sprite;
blip.Color = color;
@ -151,15 +151,15 @@ namespace RageCoop.Client.Scripting
}
private void SetNameTag(CustomEventReceivedArgs e)
{
var p =PlayerList.GetPlayer((int)e.Args[0]);
if(p!= null)
var p = PlayerList.GetPlayer((int)e.Args[0]);
if (p != null)
{
p.DisplayNameTag=(bool)e.Args[1];
p.DisplayNameTag = (bool)e.Args[1];
}
}
private void SetAutoRespawn(CustomEventReceivedArgs args)
{
API.Config.EnableAutoRespawn=(bool)args.Args[0];
API.Config.EnableAutoRespawn = (bool)args.Args[0];
}
private void DeleteServerProp(CustomEventReceivedArgs e)
{
@ -169,7 +169,7 @@ namespace RageCoop.Client.Scripting
EntityPool.ServerProps.Remove(id);
prop?.MainProp?.Delete();
}
}
private void ServerObjectSync(CustomEventReceivedArgs e)
{
@ -179,13 +179,13 @@ namespace RageCoop.Client.Scripting
{
if (!EntityPool.ServerProps.TryGetValue(id, out prop))
{
EntityPool.ServerProps.Add(id, prop=new SyncedProp(id));
EntityPool.ServerProps.Add(id, prop = new SyncedProp(id));
}
}
prop.LastSynced=Main.Ticked+1;
prop.ModelHash= (Model)e.Args[1];
prop.Position=(Vector3)e.Args[2];
prop.Rotation=(Vector3)e.Args[3];
prop.LastSynced = Main.Ticked + 1;
prop.Model = (Model)e.Args[1];
prop.Position = (Vector3)e.Args[2];
prop.Rotation = (Vector3)e.Args[3];
prop.Update();
}
private void NativeCall(CustomEventReceivedArgs e)
@ -193,15 +193,15 @@ namespace RageCoop.Client.Scripting
List<InputArgument> arguments = new List<InputArgument>();
int i;
var ty = (byte)e.Args[0];
TypeCode returnType=(TypeCode)ty;
i = returnType==TypeCode.Empty ? 1 : 2;
TypeCode returnType = (TypeCode)ty;
i = returnType == TypeCode.Empty ? 1 : 2;
var hash = (Hash)e.Args[i++];
for(; i<e.Args.Length;i++)
for (; i < e.Args.Length; i++)
{
arguments.Add(GetInputArgument(e.Args[i]));
}
if (returnType==TypeCode.Empty)
if (returnType == TypeCode.Empty)
{
Function.Call(hash, arguments.ToArray());
return;
@ -300,6 +300,6 @@ namespace RageCoop.Client.Scripting
default:
return null;
}
}
}
}
}

View File

@ -27,5 +27,10 @@ namespace RageCoop.Client.Scripting
/// </summary>
public ClientResource CurrentResource { get; internal set; }
/// <summary>
/// Eqivalent of <see cref="ClientResource.Logger"/> in <see cref="CurrentResource"/>
/// </summary>
public Core.Logger Logger => CurrentResource.Logger;
}
}

View File

@ -1,286 +1,265 @@
using System.IO;
using RageCoop.Core.Scripting;
using ICSharpCode.SharpZipLib.Zip;
using RageCoop.Core;
using ICSharpCode.SharpZipLib.Zip;
using RageCoop.Core.Scripting;
using System;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace RageCoop.Client.Scripting
{
/// <summary>
///
/// </summary>
public class ClientResource
{
/// <summary>
/// Name of the resource
/// </summary>
public string Name { get; internal set; }
/// <summary>
/// A resource-specific folder that can be used to store your files.
/// </summary>
public string DataFolder { get; internal set; }
/// <summary>
/// Get all <see cref="ClientScript"/> instance in this resource.
/// </summary>
public List<ClientScript> Scripts { get; internal set; } = new List<ClientScript>();
/// <summary>
/// Get the <see cref="ResourceFile"/> where this script is loaded from.
/// </summary>
public Dictionary<string, ResourceFile> Files { get; internal set; } = new Dictionary<string, ResourceFile>();
}
internal class Resources
{
public Resources(){
BaseScriptType = "RageCoop.Client.Scripting.ClientScript";
Logger = Main.Logger;
}
private void StartAll()
{
lock (LoadedResources)
{
foreach (var d in LoadedResources)
{
foreach (var s in d.Scripts)
{
/// <summary>
///
/// </summary>
public class ClientResource
{
/// <summary>
/// Name of the resource
/// </summary>
public string Name { get; internal set; }
/// <summary>
/// A resource-specific folder that can be used to store your files.
/// </summary>
public string DataFolder { get; internal set; }
/// <summary>
/// Get all <see cref="ClientScript"/> instance in this resource.
/// </summary>
public List<ClientScript> Scripts { get; internal set; } = new List<ClientScript>();
/// <summary>
/// Get the <see cref="ResourceFile"/> where this script is loaded from.
/// </summary>
public Dictionary<string, ResourceFile> Files { get; internal set; } = new Dictionary<string, ResourceFile>();
/// <summary>
/// A <see cref="Core.Logger"/> instance that can be used to debug your resource.
/// </summary>
public Logger Logger { get; internal set; }
}
internal class Resources
{
private readonly List<ClientResource> LoadedResources = new List<ClientResource>();
private const string BaseScriptType = "RageCoop.Client.Scripting.ClientScript";
private Logger Logger { get; set; }
public Resources()
{
Logger = Main.Logger;
}
private void StartAll()
{
lock (LoadedResources)
{
foreach (var d in LoadedResources)
{
foreach (var s in d.Scripts)
{
try
{
s.OnStart();
}
catch(Exception ex)
{
Logger.Error("Error occurred when starting script:"+s.GetType().FullName);
Logger?.Error(ex);
s.CurrentResource = d;
s.OnStart();
}
}
}
}
}
private void StopAll()
{
lock (LoadedResources)
{
foreach (var d in LoadedResources)
{
foreach (var s in d.Scripts)
{
try
{
s.OnStop();
}
catch (Exception ex)
{
Logger.Error("Error occurred when stopping script:"+s.GetType().FullName);
Logger?.Error(ex);
}
}
}
}
}
public void Load(string path,string[] zips)
{
foreach (var zip in zips)
{
var zipPath=Path.Combine(path, zip);
Logger?.Info($"Loading resource: {Path.GetFileNameWithoutExtension(zip)}");
LoadResource(new ZipFile(zipPath),Path.Combine(path,"data"));
}
StartAll();
}
public void Unload()
{
StopAll();
if (LoadedResources.Count > 0)
{
API.QueueAction(()=>Util.Reload());
}
LoadedResources.Clear();
catch (Exception ex)
{
Logger.Error("Error occurred when starting script:" + s.GetType().FullName);
Logger?.Error(ex);
}
}
}
}
}
private void StopAll()
{
lock (LoadedResources)
{
foreach (var d in LoadedResources)
{
foreach (var s in d.Scripts)
{
try
{
s.OnStop();
}
catch (Exception ex)
{
Logger.Error("Error occurred when stopping script:" + s.GetType().FullName);
Logger?.Error(ex);
}
}
}
}
}
public void Load(string path, string[] zips)
{
LoadedResources.Clear();
foreach (var zip in zips)
{
var zipPath = Path.Combine(path, zip);
Logger?.Info($"Loading resource: {Path.GetFileNameWithoutExtension(zip)}");
LoadResource(new ZipFile(zipPath), Path.Combine(path, "data"));
}
StartAll();
}
public void Unload()
{
StopAll();
if (LoadedResources.Count > 0)
{
API.QueueAction(() => Util.Reload());
}
LoadedResources.Clear();
}
private List<string> ToIgnore = new List<string>
{
"RageCoop.Client.dll",
"RageCoop.Core.dll",
"RageCoop.Server.dll",
"ScriptHookVDotNet3.dll"
};
private List<ClientResource> LoadedResources = new List<ClientResource>();
private string BaseScriptType;
public Logger Logger { get; set; }
private void LoadResource(ZipFile file, string dataFolderRoot)
{
var r = new ClientResource()
{
Scripts = new List<ClientScript>(),
Name=Path.GetFileNameWithoutExtension(file.Name),
DataFolder=Path.Combine(dataFolderRoot, Path.GetFileNameWithoutExtension(file.Name))
};
Directory.CreateDirectory(r.DataFolder);
private void LoadResource(ZipFile file, string dataFolderRoot)
{
List<Action> toLoad = new List<Action>(10);
var r = new ClientResource()
{
Logger = Main.Logger,
Scripts = new List<ClientScript>(),
Name = Path.GetFileNameWithoutExtension(file.Name),
DataFolder = Path.Combine(dataFolderRoot, Path.GetFileNameWithoutExtension(file.Name))
};
Directory.CreateDirectory(r.DataFolder);
foreach (ZipEntry entry in file)
{
ResourceFile rFile;
r.Files.Add(entry.Name, rFile=new ResourceFile()
{
Name=entry.Name,
IsDirectory=entry.IsDirectory,
});
if (!entry.IsDirectory)
{
rFile.GetStream=() => { return file.GetInputStream(entry); };
if (entry.Name.EndsWith(".dll"))
{
var tmp = Path.GetTempFileName();
var f = File.OpenWrite(tmp);
rFile.GetStream().CopyTo(f);
f.Close();
LoadScriptsFromAssembly(rFile, tmp, r, false);
}
}
}
LoadedResources.Add(r);
file.Close();
}
private bool LoadScriptsFromAssembly(ResourceFile file, string path, ClientResource resource, bool shadowCopy = true)
{
lock (LoadedResources)
{
if (!IsManagedAssembly(path)) { return false; }
if (ToIgnore.Contains(file.Name)) { try { File.Delete(path); } catch { }; return false; }
foreach (ZipEntry entry in file)
{
ResourceFile rFile;
r.Files.Add(entry.Name, rFile = new ResourceFile()
{
Name = entry.Name,
IsDirectory = entry.IsDirectory,
});
if (!entry.IsDirectory)
{
rFile.GetStream = () => { return file.GetInputStream(entry); };
if (entry.Name.EndsWith(".dll") && !entry.Name.Contains("/"))
{
// Don't load API assembly
if (Path.GetFileName(entry.Name).CanBeIgnored()) { continue; }
var tmp = Path.GetTempFileName();
var f = File.OpenWrite(tmp);
rFile.GetStream().CopyTo(f);
f.Close();
if (!IsManagedAssembly(tmp))
{
continue;
}
var asm = Assembly.LoadFrom(tmp);
toLoad.Add(() => LoadScriptsFromAssembly(rFile, asm, entry.Name, r));
}
}
}
foreach (var a in toLoad)
{
a();
}
LoadedResources.Add(r);
file.Close();
}
private bool LoadScriptsFromAssembly(ResourceFile rfile, Assembly assembly, string filename, ClientResource toload)
{
int count = 0;
Logger?.Debug($"Loading assembly {file.Name} ...");
try
{
// Find all script types in the assembly
foreach (var type in assembly.GetTypes().Where(x => IsSubclassOf(x, BaseScriptType)))
{
ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
if (constructor != null && constructor.IsPublic)
{
try
{
// Invoke script constructor
var script = constructor.Invoke(null) as ClientScript;
// script.CurrentResource = toload;
script.CurrentFile = rfile;
script.CurrentResource = toload;
toload.Scripts.Add(script);
count++;
}
catch (Exception ex)
{
Logger?.Error($"Error occurred when loading script: {type.FullName}.");
Logger?.Error(ex);
}
}
else
{
Logger?.Error($"Script {type.FullName} has an invalid contructor.");
}
}
}
catch (ReflectionTypeLoadException ex)
{
Logger?.Error($"Failed to load assembly {rfile.Name}: ");
Logger?.Error(ex);
foreach (var e in ex.LoaderExceptions)
{
Logger?.Error(e);
}
return false;
}
Assembly assembly;
Logger?.Info($"Loaded {count} script(s) in {rfile.Name}");
return count != 0;
}
private bool IsManagedAssembly(string filename)
{
try
{
using (Stream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
if (file.Length < 64)
return false;
try
{
if (shadowCopy)
{
var temp = Path.GetTempFileName();
File.Copy(path, temp, true);
assembly = Assembly.LoadFrom(temp);
}
else
{
assembly = Assembly.LoadFrom(path);
}
}
catch (Exception ex)
{
Logger?.Error("Unable to load "+file.Name);
Logger?.Error(ex);
return false;
}
using (BinaryReader bin = new BinaryReader(file))
{
// PE header starts at offset 0x3C (60). Its a 4 byte header.
file.Position = 0x3C;
uint offset = bin.ReadUInt32();
if (offset == 0)
offset = 0x80;
return LoadScriptsFromAssembly(file, assembly, path, resource);
}
}
private bool LoadScriptsFromAssembly(ResourceFile rfile, Assembly assembly, string filename, ClientResource toload)
{
int count = 0;
// Ensure there is at least enough room for the following structures:
// 24 byte PE Signature & Header
// 28 byte Standard Fields (24 bytes for PE32+)
// 68 byte NT Fields (88 bytes for PE32+)
// >= 128 byte Data Dictionary Table
if (offset > file.Length - 256)
return false;
try
{
// Find all script types in the assembly
foreach (var type in assembly.GetTypes().Where(x => IsSubclassOf(x, BaseScriptType)))
{
ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
if (constructor != null && constructor.IsPublic)
{
try
{
// Invoke script constructor
var script = constructor.Invoke(null) as ClientScript;
// script.CurrentResource = toload;
script.CurrentFile=rfile;
script.CurrentResource=toload;
toload.Scripts.Add(script);
count++;
}
catch (Exception ex)
{
Logger?.Error($"Error occurred when loading script: {type.FullName}.");
Logger?.Error(ex);
}
}
else
{
Logger?.Error($"Script {type.FullName} has an invalid contructor.");
}
}
}
catch (ReflectionTypeLoadException ex)
{
Logger?.Error($"Failed to load assembly {rfile.Name}: ");
Logger?.Error(ex);
foreach (var e in ex.LoaderExceptions)
{
Logger?.Error(e);
}
return false;
}
// Check the PE signature. Should equal 'PE\0\0'.
file.Position = offset;
if (bin.ReadUInt32() != 0x00004550)
return false;
Logger?.Info($"Loaded {count} script(s) in {rfile.Name}");
return count != 0;
}
private bool IsManagedAssembly(string filename)
{
try
{
using (Stream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
if (file.Length < 64)
return false;
// Read PE magic number from Standard Fields to determine format.
file.Position += 20;
var peFormat = bin.ReadUInt16();
if (peFormat != 0x10b /* PE32 */ && peFormat != 0x20b /* PE32Plus */)
return false;
using (BinaryReader bin = new BinaryReader(file))
{
// PE header starts at offset 0x3C (60). Its a 4 byte header.
file.Position = 0x3C;
uint offset = bin.ReadUInt32();
if (offset == 0)
offset = 0x80;
// Ensure there is at least enough room for the following structures:
// 24 byte PE Signature & Header
// 28 byte Standard Fields (24 bytes for PE32+)
// 68 byte NT Fields (88 bytes for PE32+)
// >= 128 byte Data Dictionary Table
if (offset > file.Length - 256)
return false;
// Check the PE signature. Should equal 'PE\0\0'.
file.Position = offset;
if (bin.ReadUInt32() != 0x00004550)
return false;
// Read PE magic number from Standard Fields to determine format.
file.Position += 20;
var peFormat = bin.ReadUInt16();
if (peFormat != 0x10b /* PE32 */ && peFormat != 0x20b /* PE32Plus */)
return false;
// Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
// When this is non-zero then the file contains CLI data otherwise not.
file.Position = offset + (peFormat == 0x10b ? 232 : 248);
return bin.ReadUInt32() != 0;
}
}
}
catch
{
// This is likely not a valid assembly if any IO exceptions occur during reading
return false;
}
}
private bool IsSubclassOf(Type type, string baseTypeName)
{
for (Type t = type.BaseType; t != null; t = t.BaseType)
if (t.FullName == baseTypeName)
return true;
return false;
}
}
// Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
// When this is non-zero then the file contains CLI data otherwise not.
file.Position = offset + (peFormat == 0x10b ? 232 : 248);
return bin.ReadUInt32() != 0;
}
}
}
catch
{
// This is likely not a valid assembly if any IO exceptions occur during reading
return false;
}
}
private bool IsSubclassOf(Type type, string baseTypeName)
{
for (Type t = type.BaseType; t != null; t = t.BaseType)
if (t.FullName == baseTypeName)
return true;
return false;
}
}
}

View File

@ -1,44 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using RageCoop.Core;
using System.IO;
using RageCoop.Core;
using System.Security.Cryptography;
namespace RageCoop.Client
{
internal class Security
{
public RSA ServerRSA { get; set; }
public Aes ClientAes { get; set; }=Aes.Create();
private Logger Logger;
public Aes ClientAes { get; set; } = Aes.Create();
private readonly Logger Logger;
public Security(Logger logger)
{
Logger = logger;
ClientAes.GenerateKey();
ClientAes.GenerateIV();
}
public void GetSymmetricKeysCrypted(out byte[] cryptedKey,out byte[] cryptedIV)
public void GetSymmetricKeysCrypted(out byte[] cryptedKey, out byte[] cryptedIV)
{
// Logger?.Debug($"Aes.Key:{ClientAes.Key.Dump()}, Aes.IV:{ClientAes.IV.Dump()}");
cryptedKey =ServerRSA.Encrypt(ClientAes.Key, RSAEncryptionPadding.Pkcs1);
cryptedIV =ServerRSA.Encrypt(ClientAes.IV,RSAEncryptionPadding.Pkcs1);
cryptedKey = ServerRSA.Encrypt(ClientAes.Key, RSAEncryptionPadding.Pkcs1);
cryptedIV = ServerRSA.Encrypt(ClientAes.IV, RSAEncryptionPadding.Pkcs1);
}
public byte[] Encrypt(byte[] data)
{
return new CryptoStream(new MemoryStream(data), ClientAes.CreateEncryptor(), CryptoStreamMode.Read).ReadToEnd();
}
public void SetServerPublicKey(byte[] modulus,byte[] exponent)
public byte[] Decrypt(byte[] data)
{
return new CryptoStream(new MemoryStream(data), ClientAes.CreateDecryptor(), CryptoStreamMode.Read).ReadToEnd();
}
public void SetServerPublicKey(byte[] modulus, byte[] exponent)
{
var para = new RSAParameters();
para.Modulus = modulus;
para.Exponent = exponent;
ServerRSA=RSA.Create(para);
ServerRSA = RSA.Create(para);
}
public void Regen()
{
ClientAes=Aes.Create();
ClientAes = Aes.Create();
ClientAes.GenerateKey();
ClientAes.GenerateIV();
}

View File

@ -22,17 +22,21 @@ namespace RageCoop.Client
/// <summary>
/// Don't use it!
/// </summary>
public string MasterServer { get; set; } = "https://masterserver.ragecoop.online/";
public string MasterServer { get; set; } = "https://masterserver.ragecoop.com/";
/// <summary>
/// Don't use it!
/// </summary>
public bool FlipMenu { get; set; } = false;
/// <summary>
/// Don't use it!
/// </summary>
public bool Voice { get; set; } = false;
/// <summary>
/// LogLevel for RageCoop.
/// 0:Trace, 1:Debug, 2:Info, 3:Warning, 4:Error
/// </summary>
public int LogLevel = 2;
public int LogLevel = 00;
/// <summary>
/// The key to open menu
@ -42,12 +46,12 @@ namespace RageCoop.Client
/// <summary>
/// The key to enter a vehicle as passenger.
/// </summary>
public Keys PassengerKey { get; set; }=Keys.G;
public Keys PassengerKey { get; set; } = Keys.G;
/// <summary>
/// Disable world NPC traffic, mission entities won't be affected
/// </summary>
public bool DisableTraffic { get; set; } = true;
public bool DisableTraffic { get; set; } = false;
/// <summary>
/// Bring up pause menu but don't freeze time when FrontEndPauseAlternate(Esc) is pressed.
@ -57,15 +61,31 @@ namespace RageCoop.Client
/// <summary>
/// The game won't spawn more NPC traffic if the limit is exceeded. -1 for unlimited (not recommended).
/// </summary>
public int WorldVehicleSoftLimit { get; set; } = 35;
public int WorldVehicleSoftLimit { get; set; } = 20;
/// <summary>
/// The game won't spawn more NPC traffic if the limit is exceeded. -1 for unlimited (not recommended).
/// </summary>
public int WorldPedSoftLimit { get; set; } = 50;
public int WorldPedSoftLimit { get; set; } = 30;
/// <summary>
/// The directory where log and resources downloaded from server will be placed.
/// </summary>
public string DataDirectory { get; set; } = "Scripts\\RageCoop\\Data";
/// <summary>
/// Show the owner name of the entity you're aiming at
/// </summary>
public bool ShowEntityOwnerName { get; set; } = false;
/// <summary>
/// Show other player's nametag on your screen
/// </summary>
public bool ShowPlayerNameTag { get; set; } = true;
/// <summary>
/// Show other player's blip on map
/// </summary>
public bool ShowPlayerBlip { get; set; } = true;
}
}

View File

@ -0,0 +1,161 @@
using GTA;
using GTA.Native;
namespace RageCoop.Client
{
public partial class SyncedPed
{
private void DisplaySpeaking(bool speaking)
{
if (!MainPed.IsHuman)
return;
if (speaking)
{
Function.Call(Hash.PLAY_FACIAL_ANIM, MainPed.Handle, "mic_chatter", "mp_facial");
return;
}
switch (MainPed.Gender)
{
case Gender.Male:
Function.Call(Hash.PLAY_FACIAL_ANIM, MainPed.Handle, "mood_normal_1", "facials@gen_male@variations@normal");
break;
case Gender.Female:
Function.Call(Hash.PLAY_FACIAL_ANIM, MainPed.Handle, "mood_normal_1", "facials@gen_female@variations@normal");
break;
default:
Function.Call(Hash.PLAY_FACIAL_ANIM, MainPed.Handle, "mood_normal_1", "facials@mime@variations@normal");
break;
}
}
private void DisplayInCover()
{
var ourAnim = GetCoverAnim();
var animDict = GetCoverIdleAnimDict();
if (ourAnim != null && animDict != null)
{
var flag = AnimationFlags.Loop;
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed, animDict, ourAnim, 3))
{
MainPed.Task.ClearAll();
Function.Call(Hash.TASK_PLAY_ANIM, MainPed, LoadAnim(animDict), ourAnim, 8f, 10f, -1, flag, -8f, 1, 1, 1);
}
}
}
internal string GetCoverAnim()
{
if (IsInCover)
{
if (IsBlindFiring)
{
if (IsInCover)
return IsInCoverFacingLeft ? "blindfire_low_l_aim_med" : "blindfire_low_r_aim_med";
return IsInCoverFacingLeft ? "blindfire_hi_l_aim_med" : "blindfire_hi_r_aim_med";
}
return IsInCoverFacingLeft ? "idle_l_corner" : "idle_r_corner";
}
return null;
}
internal string GetCoverIdleAnimDict()
{
if (!IsInCover) return "";
var altitude = IsInLowCover ? "low" : "high";
var hands = GetWeaponHandsHeld(CurrentWeaponHash);
if (IsBlindFiring)
{
if (hands == 1) return "cover@weapon@1h";
if (hands == 2 || hands == 5) return "cover@weapon@2h";
}
if (hands == 1) return "cover@idles@1h@" + altitude + "@_a";
if (hands == 2 || hands == 5) return "cover@idles@2h@" + altitude + "@_a";
if (hands == 3 || hands == 4 || hands == 0) return "cover@idles@unarmed@" + altitude + "@_a";
return "";
}
internal int GetWeaponHandsHeld(uint weapon)
{
switch (weapon)
{
case unchecked((uint)WeaponHash.Unarmed):
return 0;
case unchecked((uint)WeaponHash.RPG):
case unchecked((uint)WeaponHash.HomingLauncher):
case unchecked((uint)WeaponHash.Firework):
return 5;
case unchecked((uint)WeaponHash.Minigun):
return 5;
case unchecked((uint)WeaponHash.GolfClub):
case unchecked((uint)WeaponHash.PoolCue):
case unchecked((uint)WeaponHash.Bat):
return 4;
case unchecked((uint)WeaponHash.Knife):
case unchecked((uint)WeaponHash.Nightstick):
case unchecked((uint)WeaponHash.Hammer):
case unchecked((uint)WeaponHash.Crowbar):
case unchecked((uint)WeaponHash.Wrench):
case unchecked((uint)WeaponHash.BattleAxe):
case unchecked((uint)WeaponHash.Dagger):
case unchecked((uint)WeaponHash.Hatchet):
case unchecked((uint)WeaponHash.KnuckleDuster):
case unchecked((uint)-581044007):
case unchecked((uint)-102323637):
case unchecked((uint)-538741184):
return 3;
case unchecked((uint)-1357824103):
case unchecked((uint)-1074790547):
case unchecked(2132975508):
case unchecked((uint)-2084633992):
case unchecked((uint)-952879014):
case unchecked(100416529):
case unchecked((uint)WeaponHash.Gusenberg):
case unchecked((uint)WeaponHash.MG):
case unchecked((uint)WeaponHash.CombatMG):
case unchecked((uint)WeaponHash.CombatPDW):
case unchecked((uint)WeaponHash.AssaultSMG):
case unchecked((uint)WeaponHash.SMG):
case unchecked((uint)WeaponHash.HeavySniper):
case unchecked((uint)WeaponHash.PumpShotgun):
case unchecked((uint)WeaponHash.HeavyShotgun):
case unchecked((uint)WeaponHash.Musket):
case unchecked((uint)WeaponHash.AssaultShotgun):
case unchecked((uint)WeaponHash.BullpupShotgun):
case unchecked((uint)WeaponHash.SawnOffShotgun):
case unchecked((uint)WeaponHash.SweeperShotgun):
case unchecked((uint)WeaponHash.CompactRifle):
return 2;
}
return 1;
}
private string LoadAnim(string anim)
{
ulong startTime = Util.GetTickCount64();
while (!Function.Call<bool>(Hash.HAS_ANIM_DICT_LOADED, anim))
{
Script.Yield();
Function.Call(Hash.REQUEST_ANIM_DICT, anim);
if (Util.GetTickCount64() - startTime >= 1000)
{
break;
}
}
return anim;
}
}
}

View File

@ -0,0 +1,81 @@
using GTA;
using GTA.Math;
using RageCoop.Core;
using System.Collections.Generic;
namespace RageCoop.Client
{
/// <summary>
/// ?
/// </summary>
public partial class SyncedPed : SyncedEntity
{
internal Blip PedBlip = null;
internal BlipColor BlipColor = (BlipColor)255;
internal BlipSprite BlipSprite = 0;
internal float BlipScale = 1;
internal int VehicleID
{
get => CurrentVehicle?.ID ?? 0;
set
{
if (CurrentVehicle == null || value != CurrentVehicle?.ID)
{
CurrentVehicle = EntityPool.GetVehicleByID(value);
}
}
}
internal SyncedVehicle CurrentVehicle { get; private set; }
internal VehicleSeat Seat;
public bool IsPlayer { get => OwnerID == ID && ID != 0; }
public Ped MainPed { get; internal set; }
internal int Health { get; set; }
internal Vector3 HeadPosition { get; set; }
internal Vector3 RightFootPosition { get; set; }
internal Vector3 LeftFootPosition { get; set; }
internal byte WeaponTint { get; set; }
private bool _lastRagdoll = false;
private ulong _lastRagdollTime = 0;
private bool _lastInCover = false;
private byte[] _lastClothes = null;
internal byte[] Clothes { get; set; }
internal float Heading { get; set; }
internal ulong LastSpeakingTime { get; set; } = 0;
internal bool IsSpeaking { get; set; } = false;
public byte Speed { get; set; }
private bool _lastIsJumping = false;
internal PedDataFlags Flags;
internal bool IsAiming => Flags.HasPedFlag(PedDataFlags.IsAiming);
internal bool _lastDriveBy;
internal bool IsReloading => Flags.HasPedFlag(PedDataFlags.IsReloading);
internal bool IsJumping => Flags.HasPedFlag(PedDataFlags.IsJumping);
internal bool IsRagdoll => Flags.HasPedFlag(PedDataFlags.IsRagdoll);
internal bool IsOnFire => Flags.HasPedFlag(PedDataFlags.IsOnFire);
internal bool IsInParachuteFreeFall => Flags.HasPedFlag(PedDataFlags.IsInParachuteFreeFall);
internal bool IsParachuteOpen => Flags.HasPedFlag(PedDataFlags.IsParachuteOpen);
internal bool IsOnLadder => Flags.HasPedFlag(PedDataFlags.IsOnLadder);
internal bool IsVaulting => Flags.HasPedFlag(PedDataFlags.IsVaulting);
internal bool IsInCover => Flags.HasPedFlag(PedDataFlags.IsInCover);
internal bool IsInLowCover => Flags.HasPedFlag(PedDataFlags.IsInLowCover);
internal bool IsInCoverFacingLeft => Flags.HasPedFlag(PedDataFlags.IsInCoverFacingLeft);
internal bool IsBlindFiring => Flags.HasPedFlag(PedDataFlags.IsBlindFiring);
internal bool IsInStealthMode => Flags.HasPedFlag(PedDataFlags.IsInStealthMode);
internal Prop ParachuteProp { get; set; } = null;
internal uint CurrentWeaponHash { get; set; }
private Dictionary<uint, bool> _lastWeaponComponents = null;
internal Dictionary<uint, bool> WeaponComponents { get; set; } = null;
private Entity _weaponObj;
internal Vector3 AimCoords { get; set; }
private readonly string[] _currentAnimation = new string[2] { "", "" };
private bool LastMoving;
}
}

View File

@ -1,22 +1,20 @@
using System;
using System.Linq;
using System.Drawing;
using System.Collections.Generic;
using RageCoop.Core;
using GTA;
using GTA.Native;
using GTA;
using GTA.Math;
using GTA.Native;
using LemonUI.Elements;
using System.Security.Cryptography;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
namespace RageCoop.Client
{
/// <summary>
/// ?
/// </summary>
public class SyncedPed:SyncedEntity
public partial class SyncedPed : SyncedEntity
{
#region CONSTRUCTORS
/// <summary>
/// Create a local entity (outgoing sync)
@ -24,14 +22,14 @@ namespace RageCoop.Client
/// <param name="p"></param>
internal SyncedPed(Ped p)
{
ID=EntityPool.RequestNewID();
p.CanWrithe=false;
p.IsOnlyDamagedByPlayer=false;
MainPed=p;
OwnerID=Main.LocalPlayerID;
ID = EntityPool.RequestNewID();
p.CanWrithe = false;
p.IsOnlyDamagedByPlayer = false;
MainPed = p;
OwnerID = Main.LocalPlayerID;
Function.Call(Hash._SET_PED_CAN_PLAY_INJURED_ANIMS, false);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
//Function.Call(Hash.SET_PED_IS_IGNORED_BY_AUTO_OPEN_DOORS, false);
MainPed.SetConfigFlag(PedConfigFlagToggles.DisableHurt, true);
// MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableMelee, true);
}
@ -41,53 +39,15 @@ namespace RageCoop.Client
/// </summary>
internal SyncedPed(int id)
{
ID=id;
LastSynced=Main.Ticked;
ID = id;
LastSynced = Main.Ticked;
}
#endregion
#region PLAYER -- ONLY
internal Blip PedBlip = null;
internal BlipColor BlipColor = (BlipColor)255;
internal BlipSprite BlipSprite = (BlipSprite)0;
internal float BlipScale=1;
internal PlayerData Player;
#endregion
/// <summary>
/// Indicates whether this ped is a player
/// </summary>
public bool IsPlayer { get { return (OwnerID==ID)&&(ID!=0); } }
/// <summary>
/// real entity
/// </summary>
public Ped MainPed { get; internal set; }
internal int Health { get; set; }
internal bool IsInStealthMode { get; set; }
internal byte WeaponTint { get; set; }
internal bool _lastEnteringVehicle=false;
internal bool _lastSittingInVehicle=false;
private bool _lastRagdoll=false;
private ulong _lastRagdollTime=0;
private bool _lastInCover = false;
private byte[] _lastClothes = null;
internal byte[] Clothes { get; set; }
internal float Heading { get; set; }
internal Vector3 RotationVelocity { get; set; }
internal Vector3 AimCoords { get; set; }
private WeaponAsset WeaponAsset { get; set; }
internal override void Update()
{
if (Owner == null) { OwnerID = OwnerID; return; }
if (IsPlayer)
{
if (Player==null)
{
Player = PlayerList.GetPlayer(this);
return;
}
RenderNameTag();
}
@ -95,78 +55,69 @@ namespace RageCoop.Client
if (!IsReady) { return; }
// Skip update if no new sync message has arrived.
if (!NeedUpdate)
if (!NeedUpdate) { return; }
if (MainPed == null || !MainPed.Exists())
{
return;
}
bool characterExist = (MainPed != null) && MainPed.Exists();
if (!characterExist)
{
CreateCharacter();
return;
}
if (((byte)BlipColor==255) && (PedBlip!=null))
{
PedBlip.Delete();
PedBlip=null;
}
else if (((byte)BlipColor != 255) && PedBlip==null)
{
PedBlip=MainPed.AddBlip();
if (IsPlayer)
if (!CreateCharacter())
{
Main.Logger.Debug("blip:"+Player.Username);
PedBlip.Name=Player.Username;
return;
}
PedBlip.Color=BlipColor;
PedBlip.Sprite=BlipSprite;
PedBlip.Scale=BlipScale;
}
// Need to update state
if (LastStateSynced>=LastUpdated)
if (LastFullSynced >= LastUpdated)
{
if (MainPed!=null&& (ModelHash != MainPed.Model.Hash))
if (MainPed != null && (Model != MainPed.Model.Hash))
{
CreateCharacter();
return;
if (!CreateCharacter())
{
return;
}
}
if (!Main.Settings.ShowPlayerBlip && (byte)BlipColor != 255) BlipColor = (BlipColor)255;
if ((byte)BlipColor == 255 && PedBlip != null)
{
PedBlip.Delete();
PedBlip = null;
}
else if ((byte)BlipColor != 255 && PedBlip == null)
{
PedBlip = MainPed.AddBlip();
PedBlip.Color = BlipColor;
PedBlip.Sprite = BlipSprite;
PedBlip.Scale = BlipScale;
}
if (PedBlip != null)
{
if (PedBlip.Color != BlipColor)
{
PedBlip.Color = BlipColor;
}
if (PedBlip.Sprite != BlipSprite)
{
PedBlip.Sprite = BlipSprite;
}
if (IsPlayer)
{
PedBlip.Name = Owner.Username;
}
}
if (!Clothes.SequenceEqual(_lastClothes))
{
SetClothes();
}
var b = MainPed.AttachedBlip;
if (b==null || b.Color!=BlipColor || b.Sprite!=BlipSprite)
{
PedBlip?.Delete();
PedBlip=MainPed.AddBlip();
PedBlip.Color=BlipColor;
PedBlip.Sprite =BlipSprite;
if (IsPlayer)
{
Main.Logger.Debug("blip:"+Player.Username);
b.Name=Player.Username;
}
}
CheckCurrentWeapon();
}
if (MainPed.IsDead)
{
if (Health>0)
if (Health > 0)
{
if (IsPlayer)
{
@ -178,7 +129,7 @@ namespace RageCoop.Client
}
}
}
else if (IsPlayer&&(MainPed.Health != Health))
else if (IsPlayer && (MainPed.Health != Health))
{
MainPed.Health = Health;
@ -190,154 +141,150 @@ namespace RageCoop.Client
}
}
if (MainPed.IsInVehicle()||MainPed.IsGettingIntoVehicle)
if (!IsPlayer && Health <= 0 && !MainPed.IsDead)
{
MainPed.Kill();
return;
}
if (Speed >= 4)
{
DisplayInVehicle();
}
else
{
if (MainPed.IsInVehicle()) { MainPed.Task.LeaveVehicle(LeaveVehicleFlags.WarpOut); return; }
DisplayOnFoot();
}
LastUpdated=Main.Ticked;
return;
if (IsSpeaking)
{
if (Main.Ticked - LastSpeakingTime < 10)
{
DisplaySpeaking(true);
}
else
{
DisplaySpeaking(false);
IsSpeaking = false;
LastSpeakingTime = 0;
}
}
LastUpdated = Main.Ticked;
}
private void RenderNameTag()
{
if (!Player.DisplayNameTag || (MainPed==null) || !MainPed.IsVisible || !MainPed.IsInRange(Game.Player.Character.Position, 20f))
if (!Owner.DisplayNameTag || !Main.Settings.ShowPlayerNameTag || MainPed == null || !MainPed.IsVisible || !MainPed.IsInRange(Main.PlayerPosition, 40f))
{
return;
}
string renderText = IsOutOfSync ? "~r~AFK" : Player.Username;
Vector3 targetPos = MainPed.Bones[Bone.IKHead].Position + new Vector3(0, 0, 0.35f);
Function.Call(Hash.SET_DRAW_ORIGIN, targetPos.X, targetPos.Y, targetPos.Z, 0);
float dist = (GameplayCamera.Position - MainPed.Position).Length();
var sizeOffset = Math.Max(1f - (dist / 30f), 0.3f);
new ScaledText(new PointF(0, 0), renderText, 0.4f * sizeOffset, GTA.UI.Font.ChaletLondon)
Vector3 targetPos = MainPed.Bones[Bone.IKHead].Position;
Point toDraw = default;
if (Util.WorldToScreen(targetPos, ref toDraw))
{
Outline = true,
Alignment = GTA.UI.Alignment.Center
}.Draw();
Function.Call(Hash.CLEAR_DRAW_ORIGIN);
toDraw.Y -= 100;
new ScaledText(toDraw, Owner.Username, 0.4f, GTA.UI.Font.ChaletLondon)
{
Outline = true,
Alignment = GTA.UI.Alignment.Center,
Color = Owner.HasDirectConnection ? Color.FromArgb(179, 229, 252) : Color.White,
}.Draw();
}
}
private void CreateCharacter()
private bool CreateCharacter()
{
if (MainPed != null)
{
if (MainPed.Exists())
{
Main.Logger.Debug($"Removing ped {ID}. Reason:CreateCharacter");
// Main.Logger.Debug($"Removing ped {ID}. Reason:CreateCharacter");
MainPed.Kill();
MainPed.MarkAsNoLongerNeeded();
MainPed.Delete();
}
MainPed = null;
}
if (PedBlip != null && PedBlip.Exists())
if (PedBlip != null)
{
PedBlip.Delete();
PedBlip = null;
}
Model characterModel = ModelHash.ModelRequest();
if (characterModel == null)
if (!Model.IsLoaded)
{
return;
Model.Request();
return false;
}
MainPed = World.CreatePed(characterModel, Position);
characterModel.MarkAsNoLongerNeeded();
if (MainPed == null)
if ((MainPed = Util.CreatePed(Model, Position)) == null)
{
return;
return false;
}
Model.MarkAsNoLongerNeeded();
MainPed.BlockPermanentEvents = true;
MainPed.CanWrithe=false;
MainPed.CanWrithe = false;
MainPed.CanBeDraggedOutOfVehicle = true;
MainPed.IsOnlyDamagedByPlayer = false;
MainPed.RelationshipGroup=Main.SyncedPedsGroup;
MainPed.IsFireProof=false;
MainPed.IsExplosionProof=false;
MainPed.RelationshipGroup = Main.SyncedPedsGroup;
MainPed.IsFireProof = false;
MainPed.IsExplosionProof = false;
Function.Call(Hash.SET_PED_DROPS_WEAPONS_WHEN_DEAD, MainPed.Handle, false);
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED, MainPed.Handle, true);
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED_BY_PLAYER, MainPed.Handle, Game.Player, true);
Function.Call(Hash.SET_PED_GET_OUT_UPSIDE_DOWN_VEHICLE, MainPed.Handle, false);
Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, MainPed.Handle, true, true);
Function.Call(Hash._SET_PED_CAN_PLAY_INJURED_ANIMS, false);
Function.Call(Hash.SET_PED_IS_IGNORED_BY_AUTO_OPEN_DOORS, false);
Function.Call(Hash.SET_PED_CAN_EVASIVE_DIVE, MainPed.Handle, false);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DrownsInWater,false);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableExplosionReactions, true);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_AvoidTearGas, false);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableShockingEvents, true);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
MainPed.SetConfigFlag(PedConfigFlagToggles.DrownsInWater, false);
MainPed.SetConfigFlag(PedConfigFlagToggles.DisableHurt, true);
MainPed.SetConfigFlag(PedConfigFlagToggles.DisableExplosionReactions, true);
MainPed.SetConfigFlag(PedConfigFlagToggles.AvoidTearGas, false);
MainPed.SetConfigFlag(PedConfigFlagToggles.IgnoreBeingOnFire, true);
MainPed.SetConfigFlag(PedConfigFlagToggles.DisableEvasiveDives, true);
MainPed.SetConfigFlag(PedConfigFlagToggles.DisablePanicInVehicle, true);
MainPed.SetConfigFlag(PedConfigFlagToggles.BlockNonTemporaryEvents, true);
MainPed.SetConfigFlag(PedConfigFlagToggles.DisableShockingEvents, true);
SetClothes();
if (IsPlayer)
{
MainPed.IsInvincible=true;
}
if (IsInvincible) { MainPed.IsInvincible=true; }
if (IsPlayer) { MainPed.IsInvincible = true; }
if (IsInvincible) { MainPed.IsInvincible = true; }
// Add to EntityPool so this Character can be accessed by handle.
EntityPool.Add(this);
lock (EntityPool.PedsLock)
{
// Add to EntityPool so this Character can be accessed by handle.
EntityPool.Add(this);
}
return true;
}
private void SetClothes()
{
for (byte i = 0; i < 12; i++)
{
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, MainPed.Handle, i, (int)Clothes[i], (int)Clothes[i+12], (int)Clothes[i+24]);
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, MainPed.Handle, i, (int)Clothes[i], (int)Clothes[i + 12], (int)Clothes[i + 24]);
}
_lastClothes = Clothes;
}
#region ONFOOT
#region -- VARIABLES --
/// <summary>
/// The latest character rotation (may not have been applied yet)
/// </summary>
public byte Speed { get; set; }
private bool _lastIsJumping = false;
internal bool IsJumping { get; set; }
internal bool IsOnLadder { get; set; }
internal bool IsVaulting { get; set; }
internal bool IsInParachuteFreeFall { get; set; }
internal bool IsParachuteOpen { get; set; }
internal Prop ParachuteProp { get; set; } = null;
internal bool IsRagdoll { get; set; }
internal bool IsOnFire { get; set; }
internal bool IsAiming { get; set; }
internal bool IsReloading { get; set; }
internal bool IsInCover { get; set; }
internal uint CurrentWeaponHash { get; set; }
private Dictionary<uint, bool> _lastWeaponComponents = null;
internal Dictionary<uint, bool> WeaponComponents { get; set; } = null;
private int _lastWeaponObj = 0;
#endregion
private string[] _currentAnimation = new string[2] { "", "" };
private void DisplayOnFoot()
{
if (IsInParachuteFreeFall)
{
MainPed.PositionNoOffset = Vector3.Lerp(MainPed.Position, Position + Velocity, 0.5f);
MainPed.PositionNoOffset = Vector3.Lerp(MainPed.ReadPosition(), Position + Velocity, 0.5f);
MainPed.Quaternion = Rotation.ToQuaternion();
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "skydive@base", "free_idle", 3))
@ -351,10 +298,11 @@ namespace RageCoop.Client
{
if (ParachuteProp == null)
{
Model model = 1740193300.ModelRequest();
Model model = 1740193300;
model.Request(1000);
if (model != null)
{
ParachuteProp = World.CreateProp(model, MainPed.Position, MainPed.Rotation, false, false);
ParachuteProp = World.CreateProp(model, MainPed.ReadPosition(), MainPed.ReadRotation(), false, false);
model.MarkAsNoLongerNeeded();
ParachuteProp.IsPositionFrozen = true;
ParachuteProp.IsCollisionEnabled = false;
@ -365,7 +313,7 @@ namespace RageCoop.Client
MainPed.Task.ClearSecondary();
}
MainPed.PositionNoOffset = Vector3.Lerp(MainPed.Position, Position + Velocity, 0.5f);
MainPed.PositionNoOffset = Vector3.Lerp(MainPed.ReadPosition(), Position + Velocity, 0.5f);
MainPed.Quaternion = Rotation.ToQuaternion();
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "skydive@parachute@first_person", "chute_idle_right", 3))
@ -433,7 +381,7 @@ namespace RageCoop.Client
SmoothTransition();
return;
}
if (!IsOnLadder && MainPed.IsTaskActive(TaskType.CTaskGoToAndClimbLadder))
else if (MainPed.IsTaskActive(TaskType.CTaskGoToAndClimbLadder))
{
MainPed.Task.ClearAllImmediately();
_currentAnimation[1] = "";
@ -457,12 +405,11 @@ namespace RageCoop.Client
if (IsOnFire && !MainPed.IsOnFire)
{
MainPed.SetOnFire(true);
Function.Call(Hash.START_ENTITY_FIRE, MainPed);
}
else if (!IsOnFire && MainPed.IsOnFire)
{
MainPed.SetOnFire(false);
Function.Call(Hash.STOP_ENTITY_FIRE, MainPed);
}
if (IsJumping)
@ -478,48 +425,34 @@ namespace RageCoop.Client
}
_lastIsJumping = false;
if (IsRagdoll || Health==0)
if (IsRagdoll || (IsPlayer && Health == 0))
{
if (!MainPed.IsRagdoll)
{
MainPed.Ragdoll();
}
SmoothTransition();
if (!_lastRagdoll)
{
_lastRagdoll = true;
_lastRagdollTime=Main.Ticked;
_lastRagdollTime = Main.Ticked;
}
/*
if((Main.Ticked-_lastRagdollTime>30)&&((Position.DistanceTo(MainPed.Position)>2)||MainPed.Velocity.Length()<3f))
{
MainPed.ApplyForce((Position-MainPed.Position)*0.2f, (RotationVelocity-MainPed.RotationVelocity)*0.1f);
}*/
return;
}
else
if (MainPed.IsRagdoll)
{
if (MainPed.IsRagdoll)
if (Speed == 0)
{
if (Speed==0)
{
MainPed.CancelRagdoll();
}
else
{
MainPed.Task.ClearAllImmediately();
}
return;
MainPed.CancelRagdoll();
}
else
{
_lastRagdoll = false;
MainPed.Task.ClearAllImmediately();
}
_lastRagdoll = false;
return;
}
if (IsReloading)
{
if (!MainPed.IsTaskActive(TaskType.CTaskReloadGun))
@ -542,29 +475,26 @@ namespace RageCoop.Client
}
else if (IsInCover)
{
if (!_lastInCover)
{
Function.Call(Hash.TASK_STAY_IN_COVER, MainPed.Handle);
}
_lastInCover=true;
_lastInCover = true;
if (IsAiming)
{
DisplayAiming();
_lastInCover=false;
_lastInCover = false;
}
else if (MainPed.IsInCover)
{
SmoothTransition();
}
return;
}
else if (_lastInCover)
{
MainPed.Task.ClearAllImmediately();
_lastInCover=false;
_lastInCover = false;
}
else if (IsAiming)
{
@ -580,38 +510,32 @@ namespace RageCoop.Client
}
}
#region WEAPON
private void CheckCurrentWeapon()
{
if (MainPed.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || !WeaponComponents.Compare(_lastWeaponComponents))
if (MainPed.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || !WeaponComponents.Compare(_lastWeaponComponents) || (Speed <= 3 && _weaponObj?.IsVisible != true))
{
if (WeaponAsset!=null) { WeaponAsset.MarkAsNoLongerNeeded(); }
WeaponAsset=new WeaponAsset(CurrentWeaponHash);
if (!WeaponAsset.IsLoaded) { WeaponAsset.Request(); }
MainPed.Weapons.RemoveAll();
_lastWeaponObj = Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0);
new WeaponAsset(CurrentWeaponHash).Request();
MainPed.Weapons.RemoveAll();
_weaponObj = Entity.FromHandle(Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0));
if (_weaponObj == null) { return; }
if (CurrentWeaponHash != (uint)WeaponHash.Unarmed)
{
if (WeaponComponents != null && WeaponComponents.Count != 0)
{
foreach (KeyValuePair<uint, bool> comp in WeaponComponents)
{
if (comp.Value)
{
Function.Call(Hash.GIVE_WEAPON_COMPONENT_TO_WEAPON_OBJECT, _lastWeaponObj, comp.Key);
Function.Call(Hash.GIVE_WEAPON_COMPONENT_TO_WEAPON_OBJECT, _weaponObj, comp.Key);
}
}
}
Function.Call(Hash.GIVE_WEAPON_OBJECT_TO_PED, _lastWeaponObj, MainPed.Handle);
Function.Call(Hash.GIVE_WEAPON_OBJECT_TO_PED, _weaponObj, MainPed.Handle);
}
_lastWeaponComponents = WeaponComponents;
}
if (Function.Call<int>(Hash.GET_PED_WEAPON_TINT_INDEX,MainPed,CurrentWeaponHash)!=WeaponTint)
if (Function.Call<int>(Hash.GET_PED_WEAPON_TINT_INDEX, MainPed, CurrentWeaponHash) != WeaponTint)
{
Function.Call<int>(Hash.SET_PED_WEAPON_TINT_INDEX, MainPed, CurrentWeaponHash, WeaponTint);
}
@ -619,26 +543,26 @@ namespace RageCoop.Client
private void DisplayAiming()
{
if (Velocity==default)
if (Velocity == default)
{
MainPed.Task.AimAt(AimCoords,1000);
MainPed.Task.AimGunAtPosition(AimCoords, 1000);
}
else
{
Function.Call(Hash.TASK_GO_TO_COORD_WHILE_AIMING_AT_COORD, MainPed.Handle,
Position.X+Velocity.X, Position.Y+Velocity.Y, Position.Z+Velocity.Z,
Position.X + Velocity.X, Position.Y + Velocity.Y, Position.Z + Velocity.Z,
AimCoords.X, AimCoords.Y, AimCoords.Z, 3f, false, 0x3F000000, 0x40800000, false, 512, false, 0);
}
SmoothTransition();
}
#endregion
private bool LastMoving;
private void WalkTo()
{
Vector3 predictPosition = Position + (Position - MainPed.Position) + Velocity * 0.5f;
float range = predictPosition.DistanceToSquared(MainPed.Position);
MainPed.Task.ClearAll();
Function.Call(Hash.SET_PED_STEALTH_MOVEMENT, MainPed, IsInStealthMode, 0);
Vector3 predictPosition = Predict(Position) + Velocity;
float range = predictPosition.DistanceToSquared(MainPed.ReadPosition());
switch (Speed)
{
@ -679,6 +603,8 @@ namespace RageCoop.Client
MainPed.Task.StandStill(2000);
LastMoving = false;
}
if (MainPed.IsTaskActive(TaskType.CTaskDiveToGround)) MainPed.Task.ClearAll();
break;
}
SmoothTransition();
@ -687,52 +613,128 @@ namespace RageCoop.Client
private void SmoothTransition()
{
var localRagdoll = MainPed.IsRagdoll;
var dist = Position.DistanceTo(MainPed.Position);
if (dist>3)
var predicted = Predict(Position);
var dist = predicted.DistanceTo(MainPed.ReadPosition());
if (IsOff(dist))
{
MainPed.PositionNoOffset=Position;
MainPed.PositionNoOffset = predicted;
return;
}
var f = dist*(Position+SyncParameters.PositioinPredictionDefault*Velocity-MainPed.Position)+(Velocity-MainPed.Velocity)*0.2f;
if (!localRagdoll) { f*=5; }
if (!(localRagdoll|| MainPed.IsDead))
if (!(localRagdoll || MainPed.IsDead))
{
MainPed.Rotation=Rotation;
if (MainPed.Speed<0.05) { f*=10; MainPed.Heading=Heading; }
}
else if (Main.Ticked-_lastRagdollTime<10)
{
return;
}
MainPed.ApplyForce(f);
}
private string LoadAnim(string anim)
{
ulong startTime = Util.GetTickCount64();
while (!Function.Call<bool>(Hash.HAS_ANIM_DICT_LOADED, anim))
{
Script.Yield();
Function.Call(Hash.REQUEST_ANIM_DICT, anim);
if (Util.GetTickCount64() - startTime >= 1000)
if (!IsAiming && !MainPed.IsGettingUp)
{
break;
}
}
var cur = MainPed.Heading;
var diff = Heading - cur;
if (diff > 180) { diff -= 360; }
else if (diff < -180) { diff += 360; }
return anim;
MainPed.Heading = cur + diff / 2;
}
MainPed.Velocity = Velocity + 5 * dist * (predicted - MainPed.ReadPosition());
}
else if (Main.Ticked - _lastRagdollTime < 10)
{
return;
}
else if (IsRagdoll)
{
var helper = new GTA.NaturalMotion.ApplyImpulseHelper(MainPed);
var head = MainPed.Bones[Bone.SkelHead];
var rightFoot = MainPed.Bones[Bone.SkelRightFoot];
var leftFoot = MainPed.Bones[Bone.SkelLeftFoot];
Vector3 amount;
// 20:head, 3:left foot, 6:right foot, 17:right hand,
amount = 20 * (Predict(HeadPosition) - head.Position);
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
helper.EqualizeAmount = 1;
helper.PartIndex = 20;
helper.Impulse = amount;
helper.Start();
helper.Stop();
amount = 20 * (Predict(RightFootPosition) - rightFoot.Position);
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
helper.EqualizeAmount = 1;
helper.PartIndex = 6;
helper.Impulse = amount;
helper.Start();
helper.Stop();
amount = 20 * (Predict(LeftFootPosition) - leftFoot.Position);
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
helper.EqualizeAmount = 1;
helper.PartIndex = 3;
helper.Impulse = amount;
helper.Start();
helper.Stop();
}
else
{
// localRagdoll
var force = Velocity - MainPed.Velocity + 5 * dist * (predicted - MainPed.ReadPosition());
if (force.Length() > 20) { force = force.Normalized * 20; }
MainPed.ApplyForce(force);
}
}
#endregion
private void DisplayInVehicle()
{
if (MainPed.IsOnTurretSeat())
if (CurrentVehicle?.MainVehicle == null) { return; }
switch (Speed)
{
Function.Call(Hash.SET_VEHICLE_TURRET_SPEED_THIS_FRAME, MainPed.CurrentVehicle, 100);
Function.Call(Hash.TASK_VEHICLE_AIM_AT_COORD, MainPed.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z);
case 4:
if (MainPed.CurrentVehicle != CurrentVehicle.MainVehicle || MainPed.SeatIndex != Seat || (!MainPed.IsSittingInVehicle() && !MainPed.IsBeingJacked))
{
MainPed.SetIntoVehicle(CurrentVehicle.MainVehicle, Seat);
}
if (MainPed.IsOnTurretSeat())
{
// Function.Call(Hash.SET_VEHICLE_TURRET_SPEED_THIS_FRAME, MainPed.CurrentVehicle, 100);
Function.Call(Hash.TASK_VEHICLE_AIM_AT_COORD, MainPed.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z);
}
if (MainPed.VehicleWeapon == VehicleWeaponHash.Invalid)
{
// World.DrawMarker(MarkerType.DebugSphere,AimCoords,default,default,new Vector3(0.2f,0.2f,0.2f),Color.AliceBlue);
if (IsAiming)
{
Function.Call(Hash.SET_DRIVEBY_TASK_TARGET, MainPed, 0, 0, AimCoords.X, AimCoords.Y, AimCoords.Z);
if (!_lastDriveBy)
{
_lastDriveBy = true;
Function.Call(Hash.TASK_DRIVE_BY, MainPed, 0, 0, AimCoords.X, AimCoords.Y, AimCoords.Z, 1, 100, 1, FiringPattern.SingleShot);
}
}
else if (_lastDriveBy || MainPed.IsTaskActive(TaskType.CTaskAimGunVehicleDriveBy))
{
MainPed.Task.ClearAll();
_lastDriveBy = false;
}
}
else if (MainPed.VehicleWeapon != (VehicleWeaponHash)CurrentWeaponHash)
{
MainPed.VehicleWeapon = (VehicleWeaponHash)CurrentWeaponHash;
}
break;
case 5:
if (MainPed.VehicleTryingToEnter != CurrentVehicle.MainVehicle || MainPed.GetSeatTryingToEnter() != Seat)
{
MainPed.Task.EnterVehicle(CurrentVehicle.MainVehicle, Seat, -1, 5, EnterVehicleFlags.JackAnyone);
}
break;
case 6:
if (!MainPed.IsTaskActive(TaskType.CTaskExitVehicle))
{
MainPed.Task.LeaveVehicle(CurrentVehicle.Velocity.Length() > 5f ? LeaveVehicleFlags.BailOut : LeaveVehicleFlags.None);
}
break;
}
/*
Function.Call(Hash.TASK_SWEEP_AIM_ENTITY,P, "random@paparazzi@pap_anims", "sweep_low", "sweep_med", "sweep_high", -1,V, 1.57f, 0.25f);
Function.Call(Hash.SET_PED_STEALTH_MOVEMENT, P,true, 0);
return Function.Call<bool>(Hash.GET_PED_STEALTH_MOVEMENT, P);
*/

View File

@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA;
using GTA;
using GTA.Math;
using System.Diagnostics;
namespace RageCoop.Client
{
@ -19,38 +15,50 @@ namespace RageCoop.Client
/// </summary>
public bool IsLocal
{
get
{
return OwnerID==Main.LocalPlayerID;
}
get => OwnerID == Main.LocalPlayerID;
}
/// <summary>
/// Network ID for this entity
/// </summary>
public int ID { get;internal set; }
public int ID { get; internal set; }
private int _ownerID;
/// <summary>
///
/// </summary>
public int OwnerID { get; internal set; }
public int OwnerID
{
get => _ownerID;
internal set
{
if (value == _ownerID && Owner != null) { return; }
_ownerID = value;
Owner = PlayerList.GetPlayer(value);
if (this is SyncedPed && Owner != null)
{
Owner.Character = ((SyncedPed)this);
}
}
}
internal virtual Player Owner { get; private set; }
/// <summary>
///
/// </summary>
public bool IsOutOfSync
{
get
{
return Main.Ticked-LastSynced>200 && ID!=0;
}
get => Main.Ticked - LastSynced > 200 && ID != 0;
}
internal bool IsReady
{
get {return (LastSynced>0||LastStateSynced==0);}
get => LastSynced > 0 || LastFullSynced == 0;
}
internal bool IsInvincible { get; set; } = false;
internal bool NeedUpdate
{
get { return LastSynced>LastUpdated; }
get => LastSynced >= LastUpdated;
}
#region LAST STATE
/// <summary>
@ -60,27 +68,49 @@ namespace RageCoop.Client
/// <summary>
/// Last time a new sync message arrived.
/// </summary>
public ulong LastStateSynced { get; internal set; } = 0;
public ulong LastFullSynced { get; internal set; } = 0;
/// <summary>
/// Last time the local entity has been updated,
/// </summary>
public ulong LastUpdated { get; set; } = 0;
internal Stopwatch LastSentStopWatch { get; set; } = Stopwatch.StartNew();
#endregion
public bool SendNextFrame { get; set; } = false;
public bool SendFullNextFrame { get; set; } = false;
/// <summary>
///
/// </summary>
internal protected bool _lastFrozen=false;
internal int ModelHash { get; set; }
protected internal bool _lastFrozen = false;
internal Model Model { get; set; }
internal Vector3 Position { get; set; }
internal Vector3 Rotation { get; set; }
internal Quaternion Quaternion { get; set; }
internal Vector3 Velocity { get; set; }
public Stopwatch LastSyncedStopWatch = new Stopwatch();
internal abstract void Update();
internal void PauseUpdate(ulong frames)
{
LastUpdated=Main.Ticked+frames;
LastUpdated = Main.Ticked + frames;
}
protected Vector3 Predict(Vector3 input)
{
return (Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds) * Velocity + input;
}
private float _accumulatedOff = 0;
protected bool IsOff(float thisOff, float tolerance = 3, float limit = 30)
{
_accumulatedOff += thisOff - tolerance;
if (_accumulatedOff < 0) { _accumulatedOff = 0; }
else if (_accumulatedOff >= limit)
{
_accumulatedOff = 0;
return true;
}
return false;
}
}
}

View File

@ -1,97 +1,125 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA;
using GTA;
using GTA.Math;
using GTA.Native;
using RageCoop.Core;
namespace RageCoop.Client
{
internal class SyncedProjectile : SyncedEntity
{
public SyncedProjectile(Projectile p)
{
ID=EntityPool.RequestNewID();
MainProjectile = p;
Origin=p.Position;
var shooter = EntityPool.GetPedByHandle((p.Owner?.Handle).GetValueOrDefault());
if (shooter==null)
{
// Owner will be the vehicle if projectile is shot with a vehicle
var shooterVeh = EntityPool.GetVehicleByHandle((p.Owner?.Handle).GetValueOrDefault());
if (shooterVeh!=null && shooterVeh.MainVehicle.Driver!=null)
{
shooter=shooterVeh.MainVehicle.Driver?.GetSyncEntity();
}
else
{
Main.Logger.Warning($"Could not find owner for projectile:{Hash}");
}
}
if(shooter != null)
{
if (shooter.MainPed!=null && (p.AttachedEntity==shooter.MainPed.Weapons.CurrentWeaponObject || p.AttachedEntity== shooter.MainPed))
{
// Reloading
IsValid=false;
}
ShooterID=shooter.ID;
IsLocal=shooter.IsLocal;
}
}
public SyncedProjectile(int id)
{
ID= id;
IsLocal=false;
}
public ProjectileDataFlags Flags { private get; set; } = ProjectileDataFlags.None;
public readonly Vector3 Origin;
private bool _firstSend = false;
public bool IsValid { get; private set; } = true;
public new bool IsLocal { get; private set; } = false;
public bool Exploded { get; set; } = false;
public Projectile MainProjectile { get; set; }
public int ShooterID { get; set; }
private SyncedPed Shooter { get;set; }
public Vector3 Origin { get; set; }
public SyncedEntity Shooter { get; set; }
public bool Exploded => Flags.HasProjDataFlag(ProjectileDataFlags.Exploded);
internal override Player Owner => Shooter.Owner;
/// <summary>
/// Invalid property for projectile.
/// </summary>
private new int OwnerID{ set { } }
public WeaponHash Hash { get; set; }
private new int OwnerID { set { } }
public WeaponHash WeaponHash { get; set; }
private WeaponAsset Asset { get; set; }
public void ExtractData(ref Packets.ProjectileSync p)
{
p.Position = MainProjectile.Position;
p.Velocity = MainProjectile.Velocity;
p.Rotation = MainProjectile.Rotation;
p.ID = ID;
p.ShooterID = Shooter.ID;
p.WeaponHash = (uint)MainProjectile.WeaponHash;
p.Flags = ProjectileDataFlags.None;
if (MainProjectile.IsDead)
{
p.Flags |= ProjectileDataFlags.Exploded;
}
if (MainProjectile.AttachedEntity != null)
{
p.Flags |= ProjectileDataFlags.IsAttached;
}
if (Shooter is SyncedVehicle)
{
p.Flags |= ProjectileDataFlags.IsShotByVehicle;
}
if (_firstSend)
{
p.Flags |= ProjectileDataFlags.IsAttached;
_firstSend = false;
}
}
public SyncedProjectile(Projectile p)
{
var owner = p.OwnerEntity;
if (owner == null) { IsValid = false; return; }
ID = EntityPool.RequestNewID();
MainProjectile = p;
Origin = p.Position;
if (EntityPool.PedsByHandle.TryGetValue(owner.Handle, out var shooter))
{
if (shooter.MainPed != null
&& (p.AttachedEntity == shooter.MainPed.Weapons.CurrentWeaponObject
|| p.AttachedEntity == shooter.MainPed))
{
// Reloading
IsValid = false;
return;
}
Shooter = shooter;
IsLocal = shooter.IsLocal;
}
else if (EntityPool.VehiclesByHandle.TryGetValue(owner.Handle, out var shooterVeh))
{
Shooter = shooterVeh;
IsLocal = shooterVeh.IsLocal;
}
else
{
IsValid = false;
}
}
public SyncedProjectile(int id)
{
ID = id;
IsLocal = false;
}
internal override void Update()
{
// Skip update if no new sync message has arrived.
if (!NeedUpdate){ return; }
if (!NeedUpdate) { return; }
if (MainProjectile == null || !MainProjectile.Exists())
{
CreateProjectile();
return;
}
MainProjectile.Velocity=Velocity+(Position+Networking.Latency*Velocity-MainProjectile.Position);
MainProjectile.Rotation=Rotation;
LastUpdated=Main.Ticked;
MainProjectile.Velocity = Velocity + 10 * (Predict(Position) - MainProjectile.Position);
MainProjectile.Rotation = Rotation;
LastUpdated = Main.Ticked;
}
private void CreateProjectile()
{
Asset=new WeaponAsset(Hash);
if (!Asset.IsLoaded) { Asset.Request(); }
World.ShootBullet(Position,Position+Velocity,(Shooter=EntityPool.GetPedByID(ShooterID))?.MainPed,Asset,0);
Asset = new WeaponAsset(WeaponHash);
if (!Asset.IsLoaded) { Asset.Request(); return; }
if (Shooter == null) { return; }
Entity owner;
owner = (Shooter as SyncedPed)?.MainPed ?? (Entity)(Shooter as SyncedVehicle)?.MainVehicle;
Position = (Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds) * Shooter.Velocity + Position;
var end = Position + Velocity;
Function.Call(Hash.SHOOT_SINGLE_BULLET_BETWEEN_COORDS_IGNORE_ENTITY, Position.X, Position.Y, Position.Z, end.X, end.Y, end.Z, 0, 1, WeaponHash, owner?.Handle ?? 0, 1, 0, -1);
var ps = World.GetAllProjectiles();
MainProjectile=ps[ps.Length-1];
if (Hash==(WeaponHash)VehicleWeaponHash.Tank)
{
var v = Shooter?.MainPed?.CurrentVehicle;
if (v!=null)
{
World.CreateParticleEffectNonLooped(SyncEvents.CorePFXAsset, "muz_tank", v.GetMuzzleInfo().Position, v.Bones[35].ForwardVector.ToEulerRotation(v.Bones[35].UpVector), 1);
}
}
MainProjectile = ps[ps.Length - 1];
MainProjectile.Position = Position;
MainProjectile.Rotation = Rotation;
MainProjectile.Velocity = Velocity;
EntityPool.Add(this);
}
}

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA.Native;
using GTA;
using GTA;
namespace RageCoop.Client
{
@ -15,30 +9,33 @@ namespace RageCoop.Client
{
internal SyncedProp(int id)
{
ID= id;
ID = id;
}
/// <summary>
/// The real entity
/// </summary>
public Prop MainProp { get; set; }
internal new int OwnerID { get
internal new int OwnerID
{
get
{
// alwayse owned by server
return 0;
} }
}
}
internal override void Update()
{
if (!NeedUpdate) { return; }
if (MainProp== null || !MainProp.Exists())
if (MainProp == null || !MainProp.Exists())
{
MainProp=World.CreateProp(ModelHash,Position,Rotation,false,false);
MainProp.IsInvincible=true;
MainProp = World.CreateProp(Model, Position, Rotation, false, false);
MainProp.IsInvincible = true;
}
MainProp.Position=Position;
MainProp.Rotation=Rotation;
MainProp.Position = Position;
MainProp.Rotation = Rotation;
MainProp.SetFrozen(true);
LastUpdated=Main.Ticked;
LastUpdated = Main.Ticked;
}
}
}

View File

@ -1,426 +0,0 @@
using System;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA;
using GTA.Native;
using GTA.Math;
using RageCoop.Core;
namespace RageCoop.Client
{
/// <summary>
/// A synchronized vehicle instance
/// </summary>
public class SyncedVehicle : SyncedEntity
{
#region -- CONSTRUCTORS --
/// <summary>
/// Create a local entity (outgoing sync)
/// </summary>
/// <param name="v"></param>
internal SyncedVehicle(Vehicle v)
{
ID=EntityPool.RequestNewID();
MainVehicle=v;
MainVehicle.CanPretendOccupants=false;
OwnerID=Main.LocalPlayerID;
}
/// <summary>
/// Create an empty VehicleEntity
/// </summary>
internal SyncedVehicle()
{
}
internal SyncedVehicle(int id)
{
ID=id;
LastSynced=Main.Ticked;
}
#endregion
/// <summary>
/// VehicleSeat,ID
/// </summary>
public Vehicle MainVehicle { get;internal set; }
#region LAST STATE
private byte[] _lastVehicleColors = new byte[] { 0, 0 };
private Dictionary<int, int> _lastVehicleMods = new Dictionary<int, int>();
#endregion
#region -- CRITICAL STUFF --
internal Vector3 RotationVelocity { get; set; }
internal float SteeringAngle { get; set; }
internal float ThrottlePower { get; set; }
internal float BrakePower { get; set; }
internal float DeluxoWingRatio { get; set; } = -1;
internal bool IsFlipped
{
get
{
return (Quaternion*Vector3.RelativeTop).Z <(Quaternion*Vector3.RelativeBottom).Z;
}
}
#endregion
#region -- VEHICLE STATE --
internal VehicleDataFlags Flags { get; set; }
internal bool EngineRunning { get; set; }
private bool _lastTransformed = false;
internal bool Transformed { get; set; }
private bool _lastHornActive = false;
internal bool HornActive { get; set; }
internal bool LightsOn { get; set; }
internal bool BrakeLightsOn { get; set; } = false;
internal bool HighBeamsOn { get; set; }
internal byte LandingGear { get; set; }
internal VehicleRoofState RoofState { get; set; }
internal bool SireneActive { get; set; }
internal VehicleDamageModel DamageModel { get; set; }
internal byte[] Colors { get; set; }
internal Dictionary<int, int> Mods { get; set; }
internal bool IsDead { get; set; }
internal float EngineHealth { get; set; }
internal VehicleLockStatus LockStatus{get;set;}
/// <summary>
/// VehicleSeat,PedID
/// </summary>
internal Dictionary<VehicleSeat, SyncedPed> Passengers { get; set; }
internal byte RadioStation = 255;
internal string LicensePlate { get; set; }
internal int _lastLivery = -1;
internal int Livery { get; set; } = -1;
internal bool _checkSeat { get; set; } = true;
#endregion
internal override void Update()
{
#region -- INITIAL CHECK --
// Check if all data avalible
if(!IsReady) { return; }
// Skip update if no new sync message has arrived.
if (!NeedUpdate) { return; }
#endregion
#region -- CHECK EXISTENCE --
if ((MainVehicle == null) || (!MainVehicle.Exists()) || (MainVehicle.Model.Hash != ModelHash))
{
CreateVehicle();
return;
}
#endregion
#region -- SYNC CRITICAL --
if (SteeringAngle != MainVehicle.SteeringAngle)
{
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * SteeringAngle);
}
MainVehicle.ThrottlePower=ThrottlePower;
MainVehicle.BrakePower=BrakePower;
if (MainVehicle.Position.DistanceTo(Position)<5)
{
MainVehicle.Velocity = Velocity+5*(Position+Velocity*SyncParameters.PositioinPredictionDefault - MainVehicle.Position);
if (IsFlipped)
{
MainVehicle.Quaternion=Quaternion.Slerp(MainVehicle.Quaternion, Quaternion, 0.5f);
MainVehicle.RotationVelocity=RotationVelocity;
}
else
{
Vector3 cali = GetCalibrationRotation();
if (cali.Length()<50)
{
MainVehicle.RotationVelocity = RotationVelocity+cali*0.2f;
}
else
{
MainVehicle.Quaternion=Quaternion;
MainVehicle.RotationVelocity=RotationVelocity;
}
}
}
else
{
MainVehicle.Position=Position;
MainVehicle.Velocity=Velocity;
MainVehicle.Quaternion=Quaternion;
}
if (DeluxoWingRatio!=-1)
{
MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
}
#endregion
if (LastStateSynced>LastUpdated)
{
#region -- SYNC STATE --
#region -- PASSENGER SYNC --
// check passengers (and driver).
if (_checkSeat)
{
var currentPassengers = MainVehicle.GetPassengers();
lock (Passengers)
{
for (int i = -1; i<MainVehicle.PassengerCapacity; i++)
{
VehicleSeat seat = (VehicleSeat)i;
if (Passengers.ContainsKey(seat))
{
SyncedPed c = Passengers[seat];
if (c?.ID==Main.LocalPlayerID && (RadioStation!=Function.Call<int>(Hash.GET_PLAYER_RADIO_STATION_INDEX)))
{
Util.SetPlayerRadioIndex(RadioStation);
}
if (c?.MainPed!=null&&(!currentPassengers.ContainsKey(i))&&(!c.MainPed.IsBeingJacked)&&(!c.MainPed.IsTaskActive(TaskType.CTaskExitVehicleSeat)))
{
Passengers[seat].MainPed.SetIntoVehicle(MainVehicle, seat);
}
}
else if (!MainVehicle.IsSeatFree(seat))
{
var p = MainVehicle.Occupants.Where(x => x.SeatIndex==seat).FirstOrDefault();
if ((p!=null)&& !p.IsTaskActive(TaskType.CTaskLeaveAnyCar))
{
p.Task.WarpOutOfVehicle(MainVehicle);
}
}
}
}
}
#endregion
if (Colors != null && Colors != _lastVehicleColors)
{
Function.Call(Hash.SET_VEHICLE_COLOURS, MainVehicle, Colors[0], Colors[1]);
_lastVehicleColors = Colors;
}
MainVehicle.EngineHealth=EngineHealth;
if (Mods != null && !Mods.Compare(_lastVehicleMods))
{
Function.Call(Hash.SET_VEHICLE_MOD_KIT, MainVehicle, 0);
foreach (KeyValuePair<int, int> mod in Mods)
{
MainVehicle.Mods[(VehicleModType)mod.Key].Index = mod.Value;
}
_lastVehicleMods = Mods;
}
if (IsDead)
{
if (MainVehicle.IsDead)
{
return;
}
else
{
MainVehicle.Explode();
}
}
else
{
if (MainVehicle.IsDead)
{
MainVehicle.Repair();
}
}
if (EngineRunning != MainVehicle.IsEngineRunning)
{
MainVehicle.IsEngineRunning = EngineRunning;
}
if (LightsOn != MainVehicle.AreLightsOn)
{
MainVehicle.AreLightsOn = LightsOn;
}
if (HighBeamsOn != MainVehicle.AreHighBeamsOn)
{
MainVehicle.AreHighBeamsOn = HighBeamsOn;
}
if (MainVehicle.IsSubmarineCar)
{
if (Transformed)
{
if (!_lastTransformed)
{
_lastTransformed = true;
Function.Call(Hash._TRANSFORM_VEHICLE_TO_SUBMARINE, MainVehicle.Handle, false);
}
}
else if (_lastTransformed)
{
_lastTransformed = false;
Function.Call(Hash._TRANSFORM_SUBMARINE_TO_VEHICLE, MainVehicle.Handle, false);
}
}
if (MainVehicle.IsAircraft)
{
if (LandingGear != (byte)MainVehicle.LandingGearState)
{
MainVehicle.LandingGearState = (VehicleLandingGearState)LandingGear;
}
}
else
{
if (MainVehicle.HasSiren && SireneActive != MainVehicle.IsSirenActive)
{
MainVehicle.IsSirenActive = SireneActive;
}
if (HornActive)
{
if (!_lastHornActive)
{
_lastHornActive = true;
MainVehicle.SoundHorn(99999);
}
}
else if (_lastHornActive)
{
_lastHornActive = false;
MainVehicle.SoundHorn(1);
}
if (MainVehicle.HasRoof && MainVehicle.RoofState!=RoofState)
{
MainVehicle.RoofState=RoofState;
}
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
MainVehicle.SetDamageModel(DamageModel);
}
MainVehicle.LockStatus=LockStatus;
if (Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering))
{
if (!MainVehicle.IsDeluxoHovering())
{
MainVehicle.SetDeluxoHoverState(true);
}
}
else if(ModelHash==1483171323)
{
if (MainVehicle.IsDeluxoHovering())
{
MainVehicle.SetDeluxoHoverState(false);
}
}
if (Function.Call<string>(Hash.GET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle)!=LicensePlate)
{
Function.Call(Hash.SET_VEHICLE_NUMBER_PLATE_TEXT,MainVehicle,LicensePlate);
}
if (_lastLivery!=Livery)
{
Function.Call(Hash.SET_VEHICLE_LIVERY, MainVehicle, Livery);
_lastLivery=Livery;
}
#endregion
}
LastUpdated=Main.Ticked;
}
private Vector3 GetCalibrationRotation()
{
var rot=Quaternion.LookRotation(Quaternion*Vector3.RelativeFront, Quaternion*Vector3.RelativeTop).ToEulerAngles();
var curRot=Quaternion.LookRotation(MainVehicle.Quaternion*Vector3.RelativeFront, MainVehicle.Quaternion*Vector3.RelativeTop).ToEulerAngles();
var r = (rot-curRot).ToDegree();
if (r.X>180) { r.X=r.X-360; }
else if(r.X<-180) { r.X=360+r.X; }
if (r.Y>180) { r.Y=r.Y-360; }
else if (r.Y<-180) { r.Y=360+r.Y; }
if (r.Z>180) { r.Z=r.Z-360; }
else if (r.Z<-180) { r.Z=360+r.Z; }
return r;
}
private void CreateVehicle()
{
MainVehicle?.Delete();
Model vehicleModel = ModelHash.ModelRequest();
if (vehicleModel == null)
{
//GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
return;
}
MainVehicle = World.CreateVehicle(vehicleModel, Position);
lock (EntityPool.VehiclesLock)
{
EntityPool.Add( this);
}
MainVehicle.Quaternion = Quaternion;
if (MainVehicle.HasRoof)
{
MainVehicle.RoofState=RoofState;
}
if (IsInvincible) { MainVehicle.IsInvincible=true; }
vehicleModel.MarkAsNoLongerNeeded();
}
#region -- PEDALING --
/*
* Thanks to @oldnapalm.
*/
private string PedalingAnimDict()
{
switch ((VehicleHash)ModelHash)
{
case VehicleHash.Bmx:
return "veh@bicycle@bmx@front@base";
case VehicleHash.Cruiser:
return "veh@bicycle@cruiserfront@base";
case VehicleHash.Scorcher:
return "veh@bicycle@mountainfront@base";
default:
return "veh@bicycle@roadfront@base";
}
}
private string PedalingAnimName(bool fast)
{
return fast ? "fast_pedal_char" : "cruise_pedal_char";
}
private void StartPedalingAnim(bool fast)
{
MainVehicle.Driver?.Task.PlayAnimation(PedalingAnimDict(), PedalingAnimName(fast), 8.0f, -8.0f, -1, AnimationFlags.Loop | AnimationFlags.AllowRotation, 1.0f);
}
private void StopPedalingAnim(bool fast)
{
MainVehicle.Driver.Task.ClearAnimation(PedalingAnimDict(), PedalingAnimName(fast));
}
#endregion
#region OUTGOING
internal float LastNozzleAngle { get; set; }
#endregion
}
}

View File

@ -0,0 +1,82 @@
using GTA;
using GTA.Math;
using RageCoop.Core;
using System.Collections.Generic;
namespace RageCoop.Client
{
public partial class SyncedVehicle
{
public Vehicle MainVehicle { get; internal set; }
#region -- SYNC DATA --
internal Vector3 RotationVelocity { get; set; }
internal float SteeringAngle { get; set; }
internal float ThrottlePower { get; set; }
internal float BrakePower { get; set; }
internal float DeluxoWingRatio { get; set; } = -1;
internal byte LandingGear { get; set; }
internal VehicleRoofState RoofState { get; set; }
internal VehicleDamageModel DamageModel { get; set; }
internal byte[] Colors { get; set; }
internal Dictionary<int, int> Mods { get; set; }
internal float EngineHealth { get; set; }
internal VehicleLockStatus LockStatus { get; set; }
internal byte RadioStation = 255;
internal string LicensePlate { get; set; }
internal int Livery { get; set; } = -1;
internal VehicleDataFlags Flags { get; set; }
#endregion
#region FLAGS
internal bool EngineRunning { get => Flags.HasVehFlag(VehicleDataFlags.IsEngineRunning); }
internal bool Transformed { get => Flags.HasVehFlag(VehicleDataFlags.IsTransformed); }
internal bool HornActive { get => Flags.HasVehFlag(VehicleDataFlags.IsHornActive); }
internal bool LightsOn { get => Flags.HasVehFlag(VehicleDataFlags.AreLightsOn); }
internal bool BrakeLightsOn { get => Flags.HasVehFlag(VehicleDataFlags.AreBrakeLightsOn); }
internal bool HighBeamsOn { get => Flags.HasVehFlag(VehicleDataFlags.AreHighBeamsOn); }
internal bool SireneActive { get => Flags.HasVehFlag(VehicleDataFlags.IsSirenActive); }
internal bool IsDead { get => Flags.HasVehFlag(VehicleDataFlags.IsDead); }
internal bool IsDeluxoHovering { get => Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering); }
#endregion
#region FIXED-DATA
internal bool IsFlipped
{
get => IsMotorcycle || ((Quaternion * Vector3.RelativeTop).Z - (Quaternion * Vector3.RelativeBottom).Z) < 0.5;
}
internal bool IsMotorcycle;
internal bool IsAircraft;
internal bool HasRocketBoost;
internal bool HasParachute;
internal bool HasRoof;
internal bool IsSubmarineCar;
internal bool IsDeluxo;
#endregion
#region PRIVATE
private byte[] _lastVehicleColors = new byte[] { 0, 0 };
private Dictionary<int, int> _lastVehicleMods = new Dictionary<int, int>();
private bool _lastHornActive = false;
private bool _lastTransformed = false;
internal int _lastLivery = -1;
private readonly List<Vector3> _predictedTrace = new List<Vector3>();
private readonly List<Vector3> _orgTrace = new List<Vector3>();
private Vector3 _predictedPosition;
#endregion
#region OUTGOING
internal float LastNozzleAngle { get; set; }
internal float LastEngineHealth { get; set; }
internal Vector3 LastVelocity { get; set; }
#endregion
}
}

View File

@ -0,0 +1,352 @@
using GTA;
using GTA.Math;
using GTA.Native;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Linq;
namespace RageCoop.Client
{
/// <summary>
/// A synchronized vehicle instance
/// </summary>
public partial class SyncedVehicle : SyncedEntity
{
#region -- CONSTRUCTORS --
/// <summary>
/// Create a local entity (outgoing sync)
/// </summary>
/// <param name="v"></param>
internal SyncedVehicle(Vehicle v)
{
ID = EntityPool.RequestNewID();
MainVehicle = v;
MainVehicle.CanPretendOccupants = false;
OwnerID = Main.LocalPlayerID;
SetUpFixedData();
}
internal void SetUpFixedData()
{
if (MainVehicle == null) { return; }
IsAircraft = MainVehicle.IsAircraft;
IsMotorcycle = MainVehicle.IsMotorcycle;
HasRocketBoost = MainVehicle.HasRocketBoost;
HasParachute = MainVehicle.HasParachute;
HasRoof = MainVehicle.HasRoof;
IsSubmarineCar = MainVehicle.IsSubmarineCar;
IsDeluxo = MainVehicle.Model == 1483171323;
}
/// <summary>
/// Create an empty VehicleEntity
/// </summary>
internal SyncedVehicle()
{
}
internal SyncedVehicle(int id)
{
ID = id;
LastSynced = Main.Ticked;
}
#endregion
/// <summary>
/// VehicleSeat,ID
/// </summary>
internal override void Update()
{
#if DEBUG_VEH
foreach(var s in _predictedTrace)
{
World.DrawMarker(MarkerType.DebugSphere, s, default, default, new Vector3(0.3f, 0.3f, 0.3f), Color.AliceBlue);
}
foreach (var s in _orgTrace)
{
World.DrawMarker(MarkerType.DebugSphere, s, default, default, new Vector3(0.3f, 0.3f, 0.3f), Color.Orange);
}
#endif
// Check if all data avalible
if (!IsReady || Owner == null) { return; }
// Check existence
if ((MainVehicle == null) || (!MainVehicle.Exists()) || (MainVehicle.Model != Model))
{
if (!CreateVehicle())
{
return;
}
}
DisplayVehicle();
// Skip update if no new sync message has arrived.
if (!NeedUpdate)
{
return;
}
if (SteeringAngle != MainVehicle.SteeringAngle)
{
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * SteeringAngle);
}
MainVehicle.ThrottlePower = ThrottlePower;
MainVehicle.BrakePower = BrakePower;
if (IsDead)
{
if (MainVehicle.IsDead)
{
return;
}
MainVehicle.Explode();
}
else
{
if (MainVehicle.IsDead)
{
Main.Delay(() =>
{
if (MainVehicle.IsDead && !IsDead)
{
MainVehicle.Repair();
}
}, 1000);
}
}
if (MainVehicle.IsOnFire)
{
if (!Flags.HasVehFlag(VehicleDataFlags.IsOnFire))
{
Function.Call(Hash.STOP_ENTITY_FIRE, MainVehicle);
}
}
else if (Flags.HasVehFlag(VehicleDataFlags.IsOnFire))
{
Function.Call(Hash.START_ENTITY_FIRE, MainVehicle);
}
if (EngineRunning != MainVehicle.IsEngineRunning)
{
MainVehicle.IsEngineRunning = EngineRunning;
}
if (LightsOn != MainVehicle.AreLightsOn)
{
MainVehicle.SetScriptedLightSetting(LightsOn ? ScriptedVehicleLightSetting.SetVehicleLightsOn : ScriptedVehicleLightSetting.SetVehicleLightsOff);
}
if (HighBeamsOn != MainVehicle.AreHighBeamsOn)
{
MainVehicle.AreHighBeamsOn = HighBeamsOn;
}
if (IsAircraft)
{
if (LandingGear != (byte)MainVehicle.LandingGearState)
{
MainVehicle.LandingGearState = (VehicleLandingGearState)LandingGear;
}
}
else
{
if (MainVehicle.HasSiren && SireneActive != MainVehicle.IsSirenActive)
{
MainVehicle.IsSirenActive = SireneActive;
}
if (HornActive)
{
if (!_lastHornActive)
{
_lastHornActive = true;
MainVehicle.SoundHorn(99999);
}
}
else if (_lastHornActive)
{
_lastHornActive = false;
MainVehicle.SoundHorn(1);
}
if (HasRoof && MainVehicle.RoofState != RoofState)
{
MainVehicle.RoofState = RoofState;
}
if (HasRocketBoost && Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive) != MainVehicle.IsRocketBoostActive())
{
MainVehicle.SetRocketBoostActive(Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive));
}
if (HasParachute && Flags.HasFlag(VehicleDataFlags.IsParachuteActive) != MainVehicle.IsParachuteActive())
{
MainVehicle.SetParachuteActive(Flags.HasFlag(VehicleDataFlags.IsParachuteActive));
}
if (IsSubmarineCar)
{
if (Transformed)
{
if (!_lastTransformed)
{
_lastTransformed = true;
Function.Call(Hash.TRANSFORM_TO_SUBMARINE, MainVehicle.Handle, false);
}
}
else if (_lastTransformed)
{
_lastTransformed = false;
Function.Call(Hash.TRANSFORM_TO_CAR, MainVehicle.Handle, false);
}
}
else if (IsDeluxo)
{
MainVehicle.SetDeluxoHoverState(IsDeluxoHovering);
if (IsDeluxoHovering)
{
MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
}
}
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
}
MainVehicle.LockStatus = LockStatus;
if (LastFullSynced >= LastUpdated)
{
if (Flags.HasVehFlag(VehicleDataFlags.Repaired))
{
MainVehicle.Repair();
}
if (Colors != null && Colors != _lastVehicleColors)
{
Function.Call(Hash.SET_VEHICLE_COLOURS, MainVehicle, Colors[0], Colors[1]);
_lastVehicleColors = Colors;
}
MainVehicle.EngineHealth = EngineHealth;
if (Mods != null && !Mods.Compare(_lastVehicleMods))
{
Function.Call(Hash.SET_VEHICLE_MOD_KIT, MainVehicle, 0);
foreach (KeyValuePair<int, int> mod in Mods)
{
MainVehicle.Mods[(VehicleModType)mod.Key].Index = mod.Value;
}
_lastVehicleMods = Mods;
}
if (Function.Call<string>(Hash.GET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle) != LicensePlate)
{
Function.Call(Hash.SET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle, LicensePlate);
}
if (_lastLivery != Livery)
{
Function.Call(Hash.SET_VEHICLE_LIVERY, MainVehicle, Livery);
_lastLivery = Livery;
}
MainVehicle.SetDamageModel(DamageModel);
}
LastUpdated = Main.Ticked;
}
private void DisplayVehicle()
{
_predictedPosition = Predict(Position);
var current = MainVehicle.ReadPosition();
var dist = current.DistanceTo(_predictedPosition);
var cali = dist * (_predictedPosition - current);
if (Velocity.Length() < 0.1) { cali *= 10; }
if (dist > 10)
{
MainVehicle.Position = _predictedPosition;
MainVehicle.Velocity = Velocity;
MainVehicle.Quaternion = Quaternion;
return;
}
if (dist > 0.03)
{
MainVehicle.Velocity = Velocity + cali;
}
Vector3 calirot;
if (IsFlipped || (calirot = GetCalibrationRotation()).Length() > 50)
{
MainVehicle.Quaternion = Quaternion.Slerp(MainVehicle.ReadQuaternion(), Quaternion, 0.5f);
MainVehicle.LocalRotationVelocity = RotationVelocity;
return;
}
MainVehicle.LocalRotationVelocity = RotationVelocity + calirot * 0.2f;
}
private Vector3 GetCalibrationRotation()
{
var rot = Quaternion.LookRotation(Quaternion * Vector3.RelativeFront, Quaternion * Vector3.RelativeTop).ToEulerAngles();
var curRot = Quaternion.LookRotation(MainVehicle.ReadQuaternion() * Vector3.RelativeFront, MainVehicle.ReadQuaternion() * Vector3.RelativeTop).ToEulerAngles();
var r = (rot - curRot).ToDegree();
if (r.X > 180) { r.X = r.X - 360; }
else if (r.X < -180) { r.X = 360 + r.X; }
if (r.Y > 180) { r.Y = r.Y - 360; }
else if (r.Y < -180) { r.Y = 360 + r.Y; }
if (r.Z > 180) { r.Z = r.Z - 360; }
else if (r.Z < -180) { r.Z = 360 + r.Z; }
return r;
}
private bool CreateVehicle()
{
var existing = World.GetNearbyVehicles(Position, 2).ToList().FirstOrDefault();
if (existing != null && existing != MainVehicle)
{
if (EntityPool.VehiclesByHandle.ContainsKey(existing.Handle))
{
EntityPool.RemoveVehicle(ID);
return false;
}
existing.Delete();
}
MainVehicle?.Delete();
MainVehicle = Util.CreateVehicle(Model, Position);
if (!Model.IsInCdImage)
{
// GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
return false;
}
if (MainVehicle == null)
{
Model.Request();
return false;
}
lock (EntityPool.VehiclesLock)
{
EntityPool.Add(this);
}
MainVehicle.Quaternion = Quaternion;
if (MainVehicle.HasRoof)
{
MainVehicle.RoofState = RoofState;
}
foreach (var w in MainVehicle.Wheels)
{
w.Fix();
}
if (IsInvincible) { MainVehicle.IsInvincible = true; }
SetUpFixedData();
Model.MarkAsNoLongerNeeded();
return true;
}
}
}

View File

@ -1,85 +1,81 @@

using System;
using GTA;
using GTA;
using GTA.Native;
using RageCoop.Core;
using Lidgren.Network;
using RageCoop.Client.Scripting;
using System;
using System.Collections.Generic;
using System.Linq;
using RageCoop.Client.Scripting;
using System.Text;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Security.Cryptography;
namespace RageCoop.Client
{
internal class EntityPool
{
private static bool _trafficSpawning=true;
public static object PedsLock = new object();
private static Dictionary<int, SyncedPed> ID_Peds = new Dictionary<int, SyncedPed>();
public static int CharactersCount { get { return ID_Peds.Count; } }
#if BENCHMARK
private static Stopwatch PerfCounter=new Stopwatch();
private static Stopwatch PerfCounter2=Stopwatch.StartNew();
#endif
/// <summary>
/// Faster access to Character with Handle, but values may not equal to <see cref="ID_Peds"/> since Ped might not have been created.
/// </summary>
private static Dictionary<int, SyncedPed> Handle_Peds = new Dictionary<int, SyncedPed>();
#region ACTIVE INSTANCES
public static Dictionary<int, SyncedPed> PedsByID = new Dictionary<int, SyncedPed>();
public static Dictionary<int, SyncedPed> PedsByHandle = new Dictionary<int, SyncedPed>();
public static object VehiclesLock = new object();
private static Dictionary<int, SyncedVehicle> ID_Vehicles = new Dictionary<int, SyncedVehicle>();
private static Dictionary<int, SyncedVehicle> Handle_Vehicles = new Dictionary<int, SyncedVehicle>();
public static Dictionary<int, SyncedVehicle> VehiclesByID = new Dictionary<int, SyncedVehicle>();
public static Dictionary<int, SyncedVehicle> VehiclesByHandle = new Dictionary<int, SyncedVehicle>();
public static object ProjectilesLock = new object();
private static Dictionary<int, SyncedProjectile> ID_Projectiles = new Dictionary<int, SyncedProjectile>();
private static Dictionary<int, SyncedProjectile> Handle_Projectiles = new Dictionary<int, SyncedProjectile>();
public static Dictionary<int, SyncedProjectile> ProjectilesByID = new Dictionary<int, SyncedProjectile>();
public static Dictionary<int, SyncedProjectile> ProjectilesByHandle = new Dictionary<int, SyncedProjectile>();
public static object PropsLock=new object();
public static Dictionary<int,SyncedProp> ServerProps=new Dictionary<int,SyncedProp>();
public static object BlipsLock = new object();
public static Dictionary<int, SyncedProp> ServerProps = new Dictionary<int, SyncedProp>();
public static Dictionary<int, Blip> ServerBlips = new Dictionary<int, Blip>();
#endregion
public static void Cleanup(bool keepPlayer=true,bool keepMine=true)
#region LOCKS
public static object VehiclesLock = new object();
public static object ProjectilesLock = new object();
public static object PropsLock = new object();
public static object BlipsLock = new object();
#endregion
public static void Cleanup(bool keepPlayer = true, bool keepMine = true)
{
foreach(int id in new List<int>(ID_Peds.Keys))
foreach (var ped in PedsByID.Values.ToArray())
{
if (keepPlayer&&(id==Main.LocalPlayerID)) { continue; }
if (keepMine&&(ID_Peds[id].OwnerID==Main.LocalPlayerID)) { continue; }
RemovePed(id);
if ((keepPlayer && (ped.ID == Main.LocalPlayerID)) || (keepMine && (ped.OwnerID == Main.LocalPlayerID))) { continue; }
RemovePed(ped.ID);
}
ID_Peds.Clear();
Handle_Peds.Clear();
PedsByID.Clear();
PedsByHandle.Clear();
foreach (int id in new List<int>(ID_Vehicles.Keys))
foreach (int id in VehiclesByID.Keys.ToArray())
{
if (keepMine&&(ID_Vehicles[id].OwnerID==Main.LocalPlayerID)) { continue; }
if (keepMine && (VehiclesByID[id].OwnerID == Main.LocalPlayerID)) { continue; }
RemoveVehicle(id);
}
ID_Vehicles.Clear();
Handle_Vehicles.Clear();
VehiclesByID.Clear();
VehiclesByHandle.Clear();
foreach(var p in ID_Projectiles.Values)
foreach (var p in ProjectilesByID.Values)
{
if (p.ShooterID!=Main.LocalPlayerID && p.MainProjectile!=null && p.MainProjectile.Exists())
if (p.Shooter.ID != Main.LocalPlayerID && p.MainProjectile != null && p.MainProjectile.Exists())
{
p.MainProjectile.Delete();
}
}
ID_Projectiles.Clear();
Handle_Projectiles.Clear();
ProjectilesByID.Clear();
ProjectilesByHandle.Clear();
foreach(var p in ServerProps.Values)
foreach (var p in ServerProps.Values)
{
p?.MainProp?.Delete();
}
ServerProps.Clear();
foreach(var b in ServerBlips.Values)
foreach (var b in ServerBlips.Values)
{
if (b.Exists())
{
@ -90,102 +86,94 @@ namespace RageCoop.Client
}
#region PEDS
public static SyncedPed GetPedByID(int id)
{
return ID_Peds.ContainsKey(id) ? ID_Peds[id] : null;
}
public static SyncedPed GetPedByHandle(int handle)
{
return Handle_Peds.ContainsKey(handle) ? Handle_Peds[handle] : null;
}
public static List<int> GetPedIDs()
{
return new List<int>(ID_Peds.Keys);
}
public static SyncedPed GetPedByID(int id) => PedsByID.TryGetValue(id, out var p) ? p : null;
public static SyncedPed GetPedByHandle(int handle) => PedsByHandle.TryGetValue(handle, out var p) ? p : null;
public static List<int> GetPedIDs() => new List<int>(PedsByID.Keys);
public static bool AddPlayer()
{
Ped p = Game.Player.Character;
// var clipset=p.Gender==Gender.Male? "MOVE_M@TOUGH_GUY@" : "MOVE_F@TOUGH_GUY@";
// Function.Call(Hash.SET_PED_MOVEMENT_CLIPSET,p,clipset,1f);
SyncedPed player = GetPedByID(Main.LocalPlayerID);
if (player!=null)
{
if (player.MainPed!=p)
{
// Player model changed
player.MainPed = p;
// Remove it from Handle_Characters
var pairs=Handle_Peds.Where(x=>x.Value==player);
if (pairs.Any())
{
var pair=pairs.First();
// Re-add
Handle_Peds.Remove(pair.Key);
if (Handle_Peds.ContainsKey(p.Handle))
{
RemovePed(Handle_Peds[p.Handle].ID);
}
Handle_Peds.Add(p.Handle, player);
}
}
}
else
if (player == null)
{
Main.Logger.Debug($"Creating SyncEntity for player, handle:{p.Handle}");
SyncedPed c = new SyncedPed(p);
Main.LocalPlayerID=c.OwnerID=c.ID;
Main.LocalPlayerID = c.OwnerID = c.ID;
Add(c);
Main.Logger.Debug($"Local player ID is:{c.ID}");
PlayerList.SetPlayer(c.ID, Main.Settings.Username );
PlayerList.SetPlayer(c.ID, Main.Settings.Username);
return true;
}
if (player.MainPed != p)
{
// Player model changed
player.MainPed = p;
// Remove it from Handle_Characters
var pairs = PedsByHandle.Where(x => x.Value == player);
if (pairs.Any())
{
var pair = pairs.First();
// Re-add
PedsByHandle.Remove(pair.Key);
if (PedsByHandle.ContainsKey(p.Handle))
{
RemovePed(PedsByHandle[p.Handle].ID);
}
PedsByHandle.Add(p.Handle, player);
}
}
return false;
}
public static void Add(SyncedPed c)
{
if (ID_Peds.ContainsKey(c.ID))
if (PedsByID.ContainsKey(c.ID))
{
ID_Peds[c.ID]=c;
PedsByID[c.ID] = c;
}
else
{
ID_Peds.Add(c.ID, c);
PedsByID.Add(c.ID, c);
}
if (c.MainPed==null) { return; }
if (Handle_Peds.ContainsKey(c.MainPed.Handle))
if (c.MainPed == null) { return; }
if (PedsByHandle.ContainsKey(c.MainPed.Handle))
{
Handle_Peds[c.MainPed.Handle]=c;
PedsByHandle[c.MainPed.Handle] = c;
}
else
{
Handle_Peds.Add(c.MainPed.Handle, c);
PedsByHandle.Add(c.MainPed.Handle, c);
}
if (c.IsLocal)
{
API.Events.InvokePedSpawned(c);
}
}
public static void RemovePed(int id,string reason="Cleanup")
public static void RemovePed(int id, string reason = "Cleanup")
{
if (ID_Peds.ContainsKey(id))
if (PedsByID.ContainsKey(id))
{
SyncedPed c = ID_Peds[id];
SyncedPed c = PedsByID[id];
var p = c.MainPed;
if (p!=null)
if (p != null)
{
if (Handle_Peds.ContainsKey(p.Handle))
if (PedsByHandle.ContainsKey(p.Handle))
{
Handle_Peds.Remove(p.Handle);
PedsByHandle.Remove(p.Handle);
}
// Main.Logger.Debug($"Removing ped {c.ID}. Reason:{reason}");
p.AttachedBlip?.Delete();
p.Kill();
p.Model.MarkAsNoLongerNeeded();
p.MarkAsNoLongerNeeded();
p.Delete();
}
c.PedBlip?.Delete();
c.ParachuteProp?.Delete();
ID_Peds.Remove(id);
PedsByID.Remove(id);
if (c.IsLocal)
{
API.Events.InvokePedDeleted(c);
@ -195,60 +183,52 @@ namespace RageCoop.Client
#endregion
#region VEHICLES
public static SyncedVehicle GetVehicleByID(int id)
{
return ID_Vehicles.ContainsKey(id) ? ID_Vehicles[id] : null;
}
public static SyncedVehicle GetVehicleByHandle(int handle)
{
return Handle_Vehicles.ContainsKey(handle) ? Handle_Vehicles[handle] : null;
}
public static List<int> GetVehicleIDs()
{
return new List<int>(ID_Vehicles.Keys);
}
public static SyncedVehicle GetVehicleByID(int id) => VehiclesByID.TryGetValue(id, out var v) ? v : null;
public static SyncedVehicle GetVehicleByHandle(int handle) => VehiclesByHandle.TryGetValue(handle, out var v) ? v : null;
public static List<int> GetVehicleIDs() => new List<int>(VehiclesByID.Keys);
public static void Add(SyncedVehicle v)
{
if (ID_Vehicles.ContainsKey(v.ID))
if (VehiclesByID.ContainsKey(v.ID))
{
ID_Vehicles[v.ID]=v;
VehiclesByID[v.ID] = v;
}
else
{
ID_Vehicles.Add(v.ID, v);
VehiclesByID.Add(v.ID, v);
}
if (v.MainVehicle==null) { return; }
if (Handle_Vehicles.ContainsKey(v.MainVehicle.Handle))
if (v.MainVehicle == null) { return; }
if (VehiclesByHandle.ContainsKey(v.MainVehicle.Handle))
{
Handle_Vehicles[v.MainVehicle.Handle]=v;
VehiclesByHandle[v.MainVehicle.Handle] = v;
}
else
{
Handle_Vehicles.Add(v.MainVehicle.Handle, v);
VehiclesByHandle.Add(v.MainVehicle.Handle, v);
}
if (v.IsLocal)
{
API.Events.InvokeVehicleSpawned(v);
}
}
public static void RemoveVehicle(int id,string reason = "Cleanup")
public static void RemoveVehicle(int id, string reason = "Cleanup")
{
if (ID_Vehicles.ContainsKey(id))
if (VehiclesByID.ContainsKey(id))
{
SyncedVehicle v = ID_Vehicles[id];
SyncedVehicle v = VehiclesByID[id];
var veh = v.MainVehicle;
if (veh!=null)
if (veh != null)
{
if (Handle_Vehicles.ContainsKey(veh.Handle))
if (VehiclesByHandle.ContainsKey(veh.Handle))
{
Handle_Vehicles.Remove(veh.Handle);
VehiclesByHandle.Remove(veh.Handle);
}
// Main.Logger.Debug($"Removing vehicle {v.ID}. Reason:{reason}");
veh.AttachedBlip?.Delete();
veh.Model.MarkAsNoLongerNeeded();
veh.MarkAsNoLongerNeeded();
veh.Delete();
}
ID_Vehicles.Remove(id);
VehiclesByID.Remove(id);
if (v.IsLocal) { API.Events.InvokeVehicleDeleted(v); }
}
}
@ -258,92 +238,77 @@ namespace RageCoop.Client
#region PROJECTILES
public static SyncedProjectile GetProjectileByID(int id)
{
return ID_Projectiles.ContainsKey(id) ? ID_Projectiles[id] : null;
return ProjectilesByID.TryGetValue(id, out var p) ? p : null;
}
public static void Add(SyncedProjectile p)
{
if (!p.IsValid) { return; }
if (ID_Projectiles.ContainsKey(p.ID))
if (p.WeaponHash == (WeaponHash)VehicleWeaponHash.Tank)
{
ID_Projectiles[p.ID]=p;
Networking.SendBullet(p.Position, p.Position + p.Velocity, (uint)VehicleWeaponHash.Tank, ((SyncedVehicle)p.Shooter).MainVehicle.Driver.GetSyncEntity().ID);
}
if (ProjectilesByID.ContainsKey(p.ID))
{
ProjectilesByID[p.ID] = p;
}
else
{
ID_Projectiles.Add(p.ID, p);
ProjectilesByID.Add(p.ID, p);
}
if (p.MainProjectile==null) { return; }
if (Handle_Projectiles.ContainsKey(p.MainProjectile.Handle))
if (p.MainProjectile == null) { return; }
if (ProjectilesByHandle.ContainsKey(p.MainProjectile.Handle))
{
Handle_Projectiles[p.MainProjectile.Handle]=p;
ProjectilesByHandle[p.MainProjectile.Handle] = p;
}
else
{
Handle_Projectiles.Add(p.MainProjectile.Handle, p);
ProjectilesByHandle.Add(p.MainProjectile.Handle, p);
}
}
public static void RemoveProjectile(int id, string reason)
{
if (ID_Projectiles.ContainsKey(id))
if (ProjectilesByID.ContainsKey(id))
{
SyncedProjectile sp = ID_Projectiles[id];
SyncedProjectile sp = ProjectilesByID[id];
var p = sp.MainProjectile;
if (p!=null)
if (p != null)
{
if (Handle_Projectiles.ContainsKey(p.Handle))
if (ProjectilesByHandle.ContainsKey(p.Handle))
{
Handle_Projectiles.Remove(p.Handle);
ProjectilesByHandle.Remove(p.Handle);
}
Main.Logger.Debug($"Removing projectile {sp.ID}. Reason:{reason}");
p.Explode();
//Main.Logger.Debug($"Removing projectile {sp.ID}. Reason:{reason}");
if (sp.Exploded) p.Explode();
}
ID_Projectiles.Remove(id);
ProjectilesByID.Remove(id);
}
}
public static bool PedExists(int id)
{
return ID_Peds.ContainsKey(id);
}
public static bool VehicleExists(int id)
{
return ID_Vehicles.ContainsKey(id);
}
public static bool ProjectileExists(int id)
{
return ID_Projectiles.ContainsKey(id);
}
public static bool PedExists(int id) => PedsByID.ContainsKey(id);
public static bool VehicleExists(int id) => VehiclesByID.ContainsKey(id);
public static bool ProjectileExists(int id) => ProjectilesByID.ContainsKey(id);
#endregion
static int vehStateIndex;
static int pedStateIndex;
static int vehStatesPerFrame;
static int pedStatesPerFrame;
static int i;
public static Ped[] allPeds=new Ped[0];
public static Vehicle[] allVehicles=new Vehicle[0];
public static Projectile[] allProjectiles=new Projectile[0];
private static int vehStateIndex;
private static int pedStateIndex;
private static int vehStatesPerFrame;
private static int pedStatesPerFrame;
private static int i;
public static Ped[] allPeds = new Ped[0];
public static Vehicle[] allVehicles = new Vehicle[0];
public static Projectile[] allProjectiles = new Projectile[0];
public static void DoSync()
{
UpdateTargets();
#if BENCHMARK
PerfCounter.Restart();
Debug.TimeStamps[TimeStamp.CheckProjectiles]=PerfCounter.ElapsedTicks;
#endif
allPeds = World.GetAllPeds();
allVehicles=World.GetAllVehicles();
allProjectiles=World.GetAllProjectiles();
vehStatesPerFrame=allVehicles.Length*2/(int)Game.FPS+1;
pedStatesPerFrame=allPeds.Length*2/(int)Game.FPS+1;
if (Main.Ticked%50==0)
{
bool flag1 = allVehicles.Length>Main.Settings.WorldVehicleSoftLimit && Main.Settings.WorldVehicleSoftLimit>-1;
bool flag2 = allPeds.Length>Main.Settings.WorldPedSoftLimit && Main.Settings.WorldPedSoftLimit>-1;
if ((flag1||flag2) && _trafficSpawning)
{ SetBudget(0); _trafficSpawning=false; }
else if(!_trafficSpawning)
{ SetBudget(1); _trafficSpawning=true; }
}
allVehicles = World.GetAllVehicles();
allProjectiles = World.GetAllProjectiles();
vehStatesPerFrame = allVehicles.Length * 2 / (int)Game.FPS + 1;
pedStatesPerFrame = allPeds.Length * 2 / (int)Game.FPS + 1;
#if BENCHMARK
Debug.TimeStamps[TimeStamp.GetAllEntities]=PerfCounter.ElapsedTicks;
@ -354,31 +319,24 @@ namespace RageCoop.Client
foreach (Projectile p in allProjectiles)
{
if (!Handle_Projectiles.ContainsKey(p.Handle))
if (!ProjectilesByHandle.ContainsKey(p.Handle))
{
Add(new SyncedProjectile(p));
}
}
foreach (SyncedProjectile p in ID_Projectiles.Values.ToArray())
foreach (SyncedProjectile p in ProjectilesByID.Values.ToArray())
{
// Outgoing sync
if (p.IsLocal)
{
if (p.MainProjectile.AttachedEntity==null)
if (p.MainProjectile.AttachedEntity == null)
{
// Prevent projectiles from exploding next to vehicle
if (WeaponUtil.VehicleProjectileWeapons.Contains((VehicleWeaponHash)p.MainProjectile.WeaponHash))
if (p.WeaponHash == (WeaponHash)VehicleWeaponHash.Tank || (p.MainProjectile.OwnerEntity?.EntityType == EntityType.Vehicle && p.MainProjectile.Position.DistanceTo(p.Origin) < 2))
{
if (p.MainProjectile.WeaponHash!=(WeaponHash)VehicleWeaponHash.Tank && p.Origin.DistanceTo(p.MainProjectile.Position)<2)
{
continue;
}
continue;
}
Networking.SendProjectile(p);
}
}
@ -392,48 +350,52 @@ namespace RageCoop.Client
{
p.Update();
}
}
}
}
i=-1;
i = -1;
lock (PedsLock)
{
EntityPool.AddPlayer();
AddPlayer();
var mainCharacters = new List<PedHash> { PedHash.Michael, PedHash.Franklin, PedHash.Franklin02, PedHash.Trevor };
foreach (Ped p in allPeds)
{
SyncedPed c = EntityPool.GetPedByHandle(p.Handle);
if (c==null && (p!=Game.Player.Character))
if (!PedsByHandle.ContainsKey(p.Handle) && p != Game.Player.Character && !mainCharacters.Contains((PedHash)p.Model.Hash))
{
if (PedsByID.Count(x => x.Value.IsLocal) > Main.Settings.WorldPedSoftLimit)
{
if (p.PopulationType == EntityPopulationType.RandomAmbient && !p.IsInVehicle())
{
p.Delete();
continue;
}
if (p.PopulationType == EntityPopulationType.RandomScenario) continue;
}
// Main.Logger.Trace($"Creating SyncEntity for ped, handle:{p.Handle}");
c=new SyncedPed(p);
EntityPool.Add(c);
Add(new SyncedPed(p));
}
}
#if BENCHMARK
Debug.TimeStamps[TimeStamp.AddPeds]=PerfCounter.ElapsedTicks;
#endif
var ps = ID_Peds.Values.ToArray();
pedStateIndex+=pedStatesPerFrame;
if (pedStateIndex>=ps.Length)
var ps = PedsByID.Values.ToArray();
pedStateIndex += pedStatesPerFrame;
if (pedStateIndex >= ps.Length)
{
pedStateIndex=0;
pedStateIndex = 0;
}
foreach (SyncedPed c in ps)
{
i++;
if ((c.MainPed!=null)&&(!c.MainPed.Exists()))
if ((c.MainPed != null) && (!c.MainPed.Exists()))
{
EntityPool.RemovePed(c.ID, "non-existent");
RemovePed(c.ID, "non-existent");
continue;
}
@ -446,15 +408,8 @@ namespace RageCoop.Client
// event check
SyncEvents.Check(c);
Networking.SendPed(c);
// Send state
if ((i-pedStateIndex)<pedStatesPerFrame)
{
Networking.SendPedState(c);
}
Networking.SendPed(c, (i - pedStateIndex) < pedStatesPerFrame);
#if BENCHMARK
Debug.TimeStamps[TimeStamp.SendPed]=PerfCounter2.ElapsedTicks-start;
#endif
}
@ -469,102 +424,116 @@ namespace RageCoop.Client
RemovePed(c.ID, "OutOfSync");
}
#if BENCHMARK
Debug.TimeStamps[TimeStamp.UpdatePed]=PerfCounter2.ElapsedTicks-start;
#endif
}
}
#if BENCHMARK
Debug.TimeStamps[TimeStamp.PedTotal]=PerfCounter.ElapsedTicks;
#endif
}
i=-1;
var check = Main.Ticked % 100 == 0;
i = -1;
lock (VehiclesLock)
{
foreach (Vehicle veh in allVehicles)
{
if (!Handle_Vehicles.ContainsKey(veh.Handle))
if (!VehiclesByHandle.ContainsKey(veh.Handle))
{
if (VehiclesByID.Count(x => x.Value.IsLocal) > Main.Settings.WorldVehicleSoftLimit)
{
if (veh.PopulationType == EntityPopulationType.RandomAmbient || veh.PopulationType == EntityPopulationType.RandomParked)
{
foreach (var p in veh.Occupants)
{
p.Delete();
var c = GetPedByHandle(p.Handle);
if (c != null)
{
RemovePed(c.ID, "ThrottleTraffic");
}
}
veh.Delete();
continue;
}
}
// Main.Logger.Debug($"Creating SyncEntity for vehicle, handle:{veh.Handle}");
EntityPool.Add(new SyncedVehicle(veh));
Add(new SyncedVehicle(veh));
}
}
#if BENCHMARK
Debug.TimeStamps[TimeStamp.AddVehicles]=PerfCounter.ElapsedTicks;
#endif
var vs = ID_Vehicles.Values.ToArray();
vehStateIndex+=vehStatesPerFrame;
if (vehStateIndex>=vs.Length)
var vs = VehiclesByID.Values.ToArray();
vehStateIndex += vehStatesPerFrame;
if (vehStateIndex >= vs.Length)
{
vehStateIndex=0;
vehStateIndex = 0;
}
foreach (SyncedVehicle v in vs)
{
i++;
if ((v.MainVehicle!=null)&&(!v.MainVehicle.Exists()))
if ((v.MainVehicle != null) && (!v.MainVehicle.Exists()))
{
EntityPool.RemoveVehicle(v.ID,"non-existent");
RemoveVehicle(v.ID, "non-existent");
continue;
}
if (check)
{
v.SetUpFixedData();
}
// Outgoing sync
if (v.IsLocal)
{
if (!v.MainVehicle.IsVisible) { continue; }
SyncEvents.Check(v);
Networking.SendVehicle(v);
// Send state
if ((i-vehStateIndex)<vehStatesPerFrame)
{
Networking.SendVehicleState(v);
}
Networking.SendVehicle(v, (i - vehStateIndex) < vehStatesPerFrame);
}
else // Incoming sync
{
v.Update();
if (v.IsOutOfSync)
{
RemoveVehicle(v.ID, "OutOfSync");
}
}
}
#if BENCHMARK
Debug.TimeStamps[TimeStamp.VehicleTotal]=PerfCounter.ElapsedTicks;
#endif
}
Networking.Peer.FlushSendQueue();
}
private static void UpdateTargets()
{
Networking.Targets = new List<NetConnection>(PlayerList.Players.Count) { Networking.ServerConnection };
foreach (var p in PlayerList.Players.Values.ToArray())
{
if (p.HasDirectConnection && p.Position.DistanceTo(Main.PlayerPosition) < 500)
{
Networking.Targets.Add(p.Connection);
}
}
}
public static void RemoveAllFromPlayer(int playerPedId)
{
foreach(SyncedPed p in ID_Peds.Values.ToArray())
foreach (SyncedPed p in PedsByID.Values.ToArray())
{
if (p.OwnerID==playerPedId)
if (p.OwnerID == playerPedId)
{
RemovePed(p.ID);
}
}
foreach (SyncedVehicle v in ID_Vehicles.Values.ToArray())
foreach (SyncedVehicle v in VehiclesByID.Values.ToArray())
{
if (v.OwnerID==playerPedId)
if (v.OwnerID == playerPedId)
{
RemoveVehicle(v.ID);
}
@ -573,11 +542,8 @@ namespace RageCoop.Client
public static int RequestNewID()
{
int ID=0;
while ((ID==0)
|| ID_Peds.ContainsKey(ID)
|| ID_Vehicles.ContainsKey(ID)
|| ID_Projectiles.ContainsKey(ID))
int ID = 0;
while ((ID == 0) || PedsByID.ContainsKey(ID) || VehiclesByID.ContainsKey(ID) || ProjectilesByID.ContainsKey(ID))
{
byte[] rngBytes = new byte[4];
@ -595,36 +561,34 @@ namespace RageCoop.Client
}
public static string DumpDebug()
{
string s= "";
s+="\nID_Peds: "+ID_Peds.Count;
s+="\nHandle_Peds: "+Handle_Peds.Count;
s+="\nID_Vehicles: "+ID_Vehicles.Count;
s+="\nHandle_Vehicles: "+Handle_Vehicles.Count;
s+="\nID_Projectiles: "+ID_Projectiles.Count;
s+="\nHandle_Projectiles: "+Handle_Projectiles.Count;
s+="\npedStatesPerFrame:"+pedStatesPerFrame;
s+="\nvehStatesPerFrame:"+vehStatesPerFrame;
return s;
return $"\nID_Peds: {PedsByID.Count}" +
$"\nHandle_Peds: {PedsByHandle.Count}" +
$"\nID_Vehicles: {VehiclesByID.Count}" +
$"\nHandle_vehicles: {VehiclesByHandle.Count}" +
$"\nID_Projectiles: {ProjectilesByID.Count}" +
$"\nHandle_Projectiles: {ProjectilesByHandle.Count}" +
$"\npedStatesPerFrame: {pedStatesPerFrame}" +
$"\nvehStatesPerFrame: {vehStatesPerFrame}";
}
public static class ThreadSafe
{
public static void Add(SyncedVehicle v)
{
lock (EntityPool.VehiclesLock)
lock (VehiclesLock)
{
EntityPool.Add(v);
}
}
public static void Add(SyncedPed p)
{
lock (EntityPool.PedsLock)
lock (PedsLock)
{
EntityPool.Add(p);
}
}
public static void Add(SyncedProjectile sp)
{
lock (EntityPool.ProjectilesLock)
lock (ProjectilesLock)
{
EntityPool.Add(sp);
}

View File

@ -1,103 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA;
using GTA;
using GTA.Math;
using Lidgren.Network;
using RageCoop.Core;
using GTA.Native;
using System.Threading;
using System;
namespace RageCoop.Client {
namespace RageCoop.Client
{
internal static class SyncEvents
{
#region TRIGGER
public static void TriggerPedKilled(SyncedPed victim)
{
Networking.Send(new Packets.PedKilled() { VictimID=victim.ID},ConnectionChannel.SyncEvents);
Networking.SendSync(new Packets.PedKilled() { VictimID = victim.ID }, ConnectionChannel.SyncEvents);
}
public static void TriggerEnteringVehicle(SyncedPed c,SyncedVehicle veh, VehicleSeat seat)
{
Networking.
Send(new Packets.EnteringVehicle()
{
PedID=c.ID,
VehicleID= veh.ID,
VehicleSeat=(short)seat,
}, ConnectionChannel.SyncEvents);
}
public static void TriggerEnteredVehicle(SyncedPed c, SyncedVehicle veh, VehicleSeat seat)
{
if (seat==VehicleSeat.Driver)
{
veh.OwnerID=Main.LocalPlayerID;
veh.LastSynced=Main.Ticked;
TriggerChangeOwner(veh, c.ID);
}
Networking.Send(new Packets.EnteredVehicle()
{
VehicleSeat=(short)seat,
PedID=c.ID,
VehicleID=veh.ID
},ConnectionChannel.SyncEvents);
}
public static void TriggerChangeOwner(SyncedVehicle c, int newOwnerID)
public static void TriggerChangeOwner(int vehicleID, int newOwnerID)
{
Networking.Send(new Packets.OwnerChanged()
Networking.SendSync(new Packets.OwnerChanged()
{
ID= c.ID,
NewOwnerID= newOwnerID,
}, ConnectionChannel.SyncEvents);
ID = vehicleID,
NewOwnerID = newOwnerID,
}, ConnectionChannel.SyncEvents, NetDeliveryMethod.ReliableOrdered);
}
public static void TriggerBulletShot(uint hash,SyncedPed owner,Vector3 impactPosition)
public static void TriggerBulletShot(uint hash, SyncedPed owner, Vector3 impactPosition)
{
// Main.Logger.Trace($"bullet shot:{(WeaponHash)hash}");
var start = owner.MainPed.GetMuzzlePosition();
if (owner.MainPed.IsOnTurretSeat()) { start=owner.MainPed.Bones[Bone.SkelHead].Position; }
if (start.DistanceTo(impactPosition)>10)
if (owner.MainPed.IsOnTurretSeat()) { start = owner.MainPed.Bones[Bone.SkelHead].Position; }
if (start.DistanceTo(impactPosition) > 10)
{
// Reduce latency
start=impactPosition-(impactPosition-start).Normalized*10;
start = impactPosition - (impactPosition - start).Normalized * 10;
}
Networking.SendBulletShot(start, impactPosition, hash, owner.ID);
}
public static void TriggerLeaveVehicle(int id)
{
Networking.
Send(new Packets.LeaveVehicle()
{
ID=id
}, ConnectionChannel.SyncEvents);
Networking.SendBullet(start, impactPosition, hash, owner.ID);
}
public static void TriggerVehBulletShot(uint hash, Vehicle veh, SyncedPed owner)
{
// ANNIHL
if (veh.Model.Hash==837858166)
{
Networking.SendBulletShot(veh.Bones[35].Position, veh.Bones[35].Position+veh.Bones[35].ForwardVector,hash,owner.ID);
Networking.SendBulletShot(veh.Bones[36].Position, veh.Bones[36].Position+veh.Bones[36].ForwardVector,hash, owner.ID);
Networking.SendBulletShot(veh.Bones[37].Position, veh.Bones[37].Position+veh.Bones[37].ForwardVector,hash, owner.ID);
Networking.SendBulletShot(veh.Bones[38].Position, veh.Bones[38].Position+veh.Bones[38].ForwardVector,hash, owner.ID);
return;
}
var info = veh.GetMuzzleInfo();
if (info==null) { Main.Logger.Warning($"Failed to get muzzle info for vehicle:{veh.DisplayName}");return; }
Networking.SendBulletShot(info.Position,info.Position+info.ForawardVector,hash,owner.ID);
int i;
// ANNIHL
if (veh.Model.Hash == 837858166)
{
Networking.SendVehicleBullet(hash, owner, veh.Bones[35]);
Networking.SendVehicleBullet(hash, owner, veh.Bones[36]);
Networking.SendVehicleBullet(hash, owner, veh.Bones[37]);
Networking.SendVehicleBullet(hash, owner, veh.Bones[38]);
}
else if ((i = veh.GetMuzzleIndex()) != -1)
{
Networking.SendVehicleBullet(hash, owner, veh.Bones[i]);
}
else
{
Main.Logger.Warning($"Failed to get muzzle info for vehicle:{veh.DisplayName}");
}
}
public static void TriggerNozzleTransform(int vehID,bool hover)
public static void TriggerNozzleTransform(int vehID, bool hover)
{
Networking.Send(new Packets.NozzleTransform() { VehicleID=vehID, Hover=hover }, ConnectionChannel.SyncEvents);
Networking.SendSync(new Packets.NozzleTransform() { VehicleID = vehID, Hover = hover }, ConnectionChannel.SyncEvents);
}
#endregion
@ -105,58 +71,21 @@ namespace RageCoop.Client {
#region HANDLE
public static ParticleEffectAsset CorePFXAsset = new ParticleEffectAsset("core");
private static WeaponAsset _weaponAsset = default;
private static uint _lastWeaponHash;
static WeaponAsset _weaponAsset = default;
static uint _lastWeaponHash;
private static void HandleLeaveVehicle(Packets.LeaveVehicle p)
{
var ped = EntityPool.GetPedByID(p.ID);
var veh = ped.MainPed.CurrentVehicle.GetSyncEntity();
veh._checkSeat=false;
var flag = LeaveVehicleFlags.None;
if (ped.MainPed?.CurrentVehicle==null) { return; }
// Bail out
if (ped.MainPed.CurrentVehicle.Speed>5) { flag|=LeaveVehicleFlags.BailOut;}
// ped.PauseUpdate((ulong)Game.FPS*2);
ped.MainPed.Task.LeaveVehicle(flag) ;
Task.Run(() =>
{
Thread.Sleep(1000);
veh._checkSeat=true;
});
}
private static void HandlePedKilled(Packets.PedKilled p)
{
EntityPool.GetPedByID(p.VictimID)?.MainPed?.Kill();
}
private static void HandleEnteringVehicle(SyncedPed c, SyncedVehicle veh, VehicleSeat seat)
{
c.MainPed?.Task.EnterVehicle(veh.MainVehicle, seat,-1,2,EnterVehicleFlags.WarpToDoor|EnterVehicleFlags.AllowJacking);
}
private static void HandleEnteredVehicle(int pedId, int vehId, VehicleSeat seat)
{
var v = EntityPool.GetVehicleByID(vehId);
var p = EntityPool.GetPedByID(pedId)?.MainPed;
if (v==null||p==null) { return; }
if (!v.MainVehicle.IsSeatFree(seat))
{
if (v.MainVehicle.GetPedOnSeat(seat)!=p)
{
v.MainVehicle.GetPedOnSeat(seat).Task.WarpOutOfVehicle(v.MainVehicle);
}
}
p.SetIntoVehicle(v.MainVehicle, seat);
}
private static void HandleOwnerChanged(Packets.OwnerChanged p)
{
var v = EntityPool.GetVehicleByID(p.ID);
if (v==null) { return; }
v.OwnerID=p.NewOwnerID;
v.ModelHash=v.MainVehicle.Model;
v.LastSynced=Main.Ticked;
// So this vehicle doesn's get re-spawned
if (v == null) { return; }
v.OwnerID = p.NewOwnerID;
v.LastSynced = Main.Ticked;
v.Position = v.MainVehicle.Position;
v.Quaternion = v.MainVehicle.Quaternion;
}
private static void HandleNozzleTransform(Packets.NozzleTransform p)
{
@ -168,47 +97,47 @@ namespace RageCoop.Client {
{
// Minigun, not working for some reason
case (uint)WeaponHash.Minigun:
weaponHash=1176362416;
weaponHash = 1176362416;
break;
// Valkyire, not working for some reason
case 2756787765:
weaponHash=1176362416;
weaponHash = 1176362416;
break;
// Tampa3, not working for some reason
case 3670375085:
weaponHash=1176362416;
weaponHash = 1176362416;
break;
// Ruiner2, not working for some reason
case 50118905:
weaponHash=1176362416;
weaponHash = 1176362416;
break;
// SAVAGE
case 1638077257:
weaponHash=(uint)VehicleWeaponHash.PlayerLazer;
weaponHash = (uint)VehicleWeaponHash.PlayerLazer;
break;
case (uint)VehicleWeaponHash.PlayerBuzzard:
weaponHash=1176362416;
break ;
weaponHash = 1176362416;
break;
}
var p = EntityPool.GetPedByID(ownerID)?.MainPed;
if (p == null) { p=Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); }
if (p == null) { return; /* p = Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); */ }
if (!CorePFXAsset.IsLoaded) { CorePFXAsset.Request(); }
if (_lastWeaponHash!=weaponHash)
if (_lastWeaponHash != weaponHash)
{
_weaponAsset.MarkAsNoLongerNeeded();
_weaponAsset=new WeaponAsset(weaponHash);
_lastWeaponHash=weaponHash;
_weaponAsset = new WeaponAsset(weaponHash);
_lastWeaponHash = weaponHash;
}
if (!_weaponAsset.IsLoaded) { _weaponAsset.Request(); }
World.ShootBullet(start, end, p, _weaponAsset, (int)p.GetWeaponDamage(weaponHash));
World.ShootSingleBullet(start, end, (int)p.GetWeaponDamage(weaponHash), _weaponAsset, p);
Prop w;
if(((w = p.Weapons.CurrentWeaponObject) != null)&&(p.VehicleWeapon==VehicleWeaponHash.Invalid))
if (((w = p.Weapons.CurrentWeaponObject) != null) && (p.VehicleWeapon == VehicleWeaponHash.Invalid))
{
if (p.Weapons.Current.Components.GetSuppressorComponent().Active)
{
@ -216,74 +145,53 @@ namespace RageCoop.Client {
}
else
{
World.CreateParticleEffectNonLooped(CorePFXAsset, "muz_assault_rifle", p.GetMuzzlePosition(), w.Rotation, 1);
}
}
else if (p.VehicleWeapon!=VehicleWeaponHash.Invalid)
{
if (p.VehicleWeapon==VehicleWeaponHash.Tank)
{
World.CreateParticleEffectNonLooped(CorePFXAsset, "muz_tank", p.CurrentVehicle.GetMuzzleInfo().Position, p.CurrentVehicle.Bones[35].ForwardVector.ToEulerRotation(p.CurrentVehicle.Bones[35].UpVector), 1);
World.CreateParticleEffectNonLooped(CorePFXAsset, WeaponUtil.GetFlashFX((WeaponHash)weaponHash), p.GetMuzzlePosition(), w.Rotation, 1);
}
}
}
public static void HandleEvent(PacketType type,byte[] data)
public static void HandleVehicleBulletShot(Packets.VehicleBulletShot p)
{
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
var v = EntityPool.GetPedByID(p.OwnerID)?.MainPed.CurrentVehicle;
if (v == null) { return; }
var b = v.Bones[p.Bone];
World.CreateParticleEffectNonLooped(CorePFXAsset,
WeaponUtil.GetFlashFX((WeaponHash)p.WeaponHash),
b.Position, b.ForwardVector.ToEulerRotation(v.Bones[35].UpVector), 1);
}
public static void HandleEvent(PacketType type, NetIncomingMessage msg)
{
switch (type)
{
case PacketType.BulletShot:
{
Packets.BulletShot p = new Packets.BulletShot();
p.Unpack(data);
p.Deserialize(msg);
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
break;
}
case PacketType.EnteringVehicle:
case PacketType.VehicleBulletShot:
{
Packets.EnteringVehicle p = new Packets.EnteringVehicle();
p.Unpack(data);
HandleEnteringVehicle(EntityPool.GetPedByID(p.PedID), EntityPool.GetVehicleByID(p.VehicleID), (VehicleSeat)p.VehicleSeat);
HandleVehicleBulletShot(msg.GetPacket<Packets.VehicleBulletShot>());
break;
}
break;
case PacketType.LeaveVehicle:
{
Packets.LeaveVehicle packet = new Packets.LeaveVehicle();
packet.Unpack(data);
HandleLeaveVehicle(packet);
}
break;
case PacketType.OwnerChanged:
{
Packets.OwnerChanged packet = new Packets.OwnerChanged();
packet.Unpack(data);
HandleOwnerChanged(packet);
HandleOwnerChanged(msg.GetPacket<Packets.OwnerChanged>());
}
break;
case PacketType.PedKilled:
{
var packet = new Packets.PedKilled();
packet.Unpack(data);
HandlePedKilled(packet);
HandlePedKilled(msg.GetPacket<Packets.PedKilled>());
}
break;
case PacketType.EnteredVehicle:
{
var packet = new Packets.EnteredVehicle();
packet.Unpack(data);
HandleEnteredVehicle(packet.PedID,packet.VehicleID,(VehicleSeat)packet.VehicleSeat);
break;
}
case PacketType.NozzleTransform:
{
var packet = new Packets.NozzleTransform();
packet.Unpack(data);
HandleNozzleTransform(packet);
HandleNozzleTransform(msg.GetPacket<Packets.NozzleTransform>());
break;
}
}
Networking.Peer.Recycle(msg);
}
#endregion
@ -304,108 +212,76 @@ namespace RageCoop.Client {
Func<bool> getBulletImpact = (() =>
{
Vector3 endPos = subject.LastWeaponImpactPosition;
if (endPos==default)
if (endPos == default)
{
if (i>5)
{
endPos=subject.GetAimCoord();
if (subject.IsInVehicle() && subject.VehicleWeapon!=VehicleWeaponHash.Invalid)
{
if (subject.IsOnTurretSeat())
{
TriggerBulletShot((uint)subject.VehicleWeapon, subject.GetSyncEntity(), endPos);
}
else
{
TriggerVehBulletShot((uint)subject.VehicleWeapon, subject.CurrentVehicle,c);
}
}
else
{
TriggerBulletShot((uint)subject.Weapons.Current.Hash, subject.GetSyncEntity(), endPos);
}
return true;
}
i++;
return false;
}
else
{
if (subject.IsInVehicle() && subject.VehicleWeapon!=VehicleWeaponHash.Invalid)
if (++i <= 5) { return false; }
endPos = subject.GetAimCoord();
if (subject.IsInVehicle() && subject.VehicleWeapon != VehicleWeaponHash.Invalid)
{
if (subject.IsOnTurretSeat())
{
TriggerBulletShot((uint)subject.VehicleWeapon, subject.GetSyncEntity(), endPos);
TriggerBulletShot((uint)subject.VehicleWeapon, c, endPos);
}
else
{
TriggerVehBulletShot((uint)subject.VehicleWeapon, subject.CurrentVehicle,c);
TriggerVehBulletShot((uint)subject.VehicleWeapon, subject.CurrentVehicle, c);
}
}
else
{
TriggerBulletShot((uint)subject.Weapons.Current.Hash, subject.GetSyncEntity(), endPos);
TriggerBulletShot((uint)subject.Weapons.Current.Hash, c, endPos);
}
return true;
}
if (subject.IsInVehicle() && subject.VehicleWeapon != VehicleWeaponHash.Invalid)
{
if (subject.IsOnTurretSeat())
{
TriggerBulletShot((uint)subject.VehicleWeapon, c, endPos);
}
else
{
TriggerVehBulletShot((uint)subject.VehicleWeapon, subject.CurrentVehicle, c);
}
}
else
{
TriggerBulletShot((uint)subject.Weapons.Current.Hash, c, endPos);
}
return true;
});
if (!getBulletImpact())
{
Main.QueueAction(getBulletImpact);
}
}
else if (subject.VehicleWeapon==VehicleWeaponHash.Tank && subject.LastWeaponImpactPosition!=default)
else if (subject.VehicleWeapon == VehicleWeaponHash.Tank && subject.LastWeaponImpactPosition != default)
{
TriggerBulletShot((uint)VehicleWeaponHash.Tank, subject.GetSyncEntity(),subject.LastWeaponImpactPosition);
}
}
// Vehicles
var g = subject.IsGettingIntoVehicle;
if ( g && (!c._lastEnteringVehicle))
{
var v = subject.VehicleTryingToEnter.GetSyncEntity();
TriggerEnteringVehicle(c, v, subject.GetSeatTryingToEnter());
}
var currentSitting= subject.IsSittingInVehicle();
if (c._lastSittingInVehicle)
{
if (!currentSitting)
{
var veh = subject.CurrentVehicle;
if (veh!=null)
{
var v = veh.GetSyncEntity();
TriggerLeaveVehicle(c.ID);
}
TriggerBulletShot((uint)VehicleWeaponHash.Tank, c, subject.LastWeaponImpactPosition);
}
}
else if (currentSitting)
{
TriggerEnteredVehicle(c, subject.CurrentVehicle.GetSyncEntity(), subject.SeatIndex);
}
c._lastSittingInVehicle=currentSitting;
c._lastEnteringVehicle=g;
}
public static void Check(SyncedVehicle v)
{
if (v.MainVehicle!=null&&v.MainVehicle.HasNozzle())
if (v.MainVehicle == null || !v.MainVehicle.HasNozzle())
{
if((v.LastNozzleAngle==1) && (v.MainVehicle.GetNozzleAngel()!=1))
{
TriggerNozzleTransform(v.ID,false);
}
else if((v.LastNozzleAngle==0) && (v.MainVehicle.GetNozzleAngel()!=0))
{
TriggerNozzleTransform(v.ID,true);
}
v.LastNozzleAngle=v.MainVehicle.GetNozzleAngel();
return;
}
if ((v.LastNozzleAngle == 1) && (v.MainVehicle.GetNozzleAngel() != 1))
{
TriggerNozzleTransform(v.ID, false);
}
else if ((v.LastNozzleAngle == 0) && (v.MainVehicle.GetNozzleAngel() != 0))
{
TriggerNozzleTransform(v.ID, true);
}
v.LastNozzleAngle = v.MainVehicle.GetNozzleAngel();
}
#endregion
}

View File

@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RageCoop.Client
{
internal class SyncParameters
{
public static float PositioinPredictionDefault = 0.01f;
}
}

View File

@ -0,0 +1,93 @@
using NAudio.Wave;
using System.Threading;
namespace RageCoop.Client
{
internal static class Voice
{
private static WaveInEvent _waveIn;
private static readonly BufferedWaveProvider _waveProvider = new BufferedWaveProvider(new WaveFormat(16000, 16, 1));
private static Thread _thread;
public static bool WasInitialized() => _thread != null;
public static bool IsRecording() => _waveIn != null;
public static void ClearAll()
{
_waveProvider.ClearBuffer();
StopRecording();
if (_thread != null && _thread.IsAlive)
{
_thread.Abort();
_thread = null;
}
}
public static void StopRecording()
{
if (!IsRecording())
return;
_waveIn.StopRecording();
_waveIn.Dispose();
_waveIn = null;
}
public static void Init()
{
if (WasInitialized())
return;
// I tried without thread but the game will lag without
_thread = new Thread(new ThreadStart(() =>
{
while (true)
{
using (var wo = new WaveOutEvent())
{
wo.Init(_waveProvider);
wo.Play();
while (wo.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(100);
}
}
}
}));
_thread.Start();
}
public static void StartRecording()
{
if (IsRecording())
return;
_waveIn = new WaveInEvent
{
DeviceNumber = 0,
BufferMilliseconds = 20,
NumberOfBuffers = 1,
WaveFormat = _waveProvider.WaveFormat
};
_waveIn.DataAvailable += WaveInDataAvailable;
_waveIn.StartRecording();
}
public static void AddVoiceData(byte[] buffer, int recorded)
{
_waveProvider.AddSamples(buffer, 0, recorded);
}
private static void WaveInDataAvailable(object sender, WaveInEventArgs e)
{
if (!IsRecording())
return;
Networking.SendVoiceMessage(e.Buffer, e.BytesRecorded);
}
}
}

View File

@ -0,0 +1,64 @@
using GTA;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RageCoop.Client
{
/// <summary>
/// Class providing support for addon mods
/// </summary>
internal class AddOnDataProvider
{
public static int GetMuzzleIndex(Model model)
{
switch (model.Hash)
{
// f14a2
case -848721350:
return 48;
// f15e
case 881261972:
return 32;
// f16c
case -2051171080:
return 25;
// F22A
case 2061630439:
return 14;
// f35c
case -343547392:
return 44;
// mig29a
case 513887552:
return 18;
// su30sm
case -733985185:
return 34;
// su33
case -722216722:
return 34;
// su35s
case -268602544:
return 28;
// su57
case 1490050781:
return 21;
default:
return -1;
}
}
}
}

View File

@ -0,0 +1,103 @@

using GTA;
using GTA.Math;
using RageCoop.Core;
using SHVDN;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace RageCoop.Client
{
internal unsafe class MemPatch
{
private readonly byte[] _data;
private readonly byte[] _orginal;
private readonly IntPtr _address;
public MemPatch(byte* address, byte[] data)
{
_data = data;
_orginal = new byte[data.Length];
_address = (IntPtr)address;
Marshal.Copy((IntPtr)address, _orginal, 0, data.Length);
}
public void Install()
{
Marshal.Copy(_data, 0, _address, _data.Length);
}
public void Uninstall()
{
Marshal.Copy(_orginal, 0, _address, _orginal.Length);
}
}
internal static unsafe class Memory
{
public static MemPatch VignettingPatch;
public static MemPatch VignettingCallPatch;
public static MemPatch TimeScalePatch;
static Memory()
{
// Weapon/radio wheel slow-mo patch
// Thanks @CamxxCore, https://github.com/CamxxCore/GTAVWeaponWheelMod
var result = MemScanner.FindPatternBmh("\x38\x51\x64\x74\x19", "xxxxx");
if (result == null) { throw new NotSupportedException("Can't find memory pattern to patch weapon/radio slow-mo"); }
var address = result + 26;
address = address + *(int*)address + 4u;
VignettingPatch = new MemPatch(address, new byte[] { RET, 0x90, 0x90, 0x90, 0x90 });
VignettingCallPatch = new MemPatch(result + 8, new byte[] { 0x90, 0x90, 0x90, 0x90, 0x90 });
TimeScalePatch = new MemPatch(result + 34, new byte[] { XOR_32_64, 0xD2 });
}
public static void ApplyPatches()
{
VignettingPatch.Install();
VignettingCallPatch.Install();
TimeScalePatch.Install();
}
public static void RestorePatches()
{
VignettingPatch.Uninstall();
VignettingCallPatch.Uninstall();
TimeScalePatch.Uninstall();
}
#region PATCHES
#endregion
#region OFFSET-CONST
public const int PositionOffset = 144;
public const int VelocityOffset = 800;
public const int MatrixOffset = 96;
#endregion
#region OPCODE
private const byte XOR_32_64 = 0x31;
private const byte RET = 0xC3;
#endregion
public static Vector3 ReadPosition(this Entity e) => ReadVector3(e.MemoryAddress + PositionOffset);
public static Quaternion ReadQuaternion(this Entity e) => Quaternion.RotationMatrix(e.Matrix);
public static Vector3 ReadRotation(this Entity e) => e.ReadQuaternion().ToEulerDegrees();
public static Vector3 ReadVelocity(this Ped e) => ReadVector3(e.MemoryAddress + VelocityOffset);
public static Vector3 ReadVector3(IntPtr address)
{
float* ptr = (float*)address.ToPointer();
return new Vector3()
{
X = *ptr,
Y = ptr[1],
Z = ptr[2]
};
}
public static List<int> FindOffset(float toSearch, IntPtr start, int range = 1000, float tolerance = 0.01f)
{
var foundOffsets = new List<int>(100);
for (int i = 0; i <= range; i++)
{
var val = MemDataMarshal.ReadFloat(start + i);
if (Math.Abs(val - toSearch) < tolerance)
{
foundOffsets.Add(i);
}
}
return foundOffsets;
}
}
}

View File

@ -0,0 +1,145 @@
using GTA.Math;
using GTA.Native;
using System;
using System.Runtime.InteropServices;
namespace RageCoop.Client
{
[StructLayout(LayoutKind.Explicit, Size = 80)]
public struct HeadBlendData
{
[FieldOffset(0)]
public int ShapeFirst;
[FieldOffset(8)]
public int ShapeSecond;
[FieldOffset(16)]
public int ShapeThird;
[FieldOffset(24)]
public int SkinFirst;
[FieldOffset(32)]
public int SkinSecond;
[FieldOffset(40)]
public int SkinThird;
[FieldOffset(48)]
public float ShapeMix;
[FieldOffset(56)]
public float SkinMix;
[FieldOffset(64)]
public float ThirdMix;
}
[StructLayout(LayoutKind.Explicit, Size = 24)]
public struct NativeVector3
{
[FieldOffset(0)]
public float X;
[FieldOffset(8)]
public float Y;
[FieldOffset(16)]
public float Z;
public static implicit operator Vector3(NativeVector3 vec)
{
return new Vector3() { X = vec.X, Y = vec.Y, Z = vec.Z };
}
public static implicit operator NativeVector3(Vector3 vec)
{
return new NativeVector3() { X = vec.X, Y = vec.Y, Z = vec.Z };
}
}
public static class NativeCaller
{
// These are borrowed from ScriptHookVDotNet's
[DllImport("ScriptHookV.dll", ExactSpelling = true, EntryPoint = "?nativeInit@@YAX_K@Z")]
private static extern void NativeInit(ulong hash);
[DllImport("ScriptHookV.dll", ExactSpelling = true, EntryPoint = "?nativePush64@@YAX_K@Z")]
private static extern void NativePush64(ulong val);
[DllImport("ScriptHookV.dll", ExactSpelling = true, EntryPoint = "?nativeCall@@YAPEA_KXZ")]
private static extern unsafe ulong* NativeCall();
// These are from ScriptHookV's nativeCaller.h
private static unsafe void NativePush<T>(T val) where T : unmanaged
{
ulong val64 = 0;
*(T*)(&val64) = val;
NativePush64(val64);
}
public static unsafe R Invoke<R>(ulong hash) where R : unmanaged
{
NativeInit(hash);
return *(R*)(NativeCall());
}
public static unsafe R Invoke<R>(Hash hash, params object[] args)
where R : unmanaged
{
NativeInit((ulong)hash);
var arguments = ConvertPrimitiveArguments(args);
foreach (var arg in arguments)
NativePush(arg);
return *(R*)(NativeCall());
}
/// <summary>
/// Helper function that converts an array of primitive values to a native stack.
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private static unsafe ulong[] ConvertPrimitiveArguments(object[] args)
{
var result = new ulong[args.Length];
for (int i = 0; i < args.Length; ++i)
{
if (args[i] is bool valueBool)
{
result[i] = valueBool ? 1ul : 0ul;
continue;
}
if (args[i] is byte valueByte)
{
result[i] = valueByte;
continue;
}
if (args[i] is int valueInt32)
{
result[i] = (ulong)valueInt32;
continue;
}
if (args[i] is ulong valueUInt64)
{
result[i] = valueUInt64;
continue;
}
if (args[i] is float valueFloat)
{
result[i] = *(ulong*)&valueFloat;
continue;
}
if (args[i] is IntPtr valueIntPtr)
{
result[i] = (ulong)valueIntPtr.ToInt64();
continue;
}
throw new ArgumentException("Unknown primitive type in native argument list", nameof(args));
}
return result;
}
}
}

View File

@ -1,471 +1,465 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RageCoop.Client
namespace RageCoop.Client
{
// Potential names and hash collisions included as comments
internal enum PedConfigFlags
{
_0x67D1A445 = 0,
_0xC63DE95E = 1,
CPED_CONFIG_FLAG_NoCriticalHits = 2,
CPED_CONFIG_FLAG_DrownsInWater = 3,
CPED_CONFIG_FLAG_DisableReticuleFixedLockon = 4,
_0x37D196F4 = 5,
_0xE2462399 = 6,
CPED_CONFIG_FLAG_UpperBodyDamageAnimsOnly = 7,
_0xEDDEB838 = 8,
_0xB398B6FD = 9,
_0xF6664E68 = 10,
_0xA05E7CA3 = 11,
_0xCE394045 = 12,
CPED_CONFIG_FLAG_NeverLeavesGroup = 13,
_0xCD8D1411 = 14,
_0xB031F1A9 = 15,
_0xFE65BEE3 = 16,
CPED_CONFIG_FLAG_BlockNonTemporaryEvents = 17,
_0x380165BD = 18,
_0x07C045C7 = 19,
_0x583B5E2D = 20,
_0x475EDA58 = 21,
_0x8629D05B = 22,
_0x1522968B = 23,
CPED_CONFIG_FLAG_IgnoreSeenMelee = 24,
_0x4CC09C4B = 25,
_0x034F3053 = 26,
_0xD91BA7CC = 27,
_0x5C8DC66E = 28,
_0x8902EAA0 = 29,
_0x6580B9D2 = 30,
_0x0EF7A297 = 31,
_0x6BF86E5B = 32,
CPED_CONFIG_FLAG_DieWhenRagdoll = 33,
CPED_CONFIG_FLAG_HasHelmet = 34,
CPED_CONFIG_FLAG_UseHelmet = 35,
_0xEEB3D630 = 36,
_0xB130D17B = 37,
_0x5F071200 = 38,
CPED_CONFIG_FLAG_DisableEvasiveDives = 39,
_0xC287AAFF = 40,
_0x203328CC = 41,
CPED_CONFIG_FLAG_DontInfluenceWantedLevel = 42,
CPED_CONFIG_FLAG_DisablePlayerLockon = 43,
CPED_CONFIG_FLAG_DisableLockonToRandomPeds = 44,
_0xEC4A8ACF = 45,
_0xDB115BFA = 46,
CPED_CONFIG_FLAG_PedBeingDeleted = 47,
CPED_CONFIG_FLAG_BlockWeaponSwitching = 48,
_0xF8E99565 = 49,
_0xDD17FEE6 = 50,
_0x7ED9B2C9 = 51,
_0x655E8618 = 52,
_0x5A6C1F6E = 53,
_0xD749FC41 = 54,
_0x357F63F3 = 55,
_0xC5E60961 = 56,
_0x29275C3E = 57,
CPED_CONFIG_FLAG_IsFiring = 58,
CPED_CONFIG_FLAG_WasFiring = 59,
CPED_CONFIG_FLAG_IsStanding = 60,
CPED_CONFIG_FLAG_WasStanding = 61,
CPED_CONFIG_FLAG_InVehicle = 62,
CPED_CONFIG_FLAG_OnMount = 63,
CPED_CONFIG_FLAG_AttachedToVehicle = 64,
CPED_CONFIG_FLAG_IsSwimming = 65,
CPED_CONFIG_FLAG_WasSwimming = 66,
CPED_CONFIG_FLAG_IsSkiing = 67,
CPED_CONFIG_FLAG_IsSitting = 68,
CPED_CONFIG_FLAG_KilledByStealth = 69,
CPED_CONFIG_FLAG_KilledByTakedown = 70,
CPED_CONFIG_FLAG_Knockedout = 71,
_0x3E3C4560 = 72,
_0x2994C7B7 = 73,
_0x6D59D275 = 74,
CPED_CONFIG_FLAG_UsingCoverPoint = 75,
CPED_CONFIG_FLAG_IsInTheAir = 76,
_0x2D493FB7 = 77,
CPED_CONFIG_FLAG_IsAimingGun = 78,
_0x14D69875 = 79,
_0x40B05311 = 80,
_0x8B230BC5 = 81,
_0xC74E5842 = 82,
_0x9EA86147 = 83,
_0x674C746C = 84,
_0x3E56A8C2 = 85,
_0xC144A1EF = 86,
_0x0548512D = 87,
_0x31C93909 = 88,
_0xA0269315 = 89,
_0xD4D59D4D = 90,
_0x411D4420 = 91,
_0xDF4AEF0D = 92,
CPED_CONFIG_FLAG_ForcePedLoadCover = 93,
_0x300E4CD3 = 94,
_0xF1C5BF04 = 95,
_0x89C2EF13 = 96,
CPED_CONFIG_FLAG_VaultFromCover = 97,
_0x02A852C8 = 98,
_0x3D9407F1 = 99,
_0x319B4558 = 100,
CPED_CONFIG_FLAG_ForcedAim = 101,
_0xB942D71A = 102,
_0xD26C55A8 = 103,
_0xB89E703B = 104,
CPED_CONFIG_FLAG_ForceReload = 105,
_0xD9E73DA2 = 106,
_0xFF71DC2C = 107,
_0x1E27E8D8 = 108,
_0xF2C53966 = 109,
_0xC4DBE247 = 110,
_0x83C0A4BF = 111,
_0x0E0FAF8C = 112,
_0x26616660 = 113,
_0x43B80B79 = 114,
_0x0D2A9309 = 115,
_0x12C1C983 = 116,
CPED_CONFIG_FLAG_BumpedByPlayer = 117,
_0xE586D504 = 118,
_0x52374204 = 119,
CPED_CONFIG_FLAG_IsHandCuffed = 120,
CPED_CONFIG_FLAG_IsAnkleCuffed = 121,
CPED_CONFIG_FLAG_DisableMelee = 122,
_0xFE714397 = 123,
_0xB3E660BD = 124,
_0x5FED6BFD = 125,
_0xC9D6F66F = 126,
_0x519BC986 = 127,
CPED_CONFIG_FLAG_CanBeAgitated = 128,
_0x9A4B617C = 129, // CPED_CONFIG_FLAG_FaceDirInsult
_0xDAB70E9F = 130,
_0xE569438A = 131,
_0xBBC77D6D = 132,
_0xCB59EF0F = 133,
_0x8C5EA971 = 134,
CPED_CONFIG_FLAG_IsScuba = 135,
CPED_CONFIG_FLAG_WillArrestRatherThanJack = 136,
_0xDCE59B58 = 137,
CPED_CONFIG_FLAG_RidingTrain = 138,
CPED_CONFIG_FLAG_ArrestResult = 139,
CPED_CONFIG_FLAG_CanAttackFriendly = 140,
_0x98A4BE43 = 141,
_0x6901E731 = 142,
_0x9EC9BF6C = 143,
_0x42841A8F = 144,
CPED_CONFIG_FLAG_ShootingAnimFlag = 145,
CPED_CONFIG_FLAG_DisableLadderClimbing = 146,
CPED_CONFIG_FLAG_StairsDetected = 147,
CPED_CONFIG_FLAG_SlopeDetected = 148,
_0x1A15670B = 149,
_0x61786EE5 = 150,
_0xCB9186BD = 151,
_0xF0710152 = 152,
_0x43DFE310 = 153,
_0xC43C624E = 154,
CPED_CONFIG_FLAG_CanPerformArrest = 155,
CPED_CONFIG_FLAG_CanPerformUncuff = 156,
CPED_CONFIG_FLAG_CanBeArrested = 157,
_0xF7960FF5 = 158,
_0x59564113 = 159,
_0x0C6C3099 = 160,
_0x645F927A = 161,
_0xA86549B9 = 162,
_0x8AAF337A = 163,
_0x13BAA6E7 = 164,
_0x5FB9D1F5 = 165,
CPED_CONFIG_FLAG_IsInjured = 166,
_0x6398A20B = 167,
_0xD8072639 = 168,
_0xA05B1845 = 169,
_0x83F6D220 = 170,
_0xD8430331 = 171,
_0x4B547520 = 172,
_0xE66E1406 = 173,
_0x1C4BFE0C = 174,
_0x90008BFA = 175,
_0x07C7A910 = 176,
_0xF15F8191 = 177,
_0xCE4E8BE2 = 178,
_0x1D46E4F2 = 179,
CPED_CONFIG_FLAG_IsInCustody = 180,
_0xE4FD9B3A = 181,
_0x67AE0812 = 182,
CPED_CONFIG_FLAG_IsAgitated = 183,
CPED_CONFIG_FLAG_PreventAutoShuffleToDriversSeat = 184,
_0x7B2D325E = 185,
CPED_CONFIG_FLAG_EnableWeaponBlocking = 186,
CPED_CONFIG_FLAG_HasHurtStarted = 187,
CPED_CONFIG_FLAG_DisableHurt = 188,
CPED_CONFIG_FLAG_PlayerIsWeird = 189,
_0x32FC208B = 190,
_0x0C296E5A = 191,
_0xE63B73EC = 192,
_0x04E9CC80 = 193,
CPED_CONFIG_FLAG_UsingScenario = 194,
CPED_CONFIG_FLAG_VisibleOnScreen = 195,
_0xD88C58A1 = 196,
_0x5A3DCF43 = 197, // CPED_CONFIG_FLAG_AvoidUnderSide
_0xEA02B420 = 198,
_0x3F559CFF = 199,
_0x8C55D029 = 200,
_0x5E6466F6 = 201,
_0xEB5AD706 = 202,
_0x0EDDDDE7 = 203,
_0xA64F7B1D = 204,
_0x48532CBA = 205,
_0xAA25A9E7 = 206,
_0x415B26B9 = 207,
CPED_CONFIG_FLAG_DisableExplosionReactions = 208,
CPED_CONFIG_FLAG_DodgedPlayer = 209,
_0x67405504 = 210,
_0x75DDD68C = 211,
_0x2AD879B4 = 212,
_0x51486F91 = 213,
_0x32F79E21 = 214,
_0xBF099213 = 215,
_0x054AC8E2 = 216,
_0x14E495CC = 217,
_0x3C7DF9DF = 218,
_0x848FFEF2 = 219,
CPED_CONFIG_FLAG_DontEnterLeadersVehicle = 220,
_0x2618E1CF = 221,
_0x84F722FA = 222,
_0xD1B87B1F = 223,
_0x728AA918 = 224,
CPED_CONFIG_FLAG_DisablePotentialToBeWalkedIntoResponse = 225,
CPED_CONFIG_FLAG_DisablePedAvoidance = 226,
_0x59E91185 = 227,
_0x1EA7225F = 228,
CPED_CONFIG_FLAG_DisablePanicInVehicle = 229,
_0x6DCA7D88 = 230,
_0xFC3E572D = 231,
_0x08E9F9CF = 232,
_0x2D3BA52D = 233,
_0xFD2F53EA = 234,
_0x31A1B03B = 235,
CPED_CONFIG_FLAG_IsHoldingProp = 236,
_0x82ED0A66 = 237, // CPED_CONFIG_FLAG_BlocksPathingWhenDead
_0xCE57C9A3 = 238,
_0x26149198 = 239,
_0x1B33B598 = 240,
_0x719B6E87 = 241,
_0x13E8E8E8 = 242,
_0xF29739AE = 243,
_0xABEA8A74 = 244,
_0xB60EA2BA = 245,
_0x536B0950 = 246,
_0x0C754ACA = 247,
CPED_CONFIG_FLAG_DisableVehicleSeatRandomAnimations = 248,
_0x12659168 = 249,
_0x1BDF2F04 = 250,
_0x7728FAA3 = 251,
_0x6A807ED8 = 252,
CPED_CONFIG_FLAG_OnStairs = 253,
_0xE1A2F73F = 254,
_0x5B3697C8 = 255,
_0xF1EB20A9 = 256,
_0x8B7DF407 = 257,
_0x329DCF1A = 258,
_0x8D90DD1B = 259,
_0xB8A292B7 = 260,
_0x8374B087 = 261,
_0x2AF558F0 = 262,
_0x82251455 = 263,
_0x30CF498B = 264,
_0xE1CD50AF = 265,
_0x72E4AE48 = 266,
_0xC2657EA1 = 267,
_0x29FF6030 = 268,
_0x8248A5EC = 269,
CPED_CONFIG_FLAG_OnStairSlope = 270,
_0xA0897933 = 271,
CPED_CONFIG_FLAG_DontBlipCop = 272,
CPED_CONFIG_FLAG_ClimbedShiftedFence = 273,
_0xF7823618 = 274,
_0xDC305CCE = 275, // CPED_CONFIG_FLAG_KillWhenTrapped
CPED_CONFIG_FLAG_EdgeDetected = 276,
_0x92B67896 = 277,
_0xCAD677C9 = 278,
CPED_CONFIG_FLAG_AvoidTearGas = 279,
_0x5276AC7B = 280,
_0x1032692A = 281,
_0xDA23E7F1 = 282,
_0x9139724D = 283,
_0xA1457461 = 284,
_0x4186E095 = 285,
_0xAC68E2EB = 286,
CPED_CONFIG_FLAG_RagdollingOnBoat = 287,
CPED_CONFIG_FLAG_HasBrandishedWeapon = 288,
_0x1B9EE8A1 = 289,
_0xF3F5758C = 290,
_0x2A9307F1 = 291,
_0x7403D216 = 292,
_0xA06A3C6C = 293,
CPED_CONFIG_FLAG_DisableShockingEvents = 294,
_0xF8DA25A5 = 295,
_0x7EF55802 = 296,
_0xB31F1187 = 297,
_0x84315402 = 298,
_0x0FD69867 = 299,
_0xC7829B67 = 300,
CPED_CONFIG_FLAG_DisablePedConstraints = 301,
_0x6D23CF25 = 302,
_0x2ADA871B = 303,
_0x47BC8A58 = 304,
_0xEB692FA5 = 305,
_0x4A133C50 = 306,
_0xC58099C3 = 307,
_0xF3D76D41 = 308,
_0xB0EEE9F2 = 309,
CPED_CONFIG_FLAG_IsInCluster = 310,
_0x0FA153EF = 311,
_0xD73F5CD3 = 312,
_0xD4136C22 = 313,
_0xE404CA6B = 314,
_0xB9597446 = 315,
_0xD5C98277 = 316,
_0xD5060A9C = 317,
_0x3E5F1CBB = 318,
_0xD8BE1D54 = 319,
_0x0B1F191F = 320,
_0xC995167A = 321,
CPED_CONFIG_FLAG_HasHighHeels = 322,
_0x86B01E54 = 323,
_0x3A56FE15 = 324,
_0xC03B736C = 325, // CPED_CONFIG_FLAG_SpawnedAtScenario
_0xBBF47729 = 326,
_0x22B668A8 = 327,
_0x2624D4D4 = 328,
CPED_CONFIG_FLAG_DisableTalkTo = 329,
CPED_CONFIG_FLAG_DontBlip = 330,
CPED_CONFIG_FLAG_IsSwitchingWeapon = 331,
_0x630F55F3 = 332,
_0x150468FD = 333,
_0x914EBD6B = 334,
_0x79AF3B6D = 335,
_0x75C7A632 = 336,
_0x52D530E2 = 337,
_0xDB2A90E0 = 338,
_0x5922763D = 339,
_0x12ADB567 = 340,
_0x105C8518 = 341,
_0x106F703D = 342,
_0xED152C3E = 343,
_0xA0EFE6A8 = 344,
_0xBF348C82 = 345,
_0xCDDFE830 = 346,
_0x7B59BD9B = 347,
_0x0124C788 = 348,
CPED_CONFIG_FLAG_EquipJetpack = 349,
_0x08D361A5 = 350,
_0xE13D1F7C = 351,
_0x40E25FB9 = 352,
_0x930629D9 = 353,
_0xECCF0C7F = 354,
_0xB6E9613B = 355,
_0x490C0478 = 356,
_0xE8865BEA = 357,
_0xF3C34A29 = 358,
CPED_CONFIG_FLAG_IsDuckingInVehicle = 359,
_0xF660E115 = 360,
_0xAB0E6DED = 361,
CPED_CONFIG_FLAG_HasReserveParachute = 362,
CPED_CONFIG_FLAG_UseReserveParachute = 363,
_0x5C5D9CD3 = 364,
_0x8F7701F3 = 365,
_0xBC4436AD = 366,
_0xD7E07D37 = 367,
_0x03C4FD24 = 368,
_0x7675789A = 369,
_0xB7288A88 = 370,
_0xC06B6291 = 371,
_0x95A4A805 = 372,
_0xA8E9A042 = 373,
CPED_CONFIG_FLAG_NeverLeaveTrain = 374,
_0xBAC674B3 = 375,
_0x147F1FFB = 376,
_0x4376DD79 = 377,
_0xCD3DB518 = 378,
_0xFE4BA4B6 = 379,
_0x5DF03A55 = 380,
_0xBCD816CD = 381,
_0xCF02DD69 = 382,
_0xF73AFA2E = 383,
_0x80B9A9D0 = 384,
_0xF601F7EE = 385,
_0xA91350FC = 386,
_0x3AB23B96 = 387,
CPED_CONFIG_FLAG_IsClimbingLadder = 388,
CPED_CONFIG_FLAG_HasBareFeet = 389,
_0xB4B1CD4C = 390,
_0x5459AFB8 = 391,
_0x54F27667 = 392,
_0xC11D3E8F = 393,
_0x5419EB3E = 394,
_0x82D8DBB4 = 395,
_0x33B02D2F = 396,
_0xAE66176D = 397,
_0xA2692593 = 398,
_0x714C7E31 = 399,
_0xEC488AC7 = 400,
_0xAE398504 = 401,
_0xABC58D72 = 402,
_0x5E5B9591 = 403,
_0x6BA1091E = 404,
_0x77840177 = 405,
_0x1C7ACAC4 = 406,
_0x124420E9 = 407,
_0x75A65587 = 408,
_0xDFD2D55B = 409,
_0xBDD39919 = 410,
_0x43DEC267 = 411,
_0xE42B7797 = 412,
CPED_CONFIG_FLAG_IsHolsteringWeapon = 413,
_0x4F8149F5 = 414,
_0xDD9ECA7A = 415,
_0x9E7EF9D2 = 416,
_0x2C6ED942 = 417,
CPED_CONFIG_FLAG_IsSwitchingHelmetVisor = 418,
_0xA488727D = 419,
_0xCFF5F6DE = 420,
_0x6D614599 = 421,
CPED_CONFIG_FLAG_DisableVehicleCombat = 422,
_0xFE401D26 = 423,
CPED_CONFIG_FLAG_FallsLikeAircraft = 424,
_0x2B42AE82 = 425,
_0x7A95734F = 426,
_0xDF4D8617 = 427,
_0x578F1F14 = 428,
CPED_CONFIG_FLAG_DisableStartEngine = 429,
CPED_CONFIG_FLAG_IgnoreBeingOnFire = 430,
_0x153C9500 = 431,
_0xCB7A632E = 432,
_0xDE727981 = 433,
CPED_CONFIG_FLAG_DisableHomingMissileLockon = 434,
_0x12BBB935 = 435,
_0xAD0A1277 = 436,
_0xEA6AA46A = 437,
CPED_CONFIG_FLAG_DisableHelmetArmor = 438,
_0xCB7F3A1E = 439,
_0x50178878 = 440,
_0x051B4F0D = 441,
_0x2FC3DECC = 442,
_0xC0030B0B = 443,
_0xBBDAF1E9 = 444,
_0x944FE59C = 445,
_0x506FBA39 = 446,
_0xDD45FE84 = 447,
_0xE698AE75 = 448,
_0x199633F8 = 449,
CPED_CONFIG_FLAG_PedIsArresting = 450,
CPED_CONFIG_FLAG_IsDecoyPed = 451,
_0x3A251D83 = 452,
_0xA56F6986 = 453,
_0x1D19C622 = 454,
_0xB68D3EAB = 455,
CPED_CONFIG_FLAG_CanBeIncapacitated = 456,
_0x4BD5EBAD = 457,
}
// Potential names and hash collisions included as comments
internal enum PedConfigFlags
{
_0x67D1A445 = 0,
_0xC63DE95E = 1,
CPED_CONFIG_FLAG_NoCriticalHits = 2,
CPED_CONFIG_FLAG_DrownsInWater = 3,
CPED_CONFIG_FLAG_DisableReticuleFixedLockon = 4,
_0x37D196F4 = 5,
_0xE2462399 = 6,
CPED_CONFIG_FLAG_UpperBodyDamageAnimsOnly = 7,
_0xEDDEB838 = 8,
_0xB398B6FD = 9,
_0xF6664E68 = 10,
_0xA05E7CA3 = 11,
_0xCE394045 = 12,
CPED_CONFIG_FLAG_NeverLeavesGroup = 13,
_0xCD8D1411 = 14,
_0xB031F1A9 = 15,
_0xFE65BEE3 = 16,
CPED_CONFIG_FLAG_BlockNonTemporaryEvents = 17,
_0x380165BD = 18,
_0x07C045C7 = 19,
_0x583B5E2D = 20,
_0x475EDA58 = 21,
_0x8629D05B = 22,
_0x1522968B = 23,
CPED_CONFIG_FLAG_IgnoreSeenMelee = 24,
_0x4CC09C4B = 25,
_0x034F3053 = 26,
_0xD91BA7CC = 27,
_0x5C8DC66E = 28,
_0x8902EAA0 = 29,
_0x6580B9D2 = 30,
_0x0EF7A297 = 31,
_0x6BF86E5B = 32,
CPED_CONFIG_FLAG_DieWhenRagdoll = 33,
CPED_CONFIG_FLAG_HasHelmet = 34,
CPED_CONFIG_FLAG_UseHelmet = 35,
_0xEEB3D630 = 36,
_0xB130D17B = 37,
_0x5F071200 = 38,
CPED_CONFIG_FLAG_DisableEvasiveDives = 39,
_0xC287AAFF = 40,
_0x203328CC = 41,
CPED_CONFIG_FLAG_DontInfluenceWantedLevel = 42,
CPED_CONFIG_FLAG_DisablePlayerLockon = 43,
CPED_CONFIG_FLAG_DisableLockonToRandomPeds = 44,
_0xEC4A8ACF = 45,
_0xDB115BFA = 46,
CPED_CONFIG_FLAG_PedBeingDeleted = 47,
CPED_CONFIG_FLAG_BlockWeaponSwitching = 48,
_0xF8E99565 = 49,
_0xDD17FEE6 = 50,
_0x7ED9B2C9 = 51,
_0x655E8618 = 52,
_0x5A6C1F6E = 53,
_0xD749FC41 = 54,
_0x357F63F3 = 55,
_0xC5E60961 = 56,
_0x29275C3E = 57,
CPED_CONFIG_FLAG_IsFiring = 58,
CPED_CONFIG_FLAG_WasFiring = 59,
CPED_CONFIG_FLAG_IsStanding = 60,
CPED_CONFIG_FLAG_WasStanding = 61,
CPED_CONFIG_FLAG_InVehicle = 62,
CPED_CONFIG_FLAG_OnMount = 63,
CPED_CONFIG_FLAG_AttachedToVehicle = 64,
CPED_CONFIG_FLAG_IsSwimming = 65,
CPED_CONFIG_FLAG_WasSwimming = 66,
CPED_CONFIG_FLAG_IsSkiing = 67,
CPED_CONFIG_FLAG_IsSitting = 68,
CPED_CONFIG_FLAG_KilledByStealth = 69,
CPED_CONFIG_FLAG_KilledByTakedown = 70,
CPED_CONFIG_FLAG_Knockedout = 71,
_0x3E3C4560 = 72,
_0x2994C7B7 = 73,
_0x6D59D275 = 74,
CPED_CONFIG_FLAG_UsingCoverPoint = 75,
CPED_CONFIG_FLAG_IsInTheAir = 76,
_0x2D493FB7 = 77,
CPED_CONFIG_FLAG_IsAimingGun = 78,
_0x14D69875 = 79,
_0x40B05311 = 80,
_0x8B230BC5 = 81,
_0xC74E5842 = 82,
_0x9EA86147 = 83,
_0x674C746C = 84,
_0x3E56A8C2 = 85,
_0xC144A1EF = 86,
_0x0548512D = 87,
_0x31C93909 = 88,
_0xA0269315 = 89,
_0xD4D59D4D = 90,
_0x411D4420 = 91,
_0xDF4AEF0D = 92,
CPED_CONFIG_FLAG_ForcePedLoadCover = 93,
_0x300E4CD3 = 94,
_0xF1C5BF04 = 95,
_0x89C2EF13 = 96,
CPED_CONFIG_FLAG_VaultFromCover = 97,
_0x02A852C8 = 98,
_0x3D9407F1 = 99,
_0x319B4558 = 100,
CPED_CONFIG_FLAG_ForcedAim = 101,
_0xB942D71A = 102,
_0xD26C55A8 = 103,
_0xB89E703B = 104,
CPED_CONFIG_FLAG_ForceReload = 105,
_0xD9E73DA2 = 106,
_0xFF71DC2C = 107,
_0x1E27E8D8 = 108,
_0xF2C53966 = 109,
_0xC4DBE247 = 110,
_0x83C0A4BF = 111,
_0x0E0FAF8C = 112,
_0x26616660 = 113,
_0x43B80B79 = 114,
_0x0D2A9309 = 115,
_0x12C1C983 = 116,
CPED_CONFIG_FLAG_BumpedByPlayer = 117,
_0xE586D504 = 118,
_0x52374204 = 119,
CPED_CONFIG_FLAG_IsHandCuffed = 120,
CPED_CONFIG_FLAG_IsAnkleCuffed = 121,
CPED_CONFIG_FLAG_DisableMelee = 122,
_0xFE714397 = 123,
_0xB3E660BD = 124,
_0x5FED6BFD = 125,
_0xC9D6F66F = 126,
_0x519BC986 = 127,
CPED_CONFIG_FLAG_CanBeAgitated = 128,
_0x9A4B617C = 129, // CPED_CONFIG_FLAG_FaceDirInsult
_0xDAB70E9F = 130,
_0xE569438A = 131,
_0xBBC77D6D = 132,
_0xCB59EF0F = 133,
_0x8C5EA971 = 134,
CPED_CONFIG_FLAG_IsScuba = 135,
CPED_CONFIG_FLAG_WillArrestRatherThanJack = 136,
_0xDCE59B58 = 137,
CPED_CONFIG_FLAG_RidingTrain = 138,
CPED_CONFIG_FLAG_ArrestResult = 139,
CPED_CONFIG_FLAG_CanAttackFriendly = 140,
_0x98A4BE43 = 141,
_0x6901E731 = 142,
_0x9EC9BF6C = 143,
_0x42841A8F = 144,
CPED_CONFIG_FLAG_ShootingAnimFlag = 145,
CPED_CONFIG_FLAG_DisableLadderClimbing = 146,
CPED_CONFIG_FLAG_StairsDetected = 147,
CPED_CONFIG_FLAG_SlopeDetected = 148,
_0x1A15670B = 149,
_0x61786EE5 = 150,
_0xCB9186BD = 151,
_0xF0710152 = 152,
_0x43DFE310 = 153,
_0xC43C624E = 154,
CPED_CONFIG_FLAG_CanPerformArrest = 155,
CPED_CONFIG_FLAG_CanPerformUncuff = 156,
CPED_CONFIG_FLAG_CanBeArrested = 157,
_0xF7960FF5 = 158,
_0x59564113 = 159,
_0x0C6C3099 = 160,
_0x645F927A = 161,
_0xA86549B9 = 162,
_0x8AAF337A = 163,
_0x13BAA6E7 = 164,
_0x5FB9D1F5 = 165,
CPED_CONFIG_FLAG_IsInjured = 166,
_0x6398A20B = 167,
_0xD8072639 = 168,
_0xA05B1845 = 169,
_0x83F6D220 = 170,
_0xD8430331 = 171,
_0x4B547520 = 172,
_0xE66E1406 = 173,
_0x1C4BFE0C = 174,
_0x90008BFA = 175,
_0x07C7A910 = 176,
_0xF15F8191 = 177,
_0xCE4E8BE2 = 178,
_0x1D46E4F2 = 179,
CPED_CONFIG_FLAG_IsInCustody = 180,
_0xE4FD9B3A = 181,
_0x67AE0812 = 182,
CPED_CONFIG_FLAG_IsAgitated = 183,
CPED_CONFIG_FLAG_PreventAutoShuffleToDriversSeat = 184,
_0x7B2D325E = 185,
CPED_CONFIG_FLAG_EnableWeaponBlocking = 186,
CPED_CONFIG_FLAG_HasHurtStarted = 187,
CPED_CONFIG_FLAG_DisableHurt = 188,
CPED_CONFIG_FLAG_PlayerIsWeird = 189,
_0x32FC208B = 190,
_0x0C296E5A = 191,
_0xE63B73EC = 192,
_0x04E9CC80 = 193,
CPED_CONFIG_FLAG_UsingScenario = 194,
CPED_CONFIG_FLAG_VisibleOnScreen = 195,
_0xD88C58A1 = 196,
_0x5A3DCF43 = 197, // CPED_CONFIG_FLAG_AvoidUnderSide
_0xEA02B420 = 198,
_0x3F559CFF = 199,
_0x8C55D029 = 200,
_0x5E6466F6 = 201,
_0xEB5AD706 = 202,
_0x0EDDDDE7 = 203,
_0xA64F7B1D = 204,
_0x48532CBA = 205,
_0xAA25A9E7 = 206,
_0x415B26B9 = 207,
CPED_CONFIG_FLAG_DisableExplosionReactions = 208,
CPED_CONFIG_FLAG_DodgedPlayer = 209,
_0x67405504 = 210,
_0x75DDD68C = 211,
_0x2AD879B4 = 212,
_0x51486F91 = 213,
_0x32F79E21 = 214,
_0xBF099213 = 215,
_0x054AC8E2 = 216,
_0x14E495CC = 217,
_0x3C7DF9DF = 218,
_0x848FFEF2 = 219,
CPED_CONFIG_FLAG_DontEnterLeadersVehicle = 220,
_0x2618E1CF = 221,
_0x84F722FA = 222,
_0xD1B87B1F = 223,
_0x728AA918 = 224,
CPED_CONFIG_FLAG_DisablePotentialToBeWalkedIntoResponse = 225,
CPED_CONFIG_FLAG_DisablePedAvoidance = 226,
_0x59E91185 = 227,
_0x1EA7225F = 228,
CPED_CONFIG_FLAG_DisablePanicInVehicle = 229,
_0x6DCA7D88 = 230,
_0xFC3E572D = 231,
_0x08E9F9CF = 232,
_0x2D3BA52D = 233,
_0xFD2F53EA = 234,
_0x31A1B03B = 235,
CPED_CONFIG_FLAG_IsHoldingProp = 236,
_0x82ED0A66 = 237, // CPED_CONFIG_FLAG_BlocksPathingWhenDead
_0xCE57C9A3 = 238,
_0x26149198 = 239,
_0x1B33B598 = 240,
_0x719B6E87 = 241,
_0x13E8E8E8 = 242,
_0xF29739AE = 243,
_0xABEA8A74 = 244,
_0xB60EA2BA = 245,
_0x536B0950 = 246,
_0x0C754ACA = 247,
CPED_CONFIG_FLAG_DisableVehicleSeatRandomAnimations = 248,
_0x12659168 = 249,
_0x1BDF2F04 = 250,
_0x7728FAA3 = 251,
_0x6A807ED8 = 252,
CPED_CONFIG_FLAG_OnStairs = 253,
_0xE1A2F73F = 254,
_0x5B3697C8 = 255,
_0xF1EB20A9 = 256,
_0x8B7DF407 = 257,
_0x329DCF1A = 258,
_0x8D90DD1B = 259,
_0xB8A292B7 = 260,
_0x8374B087 = 261,
_0x2AF558F0 = 262,
_0x82251455 = 263,
_0x30CF498B = 264,
_0xE1CD50AF = 265,
_0x72E4AE48 = 266,
_0xC2657EA1 = 267,
_0x29FF6030 = 268,
_0x8248A5EC = 269,
CPED_CONFIG_FLAG_OnStairSlope = 270,
_0xA0897933 = 271,
CPED_CONFIG_FLAG_DontBlipCop = 272,
CPED_CONFIG_FLAG_ClimbedShiftedFence = 273,
_0xF7823618 = 274,
_0xDC305CCE = 275, // CPED_CONFIG_FLAG_KillWhenTrapped
CPED_CONFIG_FLAG_EdgeDetected = 276,
_0x92B67896 = 277,
_0xCAD677C9 = 278,
CPED_CONFIG_FLAG_AvoidTearGas = 279,
_0x5276AC7B = 280,
_0x1032692A = 281,
_0xDA23E7F1 = 282,
_0x9139724D = 283,
_0xA1457461 = 284,
_0x4186E095 = 285,
_0xAC68E2EB = 286,
CPED_CONFIG_FLAG_RagdollingOnBoat = 287,
CPED_CONFIG_FLAG_HasBrandishedWeapon = 288,
_0x1B9EE8A1 = 289,
_0xF3F5758C = 290,
_0x2A9307F1 = 291,
_0x7403D216 = 292,
_0xA06A3C6C = 293,
CPED_CONFIG_FLAG_DisableShockingEvents = 294,
_0xF8DA25A5 = 295,
_0x7EF55802 = 296,
_0xB31F1187 = 297,
_0x84315402 = 298,
_0x0FD69867 = 299,
_0xC7829B67 = 300,
CPED_CONFIG_FLAG_DisablePedConstraints = 301,
_0x6D23CF25 = 302,
_0x2ADA871B = 303,
_0x47BC8A58 = 304,
_0xEB692FA5 = 305,
_0x4A133C50 = 306,
_0xC58099C3 = 307,
_0xF3D76D41 = 308,
_0xB0EEE9F2 = 309,
CPED_CONFIG_FLAG_IsInCluster = 310,
_0x0FA153EF = 311,
_0xD73F5CD3 = 312,
_0xD4136C22 = 313,
_0xE404CA6B = 314,
_0xB9597446 = 315,
_0xD5C98277 = 316,
_0xD5060A9C = 317,
_0x3E5F1CBB = 318,
_0xD8BE1D54 = 319,
_0x0B1F191F = 320,
_0xC995167A = 321,
CPED_CONFIG_FLAG_HasHighHeels = 322,
_0x86B01E54 = 323,
_0x3A56FE15 = 324,
_0xC03B736C = 325, // CPED_CONFIG_FLAG_SpawnedAtScenario
_0xBBF47729 = 326,
_0x22B668A8 = 327,
_0x2624D4D4 = 328,
CPED_CONFIG_FLAG_DisableTalkTo = 329,
CPED_CONFIG_FLAG_DontBlip = 330,
CPED_CONFIG_FLAG_IsSwitchingWeapon = 331,
_0x630F55F3 = 332,
_0x150468FD = 333,
_0x914EBD6B = 334,
_0x79AF3B6D = 335,
_0x75C7A632 = 336,
_0x52D530E2 = 337,
_0xDB2A90E0 = 338,
_0x5922763D = 339,
_0x12ADB567 = 340,
_0x105C8518 = 341,
_0x106F703D = 342,
_0xED152C3E = 343,
_0xA0EFE6A8 = 344,
_0xBF348C82 = 345,
_0xCDDFE830 = 346,
_0x7B59BD9B = 347,
_0x0124C788 = 348,
CPED_CONFIG_FLAG_EquipJetpack = 349,
_0x08D361A5 = 350,
_0xE13D1F7C = 351,
_0x40E25FB9 = 352,
_0x930629D9 = 353,
_0xECCF0C7F = 354,
_0xB6E9613B = 355,
_0x490C0478 = 356,
_0xE8865BEA = 357,
_0xF3C34A29 = 358,
CPED_CONFIG_FLAG_IsDuckingInVehicle = 359,
_0xF660E115 = 360,
_0xAB0E6DED = 361,
CPED_CONFIG_FLAG_HasReserveParachute = 362,
CPED_CONFIG_FLAG_UseReserveParachute = 363,
_0x5C5D9CD3 = 364,
_0x8F7701F3 = 365,
_0xBC4436AD = 366,
_0xD7E07D37 = 367,
_0x03C4FD24 = 368,
_0x7675789A = 369,
_0xB7288A88 = 370,
_0xC06B6291 = 371,
_0x95A4A805 = 372,
_0xA8E9A042 = 373,
CPED_CONFIG_FLAG_NeverLeaveTrain = 374,
_0xBAC674B3 = 375,
_0x147F1FFB = 376,
_0x4376DD79 = 377,
_0xCD3DB518 = 378,
_0xFE4BA4B6 = 379,
_0x5DF03A55 = 380,
_0xBCD816CD = 381,
_0xCF02DD69 = 382,
_0xF73AFA2E = 383,
_0x80B9A9D0 = 384,
_0xF601F7EE = 385,
_0xA91350FC = 386,
_0x3AB23B96 = 387,
CPED_CONFIG_FLAG_IsClimbingLadder = 388,
CPED_CONFIG_FLAG_HasBareFeet = 389,
_0xB4B1CD4C = 390,
_0x5459AFB8 = 391,
_0x54F27667 = 392,
_0xC11D3E8F = 393,
_0x5419EB3E = 394,
_0x82D8DBB4 = 395,
_0x33B02D2F = 396,
_0xAE66176D = 397,
_0xA2692593 = 398,
_0x714C7E31 = 399,
_0xEC488AC7 = 400,
_0xAE398504 = 401,
_0xABC58D72 = 402,
_0x5E5B9591 = 403,
_0x6BA1091E = 404,
_0x77840177 = 405,
_0x1C7ACAC4 = 406,
_0x124420E9 = 407,
_0x75A65587 = 408,
_0xDFD2D55B = 409,
_0xBDD39919 = 410,
_0x43DEC267 = 411,
_0xE42B7797 = 412,
CPED_CONFIG_FLAG_IsHolsteringWeapon = 413,
_0x4F8149F5 = 414,
_0xDD9ECA7A = 415,
_0x9E7EF9D2 = 416,
_0x2C6ED942 = 417,
CPED_CONFIG_FLAG_IsSwitchingHelmetVisor = 418,
_0xA488727D = 419,
_0xCFF5F6DE = 420,
_0x6D614599 = 421,
CPED_CONFIG_FLAG_DisableVehicleCombat = 422,
_0xFE401D26 = 423,
CPED_CONFIG_FLAG_FallsLikeAircraft = 424,
_0x2B42AE82 = 425,
_0x7A95734F = 426,
_0xDF4D8617 = 427,
_0x578F1F14 = 428,
CPED_CONFIG_FLAG_DisableStartEngine = 429,
CPED_CONFIG_FLAG_IgnoreBeingOnFire = 430,
_0x153C9500 = 431,
_0xCB7A632E = 432,
_0xDE727981 = 433,
CPED_CONFIG_FLAG_DisableHomingMissileLockon = 434,
_0x12BBB935 = 435,
_0xAD0A1277 = 436,
_0xEA6AA46A = 437,
CPED_CONFIG_FLAG_DisableHelmetArmor = 438,
_0xCB7F3A1E = 439,
_0x50178878 = 440,
_0x051B4F0D = 441,
_0x2FC3DECC = 442,
_0xC0030B0B = 443,
_0xBBDAF1E9 = 444,
_0x944FE59C = 445,
_0x506FBA39 = 446,
_0xDD45FE84 = 447,
_0xE698AE75 = 448,
_0x199633F8 = 449,
CPED_CONFIG_FLAG_PedIsArresting = 450,
CPED_CONFIG_FLAG_IsDecoyPed = 451,
_0x3A251D83 = 452,
_0xA56F6986 = 453,
_0x1D19C622 = 454,
_0xB68D3EAB = 455,
CPED_CONFIG_FLAG_CanBeIncapacitated = 456,
_0x4BD5EBAD = 457,
}
}

View File

@ -1,20 +1,15 @@
using System;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RageCoop.Core;
using GTA;
using GTA.Native;
using GTA;
using GTA.Math;
using System.Linq;
using System.Diagnostics;
using GTA.Native;
using RageCoop.Core;
using System;
using System.Collections.Generic;
namespace RageCoop.Client
{
internal static partial class PedExtensions
{
public static bool IsBetween<T>(this T item, T start, T end)
{
return Comparer<T>.Default.Compare(item, start) >= 0 && Comparer<T>.Default.Compare(item, end) <= 0;
@ -42,26 +37,40 @@ namespace RageCoop.Client
return true;
}
#region PED
public static byte GetPedSpeed(this Ped ped)
{
if (ped.IsSprinting)
if (ped.IsSittingInVehicle())
{
return 3;
return 4;
}
if (ped.IsRunning)
if (ped.IsTaskActive(TaskType.CTaskEnterVehicle))
{
return 2;
return 5;
}
if (ped.IsTaskActive(TaskType.CTaskExitVehicle))
{
return 6;
}
if (ped.IsWalking)
{
return 1;
}
if (ped.IsRunning)
{
return 2;
}
if (ped.IsSprinting)
{
return 3;
}
return 0;
}
@ -71,9 +80,9 @@ namespace RageCoop.Client
var result = new byte[36];
for (byte i = 0; i < 12; i++)
{
result[i]=(byte)Function.Call<short>(Hash.GET_PED_DRAWABLE_VARIATION, ped.Handle, i);
result[i+12]=(byte)Function.Call<short>(Hash.GET_PED_TEXTURE_VARIATION, ped.Handle, i);
result[i+24]=(byte)Function.Call<short>(Hash.GET_PED_PALETTE_VARIATION, ped.Handle, i);
result[i] = (byte)Function.Call<short>(Hash.GET_PED_DRAWABLE_VARIATION, ped.Handle, i);
result[i + 12] = (byte)Function.Call<short>(Hash.GET_PED_TEXTURE_VARIATION, ped.Handle, i);
result[i + 24] = (byte)Function.Call<short>(Hash.GET_PED_PALETTE_VARIATION, ped.Handle, i);
}
return result;
}
@ -99,7 +108,7 @@ namespace RageCoop.Client
}
// Fake death
if (ped.IsRagdoll || (ped.Health==1 && ped.IsPlayer))
if (ped.IsRagdoll || (ped.Health == 1 && ped.IsPlayer))
{
flags |= PedDataFlags.IsRagdoll;
}
@ -132,14 +141,32 @@ namespace RageCoop.Client
if (ped.IsInCover || ped.IsGoingIntoCover)
{
flags |=PedDataFlags.IsInCover;
flags |= PedDataFlags.IsInCover;
if (ped.IsInCoverFacingLeft)
{
flags |= PedDataFlags.IsInCover;
}
if (!Function.Call<bool>(Hash.IS_PED_IN_HIGH_COVER, ped))
{
flags |= PedDataFlags.IsInLowCover;
}
if (ped.IsTaskActive(TaskType.CTaskAimGunBlindFire))
{
flags |= PedDataFlags.IsBlindFiring;
}
}
if(Function.Call<bool>(Hash.GET_PED_STEALTH_MOVEMENT, ped))
if (ped.IsInvincible)
{
flags |= PedDataFlags.IsInvincible;
}
if (Function.Call<bool>(Hash.GET_PED_STEALTH_MOVEMENT, ped))
{
flags |= PedDataFlags.IsInStealthMode;
}
return flags;
}
@ -250,7 +277,7 @@ namespace RageCoop.Client
veh,
veh.Bones[text].Index
}));
bool flag2 = (num2 < distanceToignoreDoors) && (num2 < num)&& IsSeatUsableByPed(ped, veh, dictionary[text]);
bool flag2 = (num2 < distanceToignoreDoors) && (num2 < num) && IsSeatUsableByPed(ped, veh, dictionary[text]);
if (flag2)
{
num = num2;
@ -269,7 +296,7 @@ namespace RageCoop.Client
{
result = true;
}
else
else if (veh.GetPedOnSeat(seat) != null)
{
bool isDead = veh.GetPedOnSeat(seat).IsDead;
@ -294,7 +321,7 @@ namespace RageCoop.Client
}
return result;
}
public static bool IsTaskActive(this Ped p,TaskType task)
public static bool IsTaskActive(this Ped p, TaskType task)
{
return Function.Call<bool>(Hash.GET_IS_TASK_ACTIVE, p.Handle, task);
}
@ -304,47 +331,132 @@ namespace RageCoop.Client
var v = p.CurrentVehicle;
// Rhino
if (v!=null && v.Model.Hash==782665360)
if (v != null && v.Model.Hash == 782665360)
{
return v.Bones[35].Position+v.Bones[35].ForwardVector*100;
return v.Bones[35].Position + v.Bones[35].ForwardVector * 100;
}
if (p.IsOnTurretSeat()) { return p.GetLookingCoord(); }
if (weapon!=null)
if (weapon != null)
{
// Not very accurate, but doesn't matter
Vector3 dir = weapon.RightVector;
return weapon.Position+dir*20;
return weapon.Position + dir * 20;
}
return GetLookingCoord(p);
}
public static Vector3 GetLookingCoord(this Ped p)
{
if (p == Main.P && Function.Call<int>(Hash.GET_FOLLOW_PED_CAM_VIEW_MODE) == 4)
{
return RaycastEverything(default);
}
EntityBone b = p.Bones[Bone.FacialForehead];
Vector3 v = b.UpVector.Normalized;
return b.Position+200*v;
}
public static void StayInCover(this Ped p)
{
Function.Call(Hash.TASK_STAY_IN_COVER, p);
return b.Position + 200 * v;
}
public static VehicleSeat GetSeatTryingToEnter(this Ped p)
{
return (VehicleSeat)Function.Call<int>(Hash.GET_SEAT_PED_IS_TRYING_TO_ENTER, p);
}
#endregion
public static Vector3 RaycastEverything(Vector2 screenCoord)
{
Vector3 camPos = GameplayCamera.Position;
Vector3 camRot = GameplayCamera.Rotation;
const float raycastToDist = 100.0f;
const float raycastFromDist = 1f;
Vector3 target3D = ScreenRelToWorld(camPos, camRot, screenCoord);
Vector3 source3D = camPos;
Entity ignoreEntity = Game.Player.Character;
if (Game.Player.Character.IsInVehicle())
{
ignoreEntity = Game.Player.Character.CurrentVehicle;
}
Vector3 dir = target3D - source3D;
dir.Normalize();
RaycastResult raycastResults = World.Raycast(source3D + dir * raycastFromDist,
source3D + dir * raycastToDist,
IntersectFlags.Everything,
ignoreEntity);
if (raycastResults.DidHit)
{
return raycastResults.HitPosition;
}
return camPos + dir * raycastToDist;
}
public static Vector3 ScreenRelToWorld(Vector3 camPos, Vector3 camRot, Vector2 coord)
{
Vector3 camForward = camRot.ToDirection();
Vector3 rotUp = camRot + new Vector3(10, 0, 0);
Vector3 rotDown = camRot + new Vector3(-10, 0, 0);
Vector3 rotLeft = camRot + new Vector3(0, 0, -10);
Vector3 rotRight = camRot + new Vector3(0, 0, 10);
Vector3 camRight = rotRight.ToDirection() - rotLeft.ToDirection();
Vector3 camUp = rotUp.ToDirection() - rotDown.ToDirection();
double rollRad = -camRot.Y.ToRadians();
Vector3 camRightRoll = camRight * (float)Math.Cos(rollRad) - camUp * (float)Math.Sin(rollRad);
Vector3 camUpRoll = camRight * (float)Math.Sin(rollRad) + camUp * (float)Math.Cos(rollRad);
Vector3 point3D = camPos + camForward * 10.0f + camRightRoll + camUpRoll;
if (!WorldToScreenRel(point3D, out Vector2 point2D))
{
return camPos + camForward * 10.0f;
}
Vector3 point3DZero = camPos + camForward * 10.0f;
if (!WorldToScreenRel(point3DZero, out Vector2 point2DZero))
{
return camPos + camForward * 10.0f;
}
const double eps = 0.001;
if (Math.Abs(point2D.X - point2DZero.X) < eps || Math.Abs(point2D.Y - point2DZero.Y) < eps)
{
return camPos + camForward * 10.0f;
}
float scaleX = (coord.X - point2DZero.X) / (point2D.X - point2DZero.X);
float scaleY = (coord.Y - point2DZero.Y) / (point2D.Y - point2DZero.Y);
return camPos + camForward * 10.0f + camRightRoll * scaleX + camUpRoll * scaleY;
}
public static bool WorldToScreenRel(Vector3 worldCoords, out Vector2 screenCoords)
{
OutputArgument num1 = new OutputArgument();
OutputArgument num2 = new OutputArgument();
if (!Function.Call<bool>(Hash.GET_SCREEN_COORD_FROM_WORLD_COORD, worldCoords.X, worldCoords.Y, worldCoords.Z, num1, num2))
{
screenCoords = new Vector2();
return false;
}
screenCoords = new Vector2((num1.GetResult<float>() - 0.5f) * 2, (num2.GetResult<float>() - 0.5f) * 2);
return true;
}
public static void StayInCover(this Ped p)
{
Function.Call(Hash.TASK_STAY_IN_COVER, p);
}
public static bool IsTurretSeat(this Vehicle veh, int seat)
{
if (!Function.Call<bool>(Hash.DOES_VEHICLE_HAVE_WEAPONS, veh.Handle))
@ -364,7 +476,7 @@ namespace RageCoop.Client
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus3;
case 0:
return (VehicleHash)veh.Model.Hash == VehicleHash.Apc
|| (VehicleHash)veh.Model.Hash==VehicleHash.Dune3;
|| (VehicleHash)veh.Model.Hash == VehicleHash.Dune3;
case 1:
return (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie
|| (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie2
@ -393,7 +505,7 @@ namespace RageCoop.Client
}
}
}

View File

@ -3,436 +3,436 @@
// This is up-to-date for b2372
internal enum TaskType
{
CTaskHandsUp = 0,
CTaskClimbLadder = 1,
CTaskExitVehicle = 2,
CTaskCombatRoll = 3,
CTaskAimGunOnFoot = 4,
CTaskMovePlayer = 5,
CTaskPlayerOnFoot = 6,
CTaskWeapon = 8,
CTaskPlayerWeapon = 9,
CTaskPlayerIdles = 10,
CTaskAimGun = 12,
CTaskComplex = 12,
CTaskFSMClone = 12,
CTaskMotionBase = 12,
CTaskMove = 12,
CTaskMoveBase = 12,
CTaskNMBehaviour = 12,
CTaskNavBase = 12,
CTaskScenario = 12,
CTaskSearchBase = 12,
CTaskSearchInVehicleBase = 12,
CTaskShockingEvent = 12,
CTaskTrainBase = 12,
CTaskVehicleFSM = 12,
CTaskVehicleGoTo = 12,
CTaskVehicleMissionBase = 12,
CTaskVehicleTempAction = 12,
CTaskPause = 14,
CTaskDoNothing = 15,
CTaskGetUp = 16,
CTaskGetUpAndStandStill = 17,
CTaskFallOver = 18,
CTaskFallAndGetUp = 19,
CTaskCrawl = 20,
CTaskComplexOnFire = 25,
CTaskDamageElectric = 26,
CTaskTriggerLookAt = 28,
CTaskClearLookAt = 29,
CTaskSetCharDecisionMaker = 30,
CTaskSetPedDefensiveArea = 31,
CTaskUseSequence = 32,
CTaskMoveStandStill = 34,
CTaskComplexControlMovement = 35,
CTaskMoveSequence = 36,
CTaskAmbientClips = 38,
CTaskMoveInAir = 39,
CTaskNetworkClone = 40,
CTaskUseClimbOnRoute = 41,
CTaskUseDropDownOnRoute = 42,
CTaskUseLadderOnRoute = 43,
CTaskSetBlockingOfNonTemporaryEvents = 44,
CTaskForceMotionState = 45,
CTaskSlopeScramble = 46,
CTaskGoToAndClimbLadder = 47,
CTaskClimbLadderFully = 48,
CTaskRappel = 49,
CTaskVault = 50,
CTaskDropDown = 51,
CTaskAffectSecondaryBehaviour = 52,
CTaskAmbientLookAtEvent = 53,
CTaskOpenDoor = 54,
CTaskShovePed = 55,
CTaskSwapWeapon = 56,
CTaskGeneralSweep = 57,
CTaskPolice = 58,
CTaskPoliceOrderResponse = 59,
CTaskPursueCriminal = 60,
CTaskArrestPed = 62,
CTaskArrestPed2 = 63,
CTaskBusted = 64,
CTaskFirePatrol = 65,
CTaskHeliOrderResponse = 66,
CTaskHeliPassengerRappel = 67,
CTaskAmbulancePatrol = 68,
CTaskPoliceWantedResponse = 69,
CTaskSwat = 70,
CTaskSwatWantedResponse = 72,
CTaskSwatOrderResponse = 73,
CTaskSwatGoToStagingArea = 74,
CTaskSwatFollowInLine = 75,
CTaskWitness = 76,
CTaskGangPatrol = 77,
CTaskArmy = 78,
CTaskShockingEventWatch = 80,
CTaskShockingEventGoto = 82,
CTaskShockingEventHurryAway = 83,
CTaskShockingEventReactToAircraft = 84,
CTaskShockingEventReact = 85,
CTaskShockingEventBackAway = 86,
CTaskShockingPoliceInvestigate = 87,
CTaskShockingEventStopAndStare = 88,
CTaskShockingNiceCarPicture = 89,
CTaskShockingEventThreatResponse = 90,
CTaskTakeOffHelmet = 92,
CTaskCarReactToVehicleCollision = 93,
CTaskCarReactToVehicleCollisionGetOut = 95,
CTaskDyingDead = 97,
CTaskWanderingScenario = 100,
CTaskWanderingInRadiusScenario = 101,
CTaskMoveBetweenPointsScenario = 103,
CTaskChatScenario = 104,
CTaskCowerScenario = 106,
CTaskDeadBodyScenario = 107,
CTaskSayAudio = 114,
CTaskWaitForSteppingOut = 116,
CTaskCoupleScenario = 117,
CTaskUseScenario = 118,
CTaskUseVehicleScenario = 119,
CTaskUnalerted = 120,
CTaskStealVehicle = 121,
CTaskReactToPursuit = 122,
CTaskHitWall = 125,
CTaskCower = 126,
CTaskCrouch = 127,
CTaskMelee = 128,
CTaskMoveMeleeMovement = 129,
CTaskMeleeActionResult = 130,
CTaskMeleeUpperbodyAnims = 131,
CTaskMoVEScripted = 133,
CTaskScriptedAnimation = 134,
CTaskSynchronizedScene = 135,
CTaskComplexEvasiveStep = 137,
CTaskWalkRoundCarWhileWandering = 138,
CTaskComplexStuckInAir = 140,
CTaskWalkRoundEntity = 141,
CTaskMoveWalkRoundVehicle = 142,
CTaskReactToGunAimedAt = 144,
CTaskDuckAndCover = 146,
CTaskAggressiveRubberneck = 147,
CTaskInVehicleBasic = 150,
CTaskCarDriveWander = 151,
CTaskLeaveAnyCar = 152,
CTaskComplexGetOffBoat = 153,
CTaskCarSetTempAction = 155,
CTaskBringVehicleToHalt = 156,
CTaskCarDrive = 157,
CTaskPlayerDrive = 159,
CTaskEnterVehicle = 160,
CTaskEnterVehicleAlign = 161,
CTaskOpenVehicleDoorFromOutside = 162,
CTaskEnterVehicleSeat = 163,
CTaskCloseVehicleDoorFromInside = 164,
CTaskInVehicleSeatShuffle = 165,
CTaskExitVehicleSeat = 167,
CTaskCloseVehicleDoorFromOutside = 168,
CTaskControlVehicle = 169,
CTaskMotionInAutomobile = 170,
CTaskMotionOnBicycle = 171,
CTaskMotionOnBicycleController = 172,
CTaskMotionInVehicle = 173,
CTaskMotionInTurret = 174,
CTaskReactToBeingJacked = 175,
CTaskReactToBeingAskedToLeaveVehicle = 176,
CTaskTryToGrabVehicleDoor = 177,
CTaskGetOnTrain = 178,
CTaskGetOffTrain = 179,
CTaskRideTrain = 180,
CTaskMountThrowProjectile = 190,
CTaskGoToCarDoorAndStandStill = 195,
CTaskMoveGoToVehicleDoor = 196,
CTaskSetPedInVehicle = 197,
CTaskSetPedOutOfVehicle = 198,
CTaskVehicleMountedWeapon = 199,
CTaskVehicleGun = 200,
CTaskVehicleProjectile = 201,
CTaskSmashCarWindow = 204,
CTaskMoveGoToPoint = 205,
CTaskMoveAchieveHeading = 206,
CTaskMoveFaceTarget = 207,
CTaskComplexGoToPointAndStandStillTimed = 208,
CTaskMoveGoToPointAndStandStill = 208,
CTaskMoveFollowPointRoute = 209,
CTaskMoveSeekEntity_CEntitySeekPosCalculatorStandard = 210,
CTaskMoveSeekEntity_CEntitySeekPosCalculatorLastNavMeshIntersection = 211,
CTaskMoveSeekEntity_CEntitySeekPosCalculatorLastNavMeshIntersection2 = 212,
CTaskMoveSeekEntity_CEntitySeekPosCalculatorXYOffsetFixed = 213,
CTaskMoveSeekEntity_CEntitySeekPosCalculatorXYOffsetFixed2 = 214,
CTaskExhaustedFlee = 215,
CTaskGrowlAndFlee = 216,
CTaskScenarioFlee = 217,
CTaskSmartFlee = 218,
CTaskFlyAway = 219,
CTaskWalkAway = 220,
CTaskWander = 221,
CTaskWanderInArea = 222,
CTaskFollowLeaderInFormation = 223,
CTaskGoToPointAnyMeans = 224,
CTaskTurnToFaceEntityOrCoord = 225,
CTaskFollowLeaderAnyMeans = 226,
CTaskFlyToPoint = 228,
CTaskFlyingWander = 229,
CTaskGoToPointAiming = 230,
CTaskGoToScenario = 231,
CTaskSeekEntityAiming = 233,
CTaskSlideToCoord = 234,
CTaskSwimmingWander = 235,
CTaskMoveTrackingEntity = 237,
CTaskMoveFollowNavMesh = 238,
CTaskMoveGoToPointOnRoute = 239,
CTaskEscapeBlast = 240,
CTaskMoveWander = 241,
CTaskMoveBeInFormation = 242,
CTaskMoveCrowdAroundLocation = 243,
CTaskMoveCrossRoadAtTrafficLights = 244,
CTaskMoveWaitForTraffic = 245,
CTaskMoveGoToPointStandStillAchieveHeading = 246,
CTaskMoveGetOntoMainNavMesh = 251,
CTaskMoveSlideToCoord = 252,
CTaskMoveGoToPointRelativeToEntityAndStandStill = 253,
CTaskHelicopterStrafe = 254,
CTaskGetOutOfWater = 256,
CTaskMoveFollowEntityOffset = 259,
CTaskFollowWaypointRecording = 261,
CTaskMotionPed = 264,
CTaskMotionPedLowLod = 265,
CTaskHumanLocomotion = 268,
CTaskMotionBasicLocomotionLowLod = 269,
CTaskMotionStrafing = 270,
CTaskMotionTennis = 271,
CTaskMotionAiming = 272,
CTaskBirdLocomotion = 273,
CTaskFlightlessBirdLocomotion = 274,
CTaskFishLocomotion = 278,
CTaskQuadLocomotion = 279,
CTaskMotionDiving = 280,
CTaskMotionSwimming = 281,
CTaskMotionParachuting = 282,
CTaskMotionDrunk = 283,
CTaskRepositionMove = 284,
CTaskMotionAimingTransition = 285,
CTaskThrowProjectile = 286,
CTaskCover = 287,
CTaskMotionInCover = 288,
CTaskAimAndThrowProjectile = 289,
CTaskGun = 290,
CTaskAimFromGround = 291,
CTaskAimGunVehicleDriveBy = 295,
CTaskAimGunScripted = 296,
CTaskReloadGun = 298,
CTaskWeaponBlocked = 299,
CTaskEnterCover = 300,
CTaskExitCover = 301,
CTaskAimGunFromCoverIntro = 302,
CTaskAimGunFromCoverOutro = 303,
CTaskAimGunBlindFire = 304,
CTaskCombatClosestTargetInArea = 307,
CTaskCombatAdditionalTask = 308,
CTaskInCover = 309,
CTaskAimSweep = 313,
CTaskSharkCircle = 319,
CTaskSharkAttack = 320,
CTaskAgitated = 321,
CTaskAgitatedAction = 322,
CTaskConfront = 323,
CTaskIntimidate = 324,
CTaskShove = 325,
CTaskShoved = 326,
CTaskCrouchToggle = 328,
CTaskRevive = 329,
CTaskParachute = 335,
CTaskParachuteObject = 336,
CTaskTakeOffPedVariation = 337,
CTaskCombatSeekCover = 340,
CTaskCombatFlank = 342,
CTaskCombat = 343,
CTaskCombatMounted = 344,
CTaskMoveCircle = 345,
CTaskMoveCombatMounted = 346,
CTaskSearch = 347,
CTaskSearchOnFoot = 348,
CTaskSearchInAutomobile = 349,
CTaskSearchInBoat = 350,
CTaskSearchInHeli = 351,
CTaskThreatResponse = 352,
CTaskInvestigate = 353,
CTaskStandGuardFSM = 354,
CTaskPatrol = 355,
CTaskShootAtTarget = 356,
CTaskSetAndGuardArea = 357,
CTaskStandGuard = 358,
CTaskSeparate = 359,
CTaskStayInCover = 360,
CTaskVehicleCombat = 361,
CTaskVehiclePersuit = 362,
CTaskVehicleChase = 363,
CTaskDraggingToSafety = 364,
CTaskDraggedToSafety = 365,
CTaskVariedAimPose = 366,
CTaskMoveWithinAttackWindow = 367,
CTaskMoveWithinDefensiveArea = 368,
CTaskShootOutTire = 369,
CTaskShellShocked = 370,
CTaskBoatChase = 371,
CTaskBoatCombat = 372,
CTaskBoatStrafe = 373,
CTaskHeliChase = 374,
CTaskHeliCombat = 375,
CTaskSubmarineCombat = 376,
CTaskSubmarineChase = 377,
CTaskPlaneChase = 378,
CTaskTargetUnreachable = 379,
CTaskTargetUnreachableInInterior = 380,
CTaskTargetUnreachableInExterior = 381,
CTaskStealthKill = 382,
CTaskWrithe = 383,
CTaskAdvance = 384,
CTaskCharge = 385,
CTaskMoveToTacticalPoint = 386,
CTaskToHurtTransit = 387,
CTaskAnimatedHitByExplosion = 388,
CTaskNMRelax = 389,
CTaskNMPose = 391,
CTaskNMBrace = 392,
CTaskNMBuoyancy = 393,
CTaskNMInjuredOnGround = 394,
CTaskNMShot = 395,
CTaskNMHighFall = 396,
CTaskNMBalance = 397,
CTaskNMElectrocute = 398,
CTaskNMPrototype = 399,
CTaskNMExplosion = 400,
CTaskNMOnFire = 401,
CTaskNMScriptControl = 402,
CTaskNMJumpRollFromRoadVehicle = 403,
CTaskNMFlinch = 404,
CTaskNMSit = 405,
CTaskNMFallDown = 406,
CTaskBlendFromNM = 407,
CTaskNMControl = 408,
CTaskNMDangle = 409,
CTaskNMGenericAttach = 412,
CTaskNMDraggingToSafety = 414,
CTaskNMThroughWindscreen = 415,
CTaskNMRiverRapids = 416,
CTaskNMSimple = 417,
CTaskRageRagdoll = 418,
CTaskJumpVault = 421,
CTaskJump = 422,
CTaskFall = 423,
CTaskReactAimWeapon = 425,
CTaskChat = 426,
CTaskMobilePhone = 427,
CTaskReactToDeadPed = 428,
CTaskSearchForUnknownThreat = 430,
CTaskBomb = 432,
CTaskDetonator = 433,
CTaskAnimatedAttach = 435,
CTaskCutScene = 441,
CTaskReactToExplosion = 442,
CTaskReactToImminentExplosion = 443,
CTaskDiveToGround = 444,
CTaskReactAndFlee = 445,
CTaskSidestep = 446,
CTaskCallPolice = 447,
CTaskReactInDirection = 448,
CTaskReactToBuddyShot = 449,
CTaskVehicleGoToAutomobileNew = 454,
CTaskVehicleGoToPlane = 455,
CTaskVehicleGoToHelicopter = 456,
CTaskVehicleGoToSubmarine = 457,
CTaskVehicleGoToBoat = 458,
CTaskVehicleGoToPointAutomobile = 459,
CTaskVehicleGoToPointWithAvoidanceAutomobile = 460,
CTaskVehiclePursue = 461,
CTaskVehicleRam = 462,
CTaskVehicleSpinOut = 463,
CTaskVehicleApproach = 464,
CTaskVehicleThreePointTurn = 465,
CTaskVehicleDeadDriver = 466,
CTaskVehicleCruiseNew = 467,
CTaskVehicleCruiseBoat = 468,
CTaskVehicleStop = 469,
CTaskVehiclePullOver = 470,
CTaskVehiclePassengerExit = 471,
CTaskVehicleFlee = 472,
CTaskVehicleFleeAirborne = 473,
CTaskVehicleFleeBoat = 474,
CTaskVehicleFollowRecording = 475,
CTaskVehicleFollow = 476,
CTaskVehicleBlock = 477,
CTaskVehicleBlockCruiseInFront = 478,
CTaskVehicleBlockBrakeInFront = 479,
CTaskVehicleBlockBackAndForth = 478,
CTaskVehicleCrash = 481,
CTaskVehicleLand = 482,
CTaskVehicleLandPlane = 483,
CTaskVehicleHover = 484,
CTaskVehicleAttack = 485,
CTaskVehicleAttackTank = 486,
CTaskVehicleCircle = 487,
CTaskVehiclePoliceBehaviour = 488,
CTaskVehiclePoliceBehaviourHelicopter = 489,
CTaskVehiclePoliceBehaviourBoat = 490,
CTaskVehicleEscort = 491,
CTaskVehicleHeliProtect = 492,
CTaskVehiclePlayerDriveAutomobile = 494,
CTaskVehiclePlayerDriveBike = 495,
CTaskVehiclePlayerDriveBoat = 496,
CTaskVehiclePlayerDriveSubmarine = 497,
CTaskVehiclePlayerDriveSubmarineCar = 498,
CTaskVehiclePlayerDriveAmphibiousAutomobile = 499,
CTaskVehiclePlayerDrivePlane = 500,
CTaskVehiclePlayerDriveHeli = 501,
CTaskVehiclePlayerDriveAutogyro = 502,
CTaskVehiclePlayerDriveDiggerArm = 503,
CTaskVehiclePlayerDriveTrain = 504,
CTaskVehiclePlaneChase = 505,
CTaskVehicleNoDriver = 506,
CTaskVehicleAnimation = 507,
CTaskVehicleConvertibleRoof = 508,
CTaskVehicleParkNew = 509,
CTaskVehicleFollowWaypointRecording = 510,
CTaskVehicleGoToNavmesh = 511,
CTaskVehicleReactToCopSiren = 512,
CTaskVehicleGotoLongRange = 513,
CTaskVehicleWait = 514,
CTaskVehicleReverse = 515,
CTaskVehicleBrake = 516,
CTaskVehicleHandBrake = 517,
CTaskVehicleTurn = 518,
CTaskVehicleGoForward = 519,
CTaskVehicleSwerve = 520,
CTaskVehicleFlyDirection = 521,
CTaskVehicleHeadonCollision = 522,
CTaskVehicleBoostUseSteeringAngle = 523,
CTaskVehicleShotTire = 524,
CTaskVehicleBurnout = 525,
CTaskVehicleRevEngine = 526,
CTaskVehicleSurfaceInSubmarine = 527,
CTaskVehiclePullAlongside = 528,
CTaskVehicleTransformToSubmarine = 529,
CTaskAnimatedFallback = 530
CTaskHandsUp = 0,
CTaskClimbLadder = 1,
CTaskExitVehicle = 2,
CTaskCombatRoll = 3,
CTaskAimGunOnFoot = 4,
CTaskMovePlayer = 5,
CTaskPlayerOnFoot = 6,
CTaskWeapon = 8,
CTaskPlayerWeapon = 9,
CTaskPlayerIdles = 10,
CTaskAimGun = 12,
CTaskComplex = 12,
CTaskFSMClone = 12,
CTaskMotionBase = 12,
CTaskMove = 12,
CTaskMoveBase = 12,
CTaskNMBehaviour = 12,
CTaskNavBase = 12,
CTaskScenario = 12,
CTaskSearchBase = 12,
CTaskSearchInVehicleBase = 12,
CTaskShockingEvent = 12,
CTaskTrainBase = 12,
CTaskVehicleFSM = 12,
CTaskVehicleGoTo = 12,
CTaskVehicleMissionBase = 12,
CTaskVehicleTempAction = 12,
CTaskPause = 14,
CTaskDoNothing = 15,
CTaskGetUp = 16,
CTaskGetUpAndStandStill = 17,
CTaskFallOver = 18,
CTaskFallAndGetUp = 19,
CTaskCrawl = 20,
CTaskComplexOnFire = 25,
CTaskDamageElectric = 26,
CTaskTriggerLookAt = 28,
CTaskClearLookAt = 29,
CTaskSetCharDecisionMaker = 30,
CTaskSetPedDefensiveArea = 31,
CTaskUseSequence = 32,
CTaskMoveStandStill = 34,
CTaskComplexControlMovement = 35,
CTaskMoveSequence = 36,
CTaskAmbientClips = 38,
CTaskMoveInAir = 39,
CTaskNetworkClone = 40,
CTaskUseClimbOnRoute = 41,
CTaskUseDropDownOnRoute = 42,
CTaskUseLadderOnRoute = 43,
CTaskSetBlockingOfNonTemporaryEvents = 44,
CTaskForceMotionState = 45,
CTaskSlopeScramble = 46,
CTaskGoToAndClimbLadder = 47,
CTaskClimbLadderFully = 48,
CTaskRappel = 49,
CTaskVault = 50,
CTaskDropDown = 51,
CTaskAffectSecondaryBehaviour = 52,
CTaskAmbientLookAtEvent = 53,
CTaskOpenDoor = 54,
CTaskShovePed = 55,
CTaskSwapWeapon = 56,
CTaskGeneralSweep = 57,
CTaskPolice = 58,
CTaskPoliceOrderResponse = 59,
CTaskPursueCriminal = 60,
CTaskArrestPed = 62,
CTaskArrestPed2 = 63,
CTaskBusted = 64,
CTaskFirePatrol = 65,
CTaskHeliOrderResponse = 66,
CTaskHeliPassengerRappel = 67,
CTaskAmbulancePatrol = 68,
CTaskPoliceWantedResponse = 69,
CTaskSwat = 70,
CTaskSwatWantedResponse = 72,
CTaskSwatOrderResponse = 73,
CTaskSwatGoToStagingArea = 74,
CTaskSwatFollowInLine = 75,
CTaskWitness = 76,
CTaskGangPatrol = 77,
CTaskArmy = 78,
CTaskShockingEventWatch = 80,
CTaskShockingEventGoto = 82,
CTaskShockingEventHurryAway = 83,
CTaskShockingEventReactToAircraft = 84,
CTaskShockingEventReact = 85,
CTaskShockingEventBackAway = 86,
CTaskShockingPoliceInvestigate = 87,
CTaskShockingEventStopAndStare = 88,
CTaskShockingNiceCarPicture = 89,
CTaskShockingEventThreatResponse = 90,
CTaskTakeOffHelmet = 92,
CTaskCarReactToVehicleCollision = 93,
CTaskCarReactToVehicleCollisionGetOut = 95,
CTaskDyingDead = 97,
CTaskWanderingScenario = 100,
CTaskWanderingInRadiusScenario = 101,
CTaskMoveBetweenPointsScenario = 103,
CTaskChatScenario = 104,
CTaskCowerScenario = 106,
CTaskDeadBodyScenario = 107,
CTaskSayAudio = 114,
CTaskWaitForSteppingOut = 116,
CTaskCoupleScenario = 117,
CTaskUseScenario = 118,
CTaskUseVehicleScenario = 119,
CTaskUnalerted = 120,
CTaskStealVehicle = 121,
CTaskReactToPursuit = 122,
CTaskHitWall = 125,
CTaskCower = 126,
CTaskCrouch = 127,
CTaskMelee = 128,
CTaskMoveMeleeMovement = 129,
CTaskMeleeActionResult = 130,
CTaskMeleeUpperbodyAnims = 131,
CTaskMoVEScripted = 133,
CTaskScriptedAnimation = 134,
CTaskSynchronizedScene = 135,
CTaskComplexEvasiveStep = 137,
CTaskWalkRoundCarWhileWandering = 138,
CTaskComplexStuckInAir = 140,
CTaskWalkRoundEntity = 141,
CTaskMoveWalkRoundVehicle = 142,
CTaskReactToGunAimedAt = 144,
CTaskDuckAndCover = 146,
CTaskAggressiveRubberneck = 147,
CTaskInVehicleBasic = 150,
CTaskCarDriveWander = 151,
CTaskLeaveAnyCar = 152,
CTaskComplexGetOffBoat = 153,
CTaskCarSetTempAction = 155,
CTaskBringVehicleToHalt = 156,
CTaskCarDrive = 157,
CTaskPlayerDrive = 159,
CTaskEnterVehicle = 160,
CTaskEnterVehicleAlign = 161,
CTaskOpenVehicleDoorFromOutside = 162,
CTaskEnterVehicleSeat = 163,
CTaskCloseVehicleDoorFromInside = 164,
CTaskInVehicleSeatShuffle = 165,
CTaskExitVehicleSeat = 167,
CTaskCloseVehicleDoorFromOutside = 168,
CTaskControlVehicle = 169,
CTaskMotionInAutomobile = 170,
CTaskMotionOnBicycle = 171,
CTaskMotionOnBicycleController = 172,
CTaskMotionInVehicle = 173,
CTaskMotionInTurret = 174,
CTaskReactToBeingJacked = 175,
CTaskReactToBeingAskedToLeaveVehicle = 176,
CTaskTryToGrabVehicleDoor = 177,
CTaskGetOnTrain = 178,
CTaskGetOffTrain = 179,
CTaskRideTrain = 180,
CTaskMountThrowProjectile = 190,
CTaskGoToCarDoorAndStandStill = 195,
CTaskMoveGoToVehicleDoor = 196,
CTaskSetPedInVehicle = 197,
CTaskSetPedOutOfVehicle = 198,
CTaskVehicleMountedWeapon = 199,
CTaskVehicleGun = 200,
CTaskVehicleProjectile = 201,
CTaskSmashCarWindow = 204,
CTaskMoveGoToPoint = 205,
CTaskMoveAchieveHeading = 206,
CTaskMoveFaceTarget = 207,
CTaskComplexGoToPointAndStandStillTimed = 208,
CTaskMoveGoToPointAndStandStill = 208,
CTaskMoveFollowPointRoute = 209,
CTaskMoveSeekEntity_CEntitySeekPosCalculatorStandard = 210,
CTaskMoveSeekEntity_CEntitySeekPosCalculatorLastNavMeshIntersection = 211,
CTaskMoveSeekEntity_CEntitySeekPosCalculatorLastNavMeshIntersection2 = 212,
CTaskMoveSeekEntity_CEntitySeekPosCalculatorXYOffsetFixed = 213,
CTaskMoveSeekEntity_CEntitySeekPosCalculatorXYOffsetFixed2 = 214,
CTaskExhaustedFlee = 215,
CTaskGrowlAndFlee = 216,
CTaskScenarioFlee = 217,
CTaskSmartFlee = 218,
CTaskFlyAway = 219,
CTaskWalkAway = 220,
CTaskWander = 221,
CTaskWanderInArea = 222,
CTaskFollowLeaderInFormation = 223,
CTaskGoToPointAnyMeans = 224,
CTaskTurnToFaceEntityOrCoord = 225,
CTaskFollowLeaderAnyMeans = 226,
CTaskFlyToPoint = 228,
CTaskFlyingWander = 229,
CTaskGoToPointAiming = 230,
CTaskGoToScenario = 231,
CTaskSeekEntityAiming = 233,
CTaskSlideToCoord = 234,
CTaskSwimmingWander = 235,
CTaskMoveTrackingEntity = 237,
CTaskMoveFollowNavMesh = 238,
CTaskMoveGoToPointOnRoute = 239,
CTaskEscapeBlast = 240,
CTaskMoveWander = 241,
CTaskMoveBeInFormation = 242,
CTaskMoveCrowdAroundLocation = 243,
CTaskMoveCrossRoadAtTrafficLights = 244,
CTaskMoveWaitForTraffic = 245,
CTaskMoveGoToPointStandStillAchieveHeading = 246,
CTaskMoveGetOntoMainNavMesh = 251,
CTaskMoveSlideToCoord = 252,
CTaskMoveGoToPointRelativeToEntityAndStandStill = 253,
CTaskHelicopterStrafe = 254,
CTaskGetOutOfWater = 256,
CTaskMoveFollowEntityOffset = 259,
CTaskFollowWaypointRecording = 261,
CTaskMotionPed = 264,
CTaskMotionPedLowLod = 265,
CTaskHumanLocomotion = 268,
CTaskMotionBasicLocomotionLowLod = 269,
CTaskMotionStrafing = 270,
CTaskMotionTennis = 271,
CTaskMotionAiming = 272,
CTaskBirdLocomotion = 273,
CTaskFlightlessBirdLocomotion = 274,
CTaskFishLocomotion = 278,
CTaskQuadLocomotion = 279,
CTaskMotionDiving = 280,
CTaskMotionSwimming = 281,
CTaskMotionParachuting = 282,
CTaskMotionDrunk = 283,
CTaskRepositionMove = 284,
CTaskMotionAimingTransition = 285,
CTaskThrowProjectile = 286,
CTaskCover = 287,
CTaskMotionInCover = 288,
CTaskAimAndThrowProjectile = 289,
CTaskGun = 290,
CTaskAimFromGround = 291,
CTaskAimGunVehicleDriveBy = 295,
CTaskAimGunScripted = 296,
CTaskReloadGun = 298,
CTaskWeaponBlocked = 299,
CTaskEnterCover = 300,
CTaskExitCover = 301,
CTaskAimGunFromCoverIntro = 302,
CTaskAimGunFromCoverOutro = 303,
CTaskAimGunBlindFire = 304,
CTaskCombatClosestTargetInArea = 307,
CTaskCombatAdditionalTask = 308,
CTaskInCover = 309,
CTaskAimSweep = 313,
CTaskSharkCircle = 319,
CTaskSharkAttack = 320,
CTaskAgitated = 321,
CTaskAgitatedAction = 322,
CTaskConfront = 323,
CTaskIntimidate = 324,
CTaskShove = 325,
CTaskShoved = 326,
CTaskCrouchToggle = 328,
CTaskRevive = 329,
CTaskParachute = 335,
CTaskParachuteObject = 336,
CTaskTakeOffPedVariation = 337,
CTaskCombatSeekCover = 340,
CTaskCombatFlank = 342,
CTaskCombat = 343,
CTaskCombatMounted = 344,
CTaskMoveCircle = 345,
CTaskMoveCombatMounted = 346,
CTaskSearch = 347,
CTaskSearchOnFoot = 348,
CTaskSearchInAutomobile = 349,
CTaskSearchInBoat = 350,
CTaskSearchInHeli = 351,
CTaskThreatResponse = 352,
CTaskInvestigate = 353,
CTaskStandGuardFSM = 354,
CTaskPatrol = 355,
CTaskShootAtTarget = 356,
CTaskSetAndGuardArea = 357,
CTaskStandGuard = 358,
CTaskSeparate = 359,
CTaskStayInCover = 360,
CTaskVehicleCombat = 361,
CTaskVehiclePersuit = 362,
CTaskVehicleChase = 363,
CTaskDraggingToSafety = 364,
CTaskDraggedToSafety = 365,
CTaskVariedAimPose = 366,
CTaskMoveWithinAttackWindow = 367,
CTaskMoveWithinDefensiveArea = 368,
CTaskShootOutTire = 369,
CTaskShellShocked = 370,
CTaskBoatChase = 371,
CTaskBoatCombat = 372,
CTaskBoatStrafe = 373,
CTaskHeliChase = 374,
CTaskHeliCombat = 375,
CTaskSubmarineCombat = 376,
CTaskSubmarineChase = 377,
CTaskPlaneChase = 378,
CTaskTargetUnreachable = 379,
CTaskTargetUnreachableInInterior = 380,
CTaskTargetUnreachableInExterior = 381,
CTaskStealthKill = 382,
CTaskWrithe = 383,
CTaskAdvance = 384,
CTaskCharge = 385,
CTaskMoveToTacticalPoint = 386,
CTaskToHurtTransit = 387,
CTaskAnimatedHitByExplosion = 388,
CTaskNMRelax = 389,
CTaskNMPose = 391,
CTaskNMBrace = 392,
CTaskNMBuoyancy = 393,
CTaskNMInjuredOnGround = 394,
CTaskNMShot = 395,
CTaskNMHighFall = 396,
CTaskNMBalance = 397,
CTaskNMElectrocute = 398,
CTaskNMPrototype = 399,
CTaskNMExplosion = 400,
CTaskNMOnFire = 401,
CTaskNMScriptControl = 402,
CTaskNMJumpRollFromRoadVehicle = 403,
CTaskNMFlinch = 404,
CTaskNMSit = 405,
CTaskNMFallDown = 406,
CTaskBlendFromNM = 407,
CTaskNMControl = 408,
CTaskNMDangle = 409,
CTaskNMGenericAttach = 412,
CTaskNMDraggingToSafety = 414,
CTaskNMThroughWindscreen = 415,
CTaskNMRiverRapids = 416,
CTaskNMSimple = 417,
CTaskRageRagdoll = 418,
CTaskJumpVault = 421,
CTaskJump = 422,
CTaskFall = 423,
CTaskReactAimWeapon = 425,
CTaskChat = 426,
CTaskMobilePhone = 427,
CTaskReactToDeadPed = 428,
CTaskSearchForUnknownThreat = 430,
CTaskBomb = 432,
CTaskDetonator = 433,
CTaskAnimatedAttach = 435,
CTaskCutScene = 441,
CTaskReactToExplosion = 442,
CTaskReactToImminentExplosion = 443,
CTaskDiveToGround = 444,
CTaskReactAndFlee = 445,
CTaskSidestep = 446,
CTaskCallPolice = 447,
CTaskReactInDirection = 448,
CTaskReactToBuddyShot = 449,
CTaskVehicleGoToAutomobileNew = 454,
CTaskVehicleGoToPlane = 455,
CTaskVehicleGoToHelicopter = 456,
CTaskVehicleGoToSubmarine = 457,
CTaskVehicleGoToBoat = 458,
CTaskVehicleGoToPointAutomobile = 459,
CTaskVehicleGoToPointWithAvoidanceAutomobile = 460,
CTaskVehiclePursue = 461,
CTaskVehicleRam = 462,
CTaskVehicleSpinOut = 463,
CTaskVehicleApproach = 464,
CTaskVehicleThreePointTurn = 465,
CTaskVehicleDeadDriver = 466,
CTaskVehicleCruiseNew = 467,
CTaskVehicleCruiseBoat = 468,
CTaskVehicleStop = 469,
CTaskVehiclePullOver = 470,
CTaskVehiclePassengerExit = 471,
CTaskVehicleFlee = 472,
CTaskVehicleFleeAirborne = 473,
CTaskVehicleFleeBoat = 474,
CTaskVehicleFollowRecording = 475,
CTaskVehicleFollow = 476,
CTaskVehicleBlock = 477,
CTaskVehicleBlockCruiseInFront = 478,
CTaskVehicleBlockBrakeInFront = 479,
CTaskVehicleBlockBackAndForth = 478,
CTaskVehicleCrash = 481,
CTaskVehicleLand = 482,
CTaskVehicleLandPlane = 483,
CTaskVehicleHover = 484,
CTaskVehicleAttack = 485,
CTaskVehicleAttackTank = 486,
CTaskVehicleCircle = 487,
CTaskVehiclePoliceBehaviour = 488,
CTaskVehiclePoliceBehaviourHelicopter = 489,
CTaskVehiclePoliceBehaviourBoat = 490,
CTaskVehicleEscort = 491,
CTaskVehicleHeliProtect = 492,
CTaskVehiclePlayerDriveAutomobile = 494,
CTaskVehiclePlayerDriveBike = 495,
CTaskVehiclePlayerDriveBoat = 496,
CTaskVehiclePlayerDriveSubmarine = 497,
CTaskVehiclePlayerDriveSubmarineCar = 498,
CTaskVehiclePlayerDriveAmphibiousAutomobile = 499,
CTaskVehiclePlayerDrivePlane = 500,
CTaskVehiclePlayerDriveHeli = 501,
CTaskVehiclePlayerDriveAutogyro = 502,
CTaskVehiclePlayerDriveDiggerArm = 503,
CTaskVehiclePlayerDriveTrain = 504,
CTaskVehiclePlaneChase = 505,
CTaskVehicleNoDriver = 506,
CTaskVehicleAnimation = 507,
CTaskVehicleConvertibleRoof = 508,
CTaskVehicleParkNew = 509,
CTaskVehicleFollowWaypointRecording = 510,
CTaskVehicleGoToNavmesh = 511,
CTaskVehicleReactToCopSiren = 512,
CTaskVehicleGotoLongRange = 513,
CTaskVehicleWait = 514,
CTaskVehicleReverse = 515,
CTaskVehicleBrake = 516,
CTaskVehicleHandBrake = 517,
CTaskVehicleTurn = 518,
CTaskVehicleGoForward = 519,
CTaskVehicleSwerve = 520,
CTaskVehicleFlyDirection = 521,
CTaskVehicleHeadonCollision = 522,
CTaskVehicleBoostUseSteeringAngle = 523,
CTaskVehicleShotTire = 524,
CTaskVehicleBurnout = 525,
CTaskVehicleRevEngine = 526,
CTaskVehicleSurfaceInSubmarine = 527,
CTaskVehiclePullAlongside = 528,
CTaskVehicleTransformToSubmarine = 529,
CTaskAnimatedFallback = 530
};

View File

@ -1,45 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using GTA;
using GTA.Math;
using GTA;
using RageCoop.Core;
using GTA.Native;
using RageCoop.Core;
using System;
using System.Drawing;
using System.IO;
using System.Xml.Serialization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Windows.Forms;
using System.Xml.Serialization;
[assembly: InternalsVisibleTo("RageCoop.Client.Installer")]
namespace RageCoop.Client
{
internal static class Util
{
public static SizeF ResolutionMaintainRatio
{
get
{
// Get the game width and height
int screenw = GTA.UI.Screen.Resolution.Width;
int screenh = GTA.UI.Screen.Resolution.Height;
// Calculate the ratio
float ratio = (float)screenw / screenh;
// And the width with that ratio
float width = 1080f * ratio;
// Finally, return a SizeF
return new SizeF(width, 1080f);
}
}
public static bool WorldToScreen(Vector3 pos, ref Point screenPos)
{
float x, y;
unsafe
{
var res = ResolutionMaintainRatio;
if (Function.Call<bool>(Hash.GET_SCREEN_COORD_FROM_WORLD_COORD, pos.X, pos.Y, pos.Z, &x, &y))
{
screenPos = new Point((int)(res.Width * x), (int)(y * 1080));
return true;
}
}
return false;
}
#region -- POINTER --
private static int _steeringAngleOffset { get; set; }
public static unsafe void NativeMemory()
{
IntPtr address;
address = Game.FindPattern("\x74\x0A\xF3\x0F\x11\xB3\x1C\x09\x00\x00\xEB\x25", "xxxxxx????xx");
if (address != IntPtr.Zero)
{
_steeringAngleOffset = *(int*)(address + 6) + 8;
}
// breaks some stuff.
/*
address = Game.FindPattern("\x32\xc0\xf3\x0f\x11\x09", "xxxxxx"); // Weapon / Radio slowdown
if (address != IntPtr.Zero)
{
for (int i = 0; i < 6; i++)
{
*(byte*)(address + i).ToPointer() = 0x90;
}
}
*/
}
public static unsafe void CustomSteeringAngle(this Vehicle veh, float value)
@ -90,12 +110,12 @@ namespace RageCoop.Client
#endregion
public static string SettingsPath= "Scripts\\RageCoop\\Data\\RageCoop.Client.Settings.xml";
public static Settings ReadSettings()
public static string SettingsPath = "Scripts\\RageCoop\\Data\\RageCoop.Client.Settings.xml";
public static Settings ReadSettings(string path = null)
{
path = path ?? SettingsPath;
XmlSerializer ser = new XmlSerializer(typeof(Settings));
string path = SettingsPath;
Directory.CreateDirectory(Directory.GetParent(path).FullName);
Settings settings = null;
@ -103,12 +123,7 @@ namespace RageCoop.Client
{
using (FileStream stream = File.OpenRead(path))
{
settings = (RageCoop.Client.Settings)ser.Deserialize(stream);
}
using (FileStream stream = new FileStream(path, FileMode.Truncate, FileAccess.ReadWrite))
{
ser.Serialize(stream, settings);
settings = (Settings)ser.Deserialize(stream);
}
}
else
@ -121,46 +136,38 @@ namespace RageCoop.Client
return settings;
}
public static void SaveSettings()
public static bool SaveSettings(string path = null, Settings settings = null)
{
try
{
string path = SettingsPath ;
path = path ?? SettingsPath;
settings = settings ?? Main.Settings;
Directory.CreateDirectory(Directory.GetParent(path).FullName);
using (FileStream stream = new FileStream(path, File.Exists(path) ? FileMode.Truncate : FileMode.Create, FileAccess.ReadWrite))
{
XmlSerializer ser = new XmlSerializer(typeof(Settings));
ser.Serialize(stream, Main.Settings);
ser.Serialize(stream, settings);
}
return true;
}
catch (Exception ex)
{
GTA.UI.Notification.Show("Error saving player settings: " + ex.Message);
return false;
// GTA.UI.Notification.Show("Error saving player settings: " + ex.Message);
}
}
public static Vector3 PredictPosition(this Entity e, bool applyDefault = true)
public static Vehicle CreateVehicle(Model model, Vector3 position, float heading = 0f)
{
return e.Position+e.Velocity*((applyDefault ? SyncParameters.PositioinPredictionDefault : 0)+Networking.Latency);
if (!model.IsLoaded) { return null; }
return (Vehicle)Entity.FromHandle(Function.Call<int>(Hash.CREATE_VEHICLE, model.Hash, position.X, position.Y, position.Z, heading, false, false));
}
public static Model ModelRequest(this int hash)
public static Ped CreatePed(Model model, Vector3 position, float heading = 0f)
{
Model model = new Model(hash);
if (!model.IsValid)
{
//GTA.UI.Notification.Show("~y~Not valid!");
return null;
}
if (!model.IsLoaded)
{
return model.Request(1000) ? model : null;
}
return model;
if (!model.IsLoaded) { return null; }
return (Ped)Entity.FromHandle(Function.Call<int>(Hash.CREATE_PED, 26, model.Hash, position.X, position.Y, position.Z, heading, false, false));
}
public static void SetOnFire(this Entity e, bool toggle)
{
@ -173,7 +180,7 @@ namespace RageCoop.Client
Function.Call(Hash.STOP_ENTITY_FIRE, e.Handle);
}
}
public static void SetFrozen(this Entity e,bool toggle)
public static void SetFrozen(this Entity e, bool toggle)
{
Function.Call(Hash.FREEZE_ENTITY_POSITION, e, toggle);
}
@ -182,7 +189,7 @@ namespace RageCoop.Client
{
if (p == null) { return null; }
var c = EntityPool.GetPedByHandle(p.Handle);
if (c==null) { EntityPool.Add(c=new SyncedPed(p)); }
if (c == null) { EntityPool.Add(c = new SyncedPed(p)); }
return c;
}
@ -190,10 +197,14 @@ namespace RageCoop.Client
{
if (veh == null) { return null; }
var v = EntityPool.GetVehicleByHandle(veh.Handle);
if (v==null) { EntityPool.Add(v=new SyncedVehicle(veh)); }
if (v == null) { EntityPool.Add(v = new SyncedVehicle(veh)); }
return v;
}
public static void ApplyForce(this Entity e, int boneIndex, Vector3 direction, Vector3 rotation = default(Vector3), ForceType forceType = ForceType.ExternalImpulse)
{
Function.Call(Hash.APPLY_FORCE_TO_ENTITY, e.Handle, forceType, direction.X, direction.Y, direction.Z, rotation.X, rotation.Y, rotation.Z, boneIndex, false, true, true, false, true);
}
public static byte GetPlayerRadioIndex()
{
return (byte)Function.Call<int>(Hash.GET_PLAYER_RADIO_STATION_INDEX);
@ -202,50 +213,64 @@ namespace RageCoop.Client
{
Function.Call(Hash.SET_RADIO_TO_STATION_INDEX, index);
}
public static byte[] GetHash(this string inputString)
{
using (HashAlgorithm algorithm = SHA256.Create())
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
}
#region WIN32
const UInt32 WM_KEYDOWN = 0x0100;
private const UInt32 WM_KEYDOWN = 0x0100;
public static void Reload()
{
string reloadKey="None";
string reloadKey = "None";
var lines = File.ReadAllLines("ScriptHookVDotNet.ini");
foreach (var l in lines)
{
var ss = l.Split('=');
if(ss.Length > 0 && ss[0]=="ReloadKey")
if (ss.Length > 0 && ss[0] == "ReloadKey")
{
reloadKey = ss[1];
}
}
var lineList = lines.ToList();
if (reloadKey=="None")
if (reloadKey == "None")
{
foreach (var l in lines)
{
var ss = l.Split('=');
if (ss.Length > 0 && ss[0]=="ReloadKey")
ss.ForEach(s => s.Replace(" ", ""));
if (ss.Length > 0 && ss[0] == "ReloadKey")
{
reloadKey = ss[1];
lineList.Remove(l);
}
}
lineList.Add("ReloadKey=Insert");
File.WriteAllLines("ScriptHookVDotNet.ini",lineList.ToArray());
File.WriteAllLines("ScriptHookVDotNet.ini", lineList.ToArray());
GTA.UI.Notification.PostTicker("Reload cannot be performed automatically, please type \"Reload()\" manually in the SHVDN console.", false);
}
Keys key = (Keys)Enum.Parse(typeof(Keys), reloadKey, true);
// Move log file so it doesn't get deleted
Main.Logger.Dispose();
var path = Main.Logger.LogPath + ".last.log";
try
{
if (File.Exists(path)) { File.Delete(path); }
if (File.Exists(Main.Logger.LogPath)) { File.Move(Main.Logger.LogPath, path); }
}
catch (Exception ex)
{
GTA.UI.Notification.PostTicker(ex.Message, false);
}
PostMessage(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle, WM_KEYDOWN, (int)key, 0);
}
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
private static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
[DllImport("kernel32.dll")]
public static extern ulong GetTickCount64();
#endregion
}
}

View File

@ -1,12 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA;
using GTA;
using GTA.Native;
using RageCoop.Core;
using GTA.Math;
using System;
using System.Collections.Generic;
namespace RageCoop.Client
{
@ -14,8 +10,9 @@ namespace RageCoop.Client
{
#region VEHICLE
public static VehicleDataFlags GetVehicleFlags(this Vehicle veh)
public static VehicleDataFlags GetVehicleFlags(this SyncedVehicle v)
{
var veh = v.MainVehicle;
VehicleDataFlags flags = 0;
if (veh.IsEngineRunning)
@ -53,34 +50,59 @@ namespace RageCoop.Client
flags |= VehicleDataFlags.IsHornActive;
}
if (veh.IsSubmarineCar && Function.Call<bool>(Hash._GET_IS_SUBMARINE_VEHICLE_TRANSFORMED, veh.Handle))
if (v.IsSubmarineCar && Function.Call<bool>(Hash.IS_VEHICLE_IN_SUBMARINE_MODE, veh.Handle))
{
flags |= VehicleDataFlags.IsTransformed;
}
if (veh.HasRoof && (veh.RoofState == VehicleRoofState.Opened || veh.RoofState == VehicleRoofState.Opening))
{
flags |= VehicleDataFlags.RoofOpened;
}
if (veh.IsAircraft)
if (v.IsAircraft)
{
flags |= VehicleDataFlags.IsAircraft;
}
if (veh.Model.Hash==1483171323 && veh.IsDeluxoHovering())
if (v.IsDeluxo && veh.IsDeluxoHovering())
{
flags|= VehicleDataFlags.IsDeluxoHovering;
}
if (veh.HasRoof)
{
flags|=VehicleDataFlags.HasRoof;
flags |= VehicleDataFlags.IsDeluxoHovering;
}
if (v.HasRoof)
{
flags |= VehicleDataFlags.HasRoof;
}
if (v.HasRocketBoost && veh.IsRocketBoostActive())
{
flags |= VehicleDataFlags.IsRocketBoostActive;
}
if (v.HasParachute && veh.IsParachuteActive())
{
flags |= VehicleDataFlags.IsParachuteActive;
}
if (veh.IsOnFire)
{
flags |= VehicleDataFlags.IsOnFire;
}
return flags;
}
public static bool IsRocketBoostActive(this Vehicle veh)
{
return Function.Call<bool>(Hash.IS_ROCKET_BOOST_ACTIVE, veh);
}
public static bool IsParachuteActive(this Vehicle veh)
{
return Function.Call<bool>((Hash)0x3DE51E9C80B116CF, veh);
}
public static void SetRocketBoostActive(this Vehicle veh, bool toggle)
{
Function.Call(Hash.SET_ROCKET_BOOST_ACTIVE, veh, toggle);
}
public static void SetParachuteActive(this Vehicle veh, bool toggle)
{
Function.Call((Hash)0x0BFFB028B3DD0A97, veh, toggle);
}
public static Dictionary<int, int> GetVehicleMods(this VehicleModCollection mods)
{
Dictionary<int, int> result = new Dictionary<int, int>();
@ -118,7 +140,6 @@ namespace RageCoop.Client
}
}
// Bursted tires
short burstedTires = 0;
foreach (VehicleWheel wheel in veh.Wheels.GetAllWheels())
@ -139,7 +160,7 @@ namespace RageCoop.Client
RightHeadLightBroken = (byte)(veh.IsRightHeadLightBroken ? 1 : 0)
};
}
public static void SetDamageModel(this Vehicle veh, VehicleDamageModel model, bool leavedoors = true)
{
for (int i = 0; i < 8; i++)
@ -151,16 +172,17 @@ namespace RageCoop.Client
{
door.Break(leavedoors);
}
continue;
}
else if (door.IsBroken)
/*else if (door.IsBroken) // causes break/repair loop in some situations
{
// The vehicle can only fix a door if the vehicle was completely fixed
veh.Repair();
return;
}
}*/
if ((model.OpenedDoors & (byte)(1 << i)) != 0)
{
if ((!door.IsOpen)&&(!door.IsBroken))
if ((!door.IsOpen) && (!door.IsBroken))
{
door.Open();
}
@ -174,10 +196,10 @@ namespace RageCoop.Client
{
veh.Windows[(VehicleWindowIndex)i].Smash();
}
else if (!veh.Windows[(VehicleWindowIndex)i].IsIntact)
/*else if (!veh.Windows[(VehicleWindowIndex)i].IsIntact) // causes smash/repair loop in some situations
{
veh.Windows[(VehicleWindowIndex)i].Repair();
}
}*/
}
foreach (VehicleWheel wheel in veh.Wheels)
@ -204,7 +226,7 @@ namespace RageCoop.Client
{
Dictionary<int, int> ps = new Dictionary<int, int>();
var d = veh.Driver;
if (d!=null&&d.IsSittingInVehicle())
if (d != null && d.IsSittingInVehicle())
{
ps.Add(-1, d.GetSyncEntity().ID);
}
@ -212,32 +234,31 @@ namespace RageCoop.Client
{
if (p.IsSittingInVehicle())
{
ps.Add((int)p.SeatIndex, (int)p.GetSyncEntity().ID);
ps.Add((int)p.SeatIndex, p.GetSyncEntity().ID);
}
}
return ps;
}
public static void SetDeluxoHoverState(this Vehicle deluxo, bool hover)
{
Function.Call(Hash._SET_VEHICLE_HOVER_TRANSFORM_PERCENTAGE, deluxo, hover ? 1f : 0f);
Function.Call(Hash.SET_SPECIAL_FLIGHT_MODE_TARGET_RATIO, deluxo, hover ? 1f : 0f);
}
public static bool IsDeluxoHovering(this Vehicle deluxo)
{
return Math.Abs(deluxo.Bones[27].ForwardVector.GetCosTheta(deluxo.ForwardVector)-1)>0.05;
return Math.Abs(deluxo.Bones[27].ForwardVector.GetCosTheta(deluxo.ForwardVector) - 1) > 0.05;
}
public static void SetDeluxoWingRatio(this Vehicle v, float ratio)
{
Function.Call(Hash._SET_SPECIALFLIGHT_WING_RATIO, v, ratio);
Function.Call(Hash.SET_HOVER_MODE_WING_RATIO, v, ratio);
}
public static float GetDeluxoWingRatio(this Vehicle v)
{
return v.Bones[99].Position.DistanceTo(v.Bones[92].Position)-1.43f;
return v.Bones[99].Position.DistanceTo(v.Bones[92].Position) - 1.43f;
}
public static float GetNozzleAngel(this Vehicle plane)
{
return Function.Call<float>(Hash._GET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane);
return Function.Call<float>(Hash.GET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane);
}
public static bool HasNozzle(this Vehicle v)
{
@ -267,7 +288,6 @@ namespace RageCoop.Client
{
Function.Call(Hash.SET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane, ratio);
}
#endregion
}
}

View File

@ -1,20 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA;
using GTA.Native;
using GTA;
using GTA.Math;
using GTA.Native;
using System.Collections.Generic;
namespace RageCoop.Client
{
internal class MuzzleInfo
{
public MuzzleInfo(Vector3 pos,Vector3 forward)
public MuzzleInfo(Vector3 pos, Vector3 forward)
{
Position = pos;
ForawardVector=forward;
ForawardVector = forward;
}
public Vector3 Position;
public Vector3 ForawardVector;
@ -41,7 +37,7 @@ namespace RageCoop.Client
public static Vector3 GetMuzzlePosition(this Ped p)
{
var w = p.Weapons.CurrentWeaponObject;
if (w!=null)
if (w != null)
{
var hash = p.Weapons.Current.Hash;
if (MuzzleBoneIndexes.ContainsKey(hash)) { return w.Bones[MuzzleBoneIndexes[hash]].Position; }
@ -49,7 +45,8 @@ namespace RageCoop.Client
}
return p.Bones[Bone.SkelRightHand].Position;
}
static long BulletsShot=0;
private static long BulletsShot = 0;
public static float GetWeaponDamage(this Ped P, uint hash)
{
@ -77,149 +74,317 @@ namespace RageCoop.Client
*/
}
public static MuzzleInfo GetMuzzleInfo(this Vehicle v)
public static int GetMuzzleIndex(this Vehicle v)
{
BulletsShot++;
int i;
switch (v.Model.Hash)
{
// cerberus3
case 1909700336:
return 53;
// cerberus2
case 679453769:
return 54;
// cerberus
case -801550069:
return 90;
/*
// cerberus (flame)
case -801550069:
i=BulletsShot%2==0 ? 89 : 88;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// cerberus (passenger flame)
case -801550069:
i=BulletsShot%2==0 ? 76 : 75;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
*/
// ISSI6
case 1239571361:
return BulletsShot % 2 == 0 ? 12 : 14;
// ISSI5
case 1537277726:
return BulletsShot % 2 == 0 ? 30 : 32;
// ISSI4
case 628003514:
return BulletsShot % 2 == 0 ? 14 : 12;
// DOMINATOR6
case -1293924613:
return BulletsShot % 2 == 0 ? 51 : 55;
// IMPALER4
case -1744505657:
return BulletsShot % 2 == 0 ? 64 : 63;
// IMPERATOR3
case -755532233:
return BulletsShot % 2 == 0 ? 86 : 88;
// SLAMVAN6
case 1742022738:
return BulletsShot % 2 == 0 ? 78 : 76;
// CHAMPION
case -915234475:
return BulletsShot % 2 == 0 ? 60 : 61;
// MONSTER4
case 840387324:
return BulletsShot % 2 == 0 ? 63 : 65;
// BRUTUS2
case -1890996696:
return 67;
// BRUISER2
case -1694081890:
return BulletsShot % 2 == 0 ? 45 : 51;
// TECHNICAL3
case 1356124575:
return 67;
// TECHNICAL2
case 1180875963:
return 54;
// TECHNICAL
case -2096818938:
return 63;
// PATRIOT3
case -670086588:
return BulletsShot % 2 == 0 ? 87 : 89;
// NIGHTSHARK
case 433954513:
return BulletsShot % 2 == 0 ? 1 : 2;
/*
// NIGHTSHARK (second)
case 433954513:
return BulletsShot%2==0 ? 3 : 4;
*/
// MENACER
case 2044532910:
return BulletsShot % 2 == 0 ? 91 : 90;
/*
// MENACER
case 2044532910:
return new MuzzleInfo(v.Bones[75].Position, v.Bones[75].ForwardVector);
// MENACER
case 2044532910:
return new MuzzleInfo(v.Bones[78].Position, v.Bones[78].ForwardVector);
*/
// CARACARA
case 1254014755:
return 83;
/*
// CARACARA
case 1254014755:
return BulletsShot%2==0 ? 93 : 94;
*/
// INSURGENT
case -1860900134:
return 49;
// INSURGENT3
case -1924433270:
return 81;
/*
// INSURGENT3
case -1924433270:
return BulletsShot%2==0 ? 86 : 91;
*/
// BLAZER5
case -1590337689:
return BulletsShot % 2 == 0 ? 17 : 18;
// BRUISER
case 668439077:
return BulletsShot % 2 == 0 ? 66 : 68;
// BRUTUS
case 2139203625:
return 84;
// MONSTER3
case 1721676810:
return BulletsShot % 2 == 0 ? 53 : 55;
// BRUISER3
case -2042350822:
return BulletsShot % 2 == 0 ? 52 : 50;
// BRUTUS3
case 2038858402:
return 84;
// MONSTER5
case -715746948:
return BulletsShot % 2 == 0 ? 63 : 65;
// JB7002
case 394110044:
i=BulletsShot%2==0 ? 54 : 53;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 54 : 53;
// DOMINATOR5
case -1375060657:
i=BulletsShot%2==0 ? 35 : 36;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 35 : 36;
// IMPALER3
case -1924800695:
i=BulletsShot%2==0 ? 75 : 76;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 75 : 76;
// IMPERATOR2
case 1637620610:
i=BulletsShot%2==0 ? 97 : 99;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 97 : 99;
// SLAMVAN5
case 373261600:
i=BulletsShot%2==0 ? 51 : 53;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 51 : 53;
// RUINER2
case 941494461:
i=BulletsShot%2==0 ? 65 : 66;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 65 : 66;
// TAMPA3
case -1210451983:
return new MuzzleInfo(v.Bones[87].Position, v.Bones[87].ForwardVector);
return 87;
// SCRAMJET
case -638562243:
i=BulletsShot%2==0 ? 44 : 45;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 44 : 45;
// VIGILANTE
case -1242608589:
i=BulletsShot%2==0 ? 42 : 43;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 42 : 43;
// ZR380
case 540101442:
i=BulletsShot%2==0 ? 57 : 63;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 57 : 63;
// ZR3802
case -1106120762:
i=BulletsShot%2==0 ? 57 : 63;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 57 : 63;
// ZR3803
case -1478704292:
i=BulletsShot%2==0 ? 53 : 59;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 53 : 59;
// STROMBERG
case 886810209:
i=BulletsShot%2==0 ? 85 : 84;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 85 : 84;
// SLAMVAN4
case -2061049099:
i=BulletsShot%2==0 ? 76 : 78;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 76 : 78;
// IMPERATOR
case 444994115:
i=BulletsShot%2==0 ? 88 : 86;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 88 : 86;
// IMPALER2
case 1009171724:
i=BulletsShot%2==0 ? 63 : 64;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 63 : 64;
// DOMINATOR4
case -688189648:
i=BulletsShot%2==0 ? 59 : 60;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 59 : 60;
// SAVAGE
case -82626025:
return new MuzzleInfo(v.Bones[30].Position, v.Bones[30].ForwardVector);
return 30;
// BUZZARD
case 788747387:
i=BulletsShot%2==0 ? 28 : 23;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 28 : 23;
// ANNIHL
case 837858166:
i=(int)BulletsShot%4+35;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return (int)BulletsShot % 4 + 35;
// HYDRA
case 970385471:
i=BulletsShot%2==0 ? 29 : 28;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 29 : 28;
// STARLING
case -1700874274:
i=BulletsShot%2==0 ? 24 : 12;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
return BulletsShot % 2 == 0 ? 24 : 12;
// RHINO
case 782665360:
return new MuzzleInfo(v.Bones[35].Position,v.Bones[35].ForwardVector);
return 30;
default:
return null;
return AddOnDataProvider.GetMuzzleIndex(v.Model.Hash);
}
}
public static bool IsUsingProjectileWeapon(this Ped p)
{
var vp = p.VehicleWeapon;
if (vp!=VehicleWeaponHash.Invalid)
var type = Function.Call<int>(Hash.GET_WEAPON_DAMAGE_TYPE, vp);
if (vp != VehicleWeaponHash.Invalid)
{
return VehicleProjectileWeapons.Contains(vp);
}
else
{
var w = p.Weapons.Current;
return w.Group==WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
return type == 3 ? false : VehicleProjectileWeapons.Contains(vp) || (type == 5 && !ExplosiveBullets.Contains((uint)vp));
}
var w = p.Weapons.Current;
return w.Group == WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
}
public static readonly HashSet<uint> ExplosiveBullets = new HashSet<uint>
{
(uint)VehicleWeaponHash.PlayerLazer,
(uint)WeaponHash.Railgun,
1638077257
};
public static readonly Dictionary<WeaponHash, int> MuzzleBoneIndexes = new Dictionary<WeaponHash, int>
{
{WeaponHash.HeavySniper,6},
@ -288,7 +453,6 @@ namespace RageCoop.Client
{WeaponHash.PumpShotgunMk2,7},
};
public static readonly HashSet<WeaponHash> ProjectileWeapons = new HashSet<WeaponHash> {
WeaponHash.HomingLauncher,
@ -307,5 +471,73 @@ namespace RageCoop.Client
(VehicleWeaponHash)3565779982, // STROMBERG missiles
(VehicleWeaponHash)3169388763, // SCRAMJET missiles
};
public static string GetFlashFX(this WeaponHash w)
{
switch (w.GetWeaponGroup())
{
case WeaponGroup.SMG:
return "muz_smg";
case WeaponGroup.Shotgun:
return "muz_smg";
case WeaponGroup.AssaultRifle:
return "muz_assault_rifle";
case WeaponGroup.Pistol:
return "muz_pistol";
case WeaponGroup.Stungun:
return "muz_stungun";
case WeaponGroup.Heavy:
switch (w)
{
case WeaponHash.Minigun:
return "muz_minigun";
case WeaponHash.RPG:
return "muz_rpg";
default:
return "muz_minigun";
}
case WeaponGroup.Sniper:
return "muz_alternate_star";
case WeaponGroup.PetrolCan:
return "weap_petrol_can";
case WeaponGroup.FireExtinguisher:
return "weap_extinguisher";
}
switch ((VehicleWeaponHash)w)
{
case VehicleWeaponHash.Tank:
return "muz_tank";
case VehicleWeaponHash.PlayerBuzzard:
return "muz_buzzard";
}
return "muz_assault_rifle";
}
public static WeaponGroup GetWeaponGroup(this WeaponHash hash)
{
return Function.Call<WeaponGroup>(Hash.GET_WEAPONTYPE_GROUP, hash);
}
}
/*
class WeaponInfo
{
public string Name;
public string MuzzleFx;
}
public class AimingInfo
{
public string Name;
public float HeadingLimit;
public float SweepPitchMin;
public float SweepPitchMax;
}
*/
}

View File

@ -1,8 +1,6 @@
using System;
using System.Linq;
using RageCoop.Core;
using GTA;
using GTA;
using GTA.Native;
using System;
namespace RageCoop.Client
{
@ -11,7 +9,6 @@ namespace RageCoop.Client
/// </summary>
public class WorldThread : Script
{
private static bool _lastDisableTraffic = false;
/// <summary>
/// Don't use it!
@ -21,43 +18,55 @@ namespace RageCoop.Client
Tick += OnTick;
Aborted += (sender, e) =>
{
if (_lastDisableTraffic)
{
Traffic(true);
}
ChangeTraffic(true);
};
}
private static bool _trafficEnabled;
private void OnTick(object sender, EventArgs e)
{
if (Game.IsLoading)
if (Game.IsLoading || !Networking.IsOnServer)
{
return;
}
if (!Networking.IsOnServer)
{
return ;
}
Game.DisableControlThisFrame(Control.FrontendPause);
if (Main.Settings.DisableAlternatePause)
{
Game.DisableControlThisFrame(Control.FrontendPauseAlternate);
}
// Sets a value that determines how aggressive the ocean waves will be.
// Values of 2.0 or more make for very aggressive waves like you see during a thunderstorm.
Function.Call(Hash.SET_DEEP_OCEAN_SCALER, 0.0f); // Works only ~200 meters around the player
// Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, Game.Player.Character.Handle, true, false);
if (Main.Settings==null) { return; }
if (Main.Settings.DisableTraffic)
if (Main.Settings.ShowEntityOwnerName)
{
if (!_lastDisableTraffic)
unsafe
{
Traffic(false);
}
int handle;
if (Function.Call<bool>(Hash.GET_ENTITY_PLAYER_IS_FREE_AIMING_AT, 0, &handle))
{
var entity = Entity.FromHandle(handle);
if (entity != null)
{
var owner = "invalid";
if (entity.EntityType == EntityType.Vehicle)
{
owner = (entity as Vehicle).GetSyncEntity()?.Owner?.Username ?? "unknown";
}
if (entity.EntityType == EntityType.Ped)
{
owner = (entity as Ped).GetSyncEntity()?.Owner?.Username ?? "unknown";
}
GTA.UI.Screen.ShowHelpTextThisFrame("Entity owner: " + owner);
}
}
}
}
if (!_trafficEnabled)
{
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 0);
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
Function.Call(Hash.SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
@ -66,15 +75,13 @@ namespace RageCoop.Client
Function.Call(Hash.SUPPRESS_SHOCKING_EVENTS_NEXT_FRAME);
Function.Call(Hash.SUPPRESS_AGITATION_EVENTS_NEXT_FRAME);
}
else if (_lastDisableTraffic)
{
Traffic(true);
}
_lastDisableTraffic = Main.Settings.DisableTraffic;
}
private void Traffic(bool enable)
public static void Traffic(bool enable)
{
ChangeTraffic(enable);
_trafficEnabled = enable;
}
private static void ChangeTraffic(bool enable)
{
if (enable)
{
@ -83,15 +90,15 @@ namespace RageCoop.Client
Function.Call(Hash.SET_RANDOM_TRAINS, true);
Function.Call(Hash.SET_RANDOM_BOATS, true);
Function.Call(Hash.SET_GARBAGE_TRUCKS, true);
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 1); // 0 - 3
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 1); // 0 - 3
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 3); // 0 - 3
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 3); // 0 - 3
Function.Call(Hash.SET_ALL_VEHICLE_GENERATORS_ACTIVE);
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, true);
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, -1);
Function.Call(Hash.SET_DISTANT_CARS_ENABLED, true);
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, false);
}
else
else if (Networking.IsOnServer)
{
Function.Call(Hash.ADD_SCENARIO_BLOCKING_AREA, -10000.0f, -10000.0f, -1000.0f, 10000.0f, 10000.0f, 1000.0f, 0, 1, 1, 1);
Function.Call(Hash.SET_CREATE_RANDOM_COPS, false);
@ -99,41 +106,38 @@ namespace RageCoop.Client
Function.Call(Hash.SET_RANDOM_BOATS, false);
Function.Call(Hash.SET_GARBAGE_TRUCKS, false);
Function.Call(Hash.DELETE_ALL_TRAINS);
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 3);
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 3);
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 0);
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, false);
Function.Call(Hash.SET_FAR_DRAW_VEHICLES, false);
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, 0);
Function.Call(Hash.SET_DISTANT_CARS_ENABLED, false);
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, true);
foreach (Ped ped in World.GetAllPeds())
{
if (ped == Game.Player.Character) { continue; }
SyncedPed c = EntityPool.GetPedByHandle(ped.Handle);
if ((c==null) || (c.IsLocal && (ped.Handle!=Game.Player.Character.Handle)&&ped.PopulationType!=EntityPopulationType.Mission))
if ((c == null) || (c.IsLocal && (ped.Handle != Game.Player.Character.Handle) && ped.PopulationType != EntityPopulationType.Mission))
{
if (ped.Handle==Game.Player.Character.Handle) { continue; }
Main.Logger.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
// Main.Logger.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
ped.CurrentVehicle?.Delete();
ped.Kill();
ped.Delete();
}
}
foreach (Vehicle veh in World.GetAllVehicles())
{
SyncedVehicle v = veh.GetSyncEntity();
if (v.MainVehicle==Game.Player.LastVehicle)
if (v.MainVehicle == Game.Player.LastVehicle || v.MainVehicle == Game.Player.Character.CurrentVehicle)
{
// Don't delete player's vehicle
continue;
}
if((v== null) || (v.IsLocal&&veh.PopulationType!=EntityPopulationType.Mission))
if ((v == null) || (v.IsLocal && veh.PopulationType != EntityPopulationType.Mission))
{
Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
// Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
veh.Delete();
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Costura.Fody" version="5.7.0" targetFramework="net48" developmentDependency="true" />
<package id="Fody" version="6.6.3" targetFramework="net48" developmentDependency="true" />
<package id="Microsoft.Extensions.ObjectPool" version="6.0.8" targetFramework="net48" />
<package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net48" />
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net48" />
<package id="Microsoft.Win32.Registry" version="4.7.0" targetFramework="net481" />
<package id="NAudio" version="2.1.0" targetFramework="net481" />
<package id="NAudio.Asio" version="2.1.0" targetFramework="net481" />
<package id="NAudio.Core" version="2.1.0" targetFramework="net481" />
<package id="NAudio.Midi" version="2.1.0" targetFramework="net481" />
<package id="NAudio.Wasapi" version="2.1.0" targetFramework="net481" />
<package id="NAudio.WinForms" version="2.1.0" targetFramework="net481" />
<package id="NAudio.WinMM" version="2.1.0" targetFramework="net481" />
<package id="NETStandard.Library" version="1.6.1" targetFramework="net48" />
<package id="SharpZipLib" version="1.3.3" targetFramework="net48" />
<package id="System.AppContext" version="4.3.0" targetFramework="net48" />
<package id="System.Collections" version="4.3.0" targetFramework="net48" />
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net48" />
<package id="System.Console" version="4.3.0" targetFramework="net48" />
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net48" />
<package id="System.Diagnostics.DiagnosticSource" version="4.3.0" targetFramework="net48" />
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net48" />
<package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net48" />
<package id="System.Globalization" version="4.3.0" targetFramework="net48" />
<package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net48" />
<package id="System.IO" version="4.3.0" targetFramework="net48" />
<package id="System.IO.Compression" version="4.3.0" targetFramework="net48" />
<package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net48" />
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net48" />
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net48" />
<package id="System.Linq" version="4.3.0" targetFramework="net48" />
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net48" />
<package id="System.Net.Http" version="4.3.0" targetFramework="net48" />
<package id="System.Net.Primitives" version="4.3.0" targetFramework="net48" />
<package id="System.Net.Sockets" version="4.3.0" targetFramework="net48" />
<package id="System.ObjectModel" version="4.3.0" targetFramework="net48" />
<package id="System.Reflection" version="4.3.0" targetFramework="net48" />
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net48" />
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net48" />
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net48" />
<package id="System.Runtime" version="4.3.0" targetFramework="net48" />
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net48" />
<package id="System.Runtime.Handles" version="4.3.0" targetFramework="net48" />
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net48" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net48" />
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net48" />
<package id="System.Security.AccessControl" version="4.7.0" targetFramework="net481" />
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net48" />
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net48" />
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net48" />
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net48" />
<package id="System.Security.Principal.Windows" version="4.7.0" targetFramework="net481" />
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net48" />
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net48" />
<package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net48" />
<package id="System.Threading" version="4.3.0" targetFramework="net48" />
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net48" />
<package id="System.Threading.Timer" version="4.3.0" targetFramework="net48" />
<package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net48" />
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net48" />
</packages>

View File

@ -1,145 +1,56 @@
using System;
using GTA.Math;
using System.IO;
using System.Text;
using System.Linq;
using GTA.Math;
namespace RageCoop.Core
{
internal class BitReader
internal class BitReader : BinaryReader
{
public int CurrentIndex { get; set; }
private byte[] ResultArray;
public BitReader(byte[] array)
public BitReader(byte[] array) : base(new MemoryStream(array))
{
CurrentIndex = 0;
ResultArray = array;
}
~BitReader()
{
ResultArray = null;
Close();
Dispose();
}
public bool CanRead(int bytes)
{
return ResultArray.Length >= CurrentIndex + bytes;
}
public bool ReadBool()
{
bool value = BitConverter.ToBoolean(ResultArray, CurrentIndex);
CurrentIndex += 1;
return value;
}
public float ReadFloat()
{
float value = BitConverter.ToSingle(ResultArray, CurrentIndex);
CurrentIndex += 4;
return value;
}
public byte ReadByte()
{
byte value = ResultArray[CurrentIndex];
CurrentIndex += 1;
return value;
}
public byte[] ReadByteArray(int length)
{
byte[] value = new byte[length];
Array.Copy(ResultArray, CurrentIndex,value,0,length);
CurrentIndex += length;
return value;
}
public byte[] ReadByteArray()
{
return ReadByteArray(ReadInt());
return base.ReadBytes(ReadInt32());
}
public short ReadShort()
public override string ReadString()
{
short value = BitConverter.ToInt16(ResultArray, CurrentIndex);
CurrentIndex += 2;
return value;
}
public ushort ReadUShort()
{
ushort value = BitConverter.ToUInt16(ResultArray, CurrentIndex);
CurrentIndex += 2;
return value;
}
public int ReadInt()
{
int value = BitConverter.ToInt32(ResultArray, CurrentIndex);
CurrentIndex += 4;
return value;
}
public uint ReadUInt()
{
uint value = BitConverter.ToUInt32(ResultArray, CurrentIndex);
CurrentIndex += 4;
return value;
}
public long ReadLong()
{
long value = BitConverter.ToInt64(ResultArray, CurrentIndex);
CurrentIndex += 8;
return value;
}
public ulong ReadULong()
{
ulong value = BitConverter.ToUInt64(ResultArray, CurrentIndex);
CurrentIndex += 8;
return value;
}
public string ReadString(int index)
{
string value = Encoding.UTF8.GetString(ResultArray.Skip(CurrentIndex).Take(index).ToArray());
CurrentIndex += index;
return value;
}
public string ReadString()
{
var len = ReadInt();
string value = Encoding.UTF8.GetString(ResultArray.Skip(CurrentIndex).Take(len).ToArray());
CurrentIndex += len;
return value;
return Encoding.UTF8.GetString(ReadBytes(ReadInt32()));
}
public Vector3 ReadVector3()
{
return new Vector3()
{
X = ReadFloat(),
Y = ReadFloat(),
Z = ReadFloat()
X = ReadSingle(),
Y = ReadSingle(),
Z = ReadSingle()
};
}
public Vector2 ReadVector2()
{
return new Vector2()
{
X = ReadFloat(),
Y = ReadFloat()
X = ReadSingle(),
Y = ReadSingle()
};
}
public Quaternion ReadQuaternion()
{
return new Quaternion()
{
X = ReadFloat(),
Y = ReadFloat(),
Z = ReadFloat(),
W = ReadFloat()
X = ReadSingle(),
Y = ReadSingle(),
Z = ReadSingle(),
W = ReadSingle()
};
}
}

View File

@ -1,135 +1,245 @@
using System;
using GTA.Math;
using Lidgren.Network;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA.Math;
using System.Security.Cryptography;
using System.Net;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
[assembly: InternalsVisibleTo("RageCoop.Server")]
[assembly: InternalsVisibleTo("RageCoop.Client")]
[assembly: InternalsVisibleTo("RageCoop.Client.Installer")]
[assembly: InternalsVisibleTo("RageCoop.ResourceBuilder")]
namespace RageCoop.Core
{
internal class CoreUtils
internal static class CoreUtils
{
public static (byte, byte[]) GetBytesFromObject(object obj)
private static readonly HashSet<string> ToIgnore = new HashSet<string>()
{
"RageCoop.Client.dll",
"RageCoop.Core.dll",
"RageCoop.Server.dll",
"ScriptHookVDotNet3.dll",
"ScriptHookVDotNet.dll"
};
public static bool CanBeIgnored(this string name)
{
return ToIgnore.Contains(name);
}
public static void GetBytesFromObject(object obj, NetOutgoingMessage m)
{
switch (obj)
{
case byte _:
return (0x01, new byte[] { (byte)obj });
case short _:
return (0x02, BitConverter.GetBytes((short)obj));
case ushort _:
return (0x03, BitConverter.GetBytes((ushort)obj));
case int _:
return (0x04, BitConverter.GetBytes((int)obj));
case uint _:
return (0x05, BitConverter.GetBytes((uint)obj));
case long _:
return (0x06, BitConverter.GetBytes((long)obj));
case ulong _:
return (0x07, BitConverter.GetBytes((ulong)obj));
case float _:
return (0x08, BitConverter.GetBytes((float)obj));
case bool _:
return (0x09, BitConverter.GetBytes((bool)obj));
case string _:
return (0x10, ((string)obj).GetBytesWithLength());
case Vector3 _:
return (0x11,((Vector3)obj).GetBytes());
case Quaternion _:
return (0x12, ((Quaternion)obj).GetBytes());
case GTA.Model _:
return (0x13, BitConverter.GetBytes((GTA.Model)obj));
case Vector2 _:
return (0x14, ((Vector2)obj).GetBytes());
case Tuple<byte, byte[]> _:
var tup = (Tuple<byte, byte[]>)obj;
return (tup.Item1, tup.Item2);
case byte value:
m.Write((byte)0x01); m.Write(value); break;
case short value:
m.Write((byte)0x02); m.Write(value); break;
case ushort value:
m.Write((byte)0x03); m.Write(value); break;
case int value:
m.Write((byte)0x04); m.Write(value); break;
case uint value:
m.Write((byte)0x05); m.Write(value); break;
case long value:
m.Write((byte)0x06); m.Write(value); break;
case ulong value:
m.Write((byte)0x07); m.Write(value); break;
case float value:
m.Write((byte)0x08); m.Write(value); break;
case bool value:
m.Write((byte)0x09); m.Write(value); break;
case string value:
m.Write((byte)0x10); m.Write(value); break;
case Vector3 value:
m.Write((byte)0x11); m.Write(value); break;
case Quaternion value:
m.Write((byte)0x12); m.Write(value); break;
case GTA.Model value:
m.Write((byte)0x13); m.Write(value); break;
case Vector2 value:
m.Write((byte)0x14); m.Write(value); break;
case byte[] value:
m.Write((byte)0x15); m.WriteByteArray(value); break;
case Tuple<byte, byte[]> value:
m.Write(value.Item1); m.Write(value.Item2); break;
default:
return (0x0, null);
throw new Exception("Unsupported object type: " + obj.GetType());
}
}
public static IPEndPoint StringToEndPoint(string endpointstring)
{
return StringToEndPoint(endpointstring, -1);
}
public static IPEndPoint StringToEndPoint(string endpointstring, int defaultport)
{
if (string.IsNullOrEmpty(endpointstring)
|| endpointstring.Trim().Length == 0)
{
throw new ArgumentException("Endpoint descriptor may not be empty.");
}
if (defaultport != -1 &&
(defaultport < IPEndPoint.MinPort
|| defaultport > IPEndPoint.MaxPort))
{
throw new ArgumentException(string.Format("Invalid default port '{0}'", defaultport));
}
string[] values = endpointstring.Split(new char[] { ':' });
IPAddress ipaddy;
int port = -1;
//check if we have an IPv6 or ports
if (values.Length <= 2) // ipv4 or hostname
{
if (values.Length == 1)
//no port is specified, default
port = defaultport;
else
port = getPort(values[1]);
//try to use the address as IPv4, otherwise get hostname
if (!IPAddress.TryParse(values[0], out ipaddy))
ipaddy = GetIPfromHost(values[0]);
}
else if (values.Length > 2) //ipv6
{
//could [a:b:c]:d
if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]"))
{
string ipaddressstring = string.Join(":", values.Take(values.Length - 1).ToArray());
ipaddy = IPAddress.Parse(ipaddressstring);
port = getPort(values[values.Length - 1]);
}
else //[a:b:c] or a:b:c
{
ipaddy = IPAddress.Parse(endpointstring);
port = defaultport;
}
}
else
{
throw new FormatException(string.Format("Invalid endpoint ipaddress '{0}'", endpointstring));
}
if (port == -1)
throw new ArgumentException(string.Format("No port specified: '{0}'", endpointstring));
return new IPEndPoint(ipaddy, port);
}
private static int getPort(string p)
{
if (!int.TryParse(p, out int port)
|| port < IPEndPoint.MinPort
|| port > IPEndPoint.MaxPort)
{
throw new FormatException(string.Format("Invalid end point port '{0}'", p));
}
return port;
}
public static IPAddress GetLocalAddress(string target = "8.8.8.8")
{
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
{
socket.Connect(target, 65530);
IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint;
return endPoint.Address;
}
}
public static IPAddress GetIPfromHost(string p)
{
var hosts = Dns.GetHostAddresses(p);
if (hosts == null || hosts.Length == 0)
throw new ArgumentException(string.Format("Host not found: {0}", p));
return hosts[0];
}
public static IpInfo GetIPInfo()
{
// TLS only
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
var httpClient = new HttpClient();
HttpResponseMessage response = httpClient.GetAsync("https://ipinfo.io/json").GetAwaiter().GetResult();
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception($"IPv4 request failed! [{(int)response.StatusCode}/{response.ReasonPhrase}]");
}
string content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
return JsonConvert.DeserializeObject<IpInfo>(content);
}
public static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target)
{
foreach (DirectoryInfo dir in source.GetDirectories())
CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
foreach (FileInfo file in source.GetFiles())
file.CopyTo(Path.Combine(target.FullName, file.Name), true);
}
public static string GetInvariantRID()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return "win-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return "linux-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return "osx-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
}
return "unknown";
}
/// <summary>
/// Get local ip addresses on all network interfaces
/// </summary>
/// <returns></returns>
public static List<IPAddress> GetLocalAddress()
{
var addresses = new List<IPAddress>();
foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
{
IPInterfaceProperties ipProps = netInterface.GetIPProperties();
foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
{
addresses.Add(addr.Address);
}
}
return addresses;
}
}
internal class IpInfo
{
[JsonProperty("ip")]
public string Address { get; set; }
[JsonProperty("country")]
public string Country { get; set; }
}
internal static class Extensions
{
public static void AddVector3(this List<byte> bytes, Vector3 vec3)
{
bytes.AddRange(BitConverter.GetBytes(vec3.X));
bytes.AddRange(BitConverter.GetBytes(vec3.Y));
bytes.AddRange(BitConverter.GetBytes(vec3.Z));
}
public static void AddQuaternion(this List<byte> bytes, Quaternion quat)
{
bytes.AddRange(BitConverter.GetBytes(quat.X));
bytes.AddRange(BitConverter.GetBytes(quat.Y));
bytes.AddRange(BitConverter.GetBytes(quat.Z));
bytes.AddRange(BitConverter.GetBytes(quat.W));
}
public static void AddInt(this List<byte> bytes,int i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddUint(this List<byte> bytes, uint i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddShort(this List<byte> bytes, short i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddUshort(this List<byte> bytes, ushort i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddLong(this List<byte> bytes, long i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddUlong(this List<byte> bytes, ulong i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddFloat(this List<byte> bytes, float i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddString(this List<byte> bytes, string s)
{
var sb = Encoding.UTF8.GetBytes(s);
bytes.AddInt(sb.Length);
bytes.AddRange(sb);
}
public static void AddArray(this List<byte> bytes, byte[] toadd)
{
bytes.AddInt(toadd.Length);
bytes.AddRange(toadd);
}
public static int GetHash(string s)
{
MD5 md5Hasher = MD5.Create();
var hashed = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(s));
return BitConverter.ToInt32(hashed, 0);
}
public static byte[] GetBytes(this string s)
{
return Encoding.UTF8.GetBytes(s);
}
public static byte[] GetBytesWithLength(this string s)
{
var data = new List<byte>(100);
var sb = Encoding.UTF8.GetBytes(s);
data.AddInt(sb.Length);
data.AddRange(sb);
return data.ToArray();
}
public static string GetString(this byte[] data)
{
return Encoding.UTF8.GetString(data);
@ -156,19 +266,28 @@ namespace RageCoop.Core
// 16 bytes
return new List<byte[]>() { BitConverter.GetBytes(qua.X), BitConverter.GetBytes(qua.Y), BitConverter.GetBytes(qua.Z), BitConverter.GetBytes(qua.W) }.Join(4);
}
public static T GetPacket<T>(this NetIncomingMessage msg) where T : Packet, new()
{
var p = new T();
p.Deserialize(msg);
return p;
}
public static bool HasPedFlag(this PedDataFlags flagToCheck, PedDataFlags flag)
{
return (flagToCheck & flag)!=0;
return (flagToCheck & flag) != 0;
}
public static bool HasProjDataFlag(this ProjectileDataFlags flagToCheck, ProjectileDataFlags flag)
{
return (flagToCheck & flag) != 0;
}
public static bool HasVehFlag(this VehicleDataFlags flagToCheck, VehicleDataFlags flag)
{
return (flagToCheck & flag)!=0;
return (flagToCheck & flag) != 0;
}
public static bool HasConfigFlag(this PlayerConfigFlags flagToCheck, PlayerConfigFlags flag)
{
return (flagToCheck & flag)!=0;
return (flagToCheck & flag) != 0;
}
public static Type GetActualType(this TypeCode code)
{
@ -235,19 +354,19 @@ namespace RageCoop.Core
public static string DumpWithType(this IEnumerable<object> objects)
{
StringBuilder sb = new StringBuilder();
foreach(var obj in objects)
foreach (var obj in objects)
{
sb.Append(obj.GetType()+":"+obj.ToString()+"\n");
sb.Append(obj.GetType() + ":" + obj.ToString() + "\n");
}
return sb.ToString();
}
public static string Dump<T>(this IEnumerable<T> objects)
{
return "{"+string.Join(",",objects)+"}";
return $"{{{string.Join(",", objects)}}}";
}
public static void ForEach<T>(this IEnumerable<T> objects,Action<T> action)
public static void ForEach<T>(this IEnumerable<T> objects, Action<T> action)
{
foreach(var obj in objects)
foreach (var obj in objects)
{
action(obj);
}
@ -263,10 +382,16 @@ namespace RageCoop.Core
return memoryStream.ToArray();
}
}
public static byte[] Join(this List<byte[]> arrays,int lengthPerArray=-1)
public static MemoryStream ToMemStream(this Stream stream)
{
if (arrays.Count==1) { return arrays[0]; }
var output = lengthPerArray== -1 ? new byte[arrays.Sum(arr => arr.Length)] : new byte[arrays.Count*lengthPerArray];
var memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
return memoryStream;
}
public static byte[] Join(this List<byte[]> arrays, int lengthPerArray = -1)
{
if (arrays.Count == 1) { return arrays[0]; }
var output = lengthPerArray == -1 ? new byte[arrays.Sum(arr => arr.Length)] : new byte[arrays.Count * lengthPerArray];
int writeIdx = 0;
foreach (var byteArr in arrays)
{
@ -284,4 +409,42 @@ namespace RageCoop.Core
return false;
}
}
/// <summary>
/// Some extension methods provided by RageCoop
/// </summary>
public static class PublicExtensions
{
/// <summary>
/// Get a SHA256 hashed byte array of the input string, internally used to hash password at client side.
/// </summary>
/// <param name="inputString"></param>
/// <returns></returns>
public static byte[] GetSHA256Hash(this string inputString)
{
using (HashAlgorithm algorithm = SHA256.Create())
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
}
/// <summary>
/// Convert a byte array to hex-encoded string, internally used to trigger handshake event
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static string ToHexString(this byte[] data)
{
return BitConverter.ToString(data).Replace("-", String.Empty);
}
/// <summary>
/// Convert a string to IP address
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public static IPAddress ToIP(this string ip)
{
return IPAddress.Parse(ip);
}
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura />
</Weavers>

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeReferences" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if runtime assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseRuntimeReferencePaths" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCompression" type="xs:boolean">
<xs:annotation>
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCleanup" type="xs:boolean">
<xs:annotation>
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
namespace RageCoop.Core
@ -32,34 +31,34 @@ namespace RageCoop.Core
private StreamWriter logWriter;
private string Buffer = "";
private Thread LoggerThread;
private readonly Thread LoggerThread;
private bool Stopping = false;
private bool FlushImmediately;
private readonly bool FlushImmediately;
internal Logger(bool flushImmediately = false, bool overwrite = true)
{
FlushImmediately = flushImmediately;
if (File.Exists(LogPath)&&overwrite) { File.Delete(LogPath); }
Name=Process.GetCurrentProcess().Id.ToString();
if (File.Exists(LogPath) && overwrite) { File.Delete(LogPath); }
Name = Process.GetCurrentProcess().Id.ToString();
if (!flushImmediately)
{
LoggerThread=new Thread(() =>
{
if (!UseConsole)
{
while (LogPath==default)
{
Thread.Sleep(100);
}
if (File.Exists(LogPath)&&overwrite) { File.Delete(LogPath); }
}
while (!Stopping)
{
Flush();
Thread.Sleep(1000);
}
Flush();
});
LoggerThread = new Thread(() =>
{
if (!UseConsole)
{
while (LogPath == default)
{
Thread.Sleep(100);
}
if (File.Exists(LogPath) && overwrite) { File.Delete(LogPath); }
}
while (!Stopping)
{
Flush();
Thread.Sleep(1000);
}
Flush();
});
LoggerThread.Start();
}
}
@ -69,12 +68,12 @@ namespace RageCoop.Core
/// <param name="message"></param>
public void Info(string message)
{
if (LogLevel>2) { return; }
if (LogLevel > 2) { return; }
lock (Buffer)
{
string msg = string.Format("[{0}][{2}] [INF] {1}", Date(), message, Name);
Buffer+=msg+"\r\n";
Buffer += msg + "\r\n";
}
if (FlushImmediately)
{
@ -87,12 +86,12 @@ namespace RageCoop.Core
/// <param name="message"></param>
public void Warning(string message)
{
if (LogLevel>3) { return; }
if (LogLevel > 3) { return; }
lock (Buffer)
{
string msg = string.Format("[{0}][{2}] [WRN] {1}", Date(), message, Name);
Buffer+=msg+"\r\n";
Buffer += msg + "\r\n";
}
if (FlushImmediately)
@ -106,12 +105,12 @@ namespace RageCoop.Core
/// <param name="message"></param>
public void Error(string message)
{
if (LogLevel>4) { return; }
if (LogLevel > 4) { return; }
lock (Buffer)
{
string msg = string.Format("[{0}][{2}] [ERR] {1}", Date(), message, Name);
Buffer+=msg+"\r\n";
Buffer += msg + "\r\n";
}
if (FlushImmediately)
{
@ -125,11 +124,11 @@ namespace RageCoop.Core
/// <param name="error"></param>
public void Error(string message, Exception error)
{
if (LogLevel>4) { return; }
if (LogLevel > 4) { return; }
lock (Buffer)
{
string msg = string.Format("[{0}][{2}] [ERR] {1}:{3}", Date(), message, Name,error.Message);
Buffer+=msg+"\r\n";
string msg = string.Format("[{0}][{2}] [ERR] {1}:{3}", Date(), message, Name, error.Message);
Buffer += msg + "\r\n";
Trace(error.ToString());
}
@ -144,11 +143,11 @@ namespace RageCoop.Core
/// <param name="ex"></param>
public void Error(Exception ex)
{
if (LogLevel>4) { return; }
if (LogLevel > 4) { return; }
lock (Buffer)
{
string msg = string.Format("[{0}][{2}] [ERR] {1}", Date(), "\r\n"+ex.Message, Name);
Buffer+=msg+"\r\n";
string msg = string.Format("[{0}][{2}] [ERR] {1}", Date(), "\r\n" + ex.Message, Name);
Buffer += msg + "\r\n";
Trace(ex.ToString());
}
if (FlushImmediately)
@ -163,12 +162,12 @@ namespace RageCoop.Core
public void Debug(string message)
{
if (LogLevel>1) { return; }
if (LogLevel > 1) { return; }
lock (Buffer)
{
string msg = string.Format("[{0}][{2}] [DBG] {1}", Date(), message, Name);
Buffer+=msg+"\r\n";
Buffer += msg + "\r\n";
}
if (FlushImmediately)
{
@ -181,12 +180,12 @@ namespace RageCoop.Core
/// <param name="message"></param>
public void Trace(string message)
{
if (LogLevel>0) { return; }
if (LogLevel > 0) { return; }
lock (Buffer)
{
string msg = string.Format("[{0}][{2}] [TRC] {1}", Date(), message, Name);
Buffer+=msg+"\r\n";
Buffer += msg + "\r\n";
}
if (FlushImmediately)
{
@ -205,21 +204,21 @@ namespace RageCoop.Core
{
lock (Buffer)
{
if (Buffer!="")
if (Buffer != "")
{
if (UseConsole)
{
Console.Write(Buffer);
Buffer="";
Buffer = "";
}
else
{
try
{
logWriter=new StreamWriter(LogPath, true, Encoding.UTF8);
logWriter = new StreamWriter(LogPath, true, Encoding.UTF8);
logWriter.Write(Buffer);
logWriter.Close();
Buffer="";
Buffer = "";
}
catch { }
}
@ -232,7 +231,7 @@ namespace RageCoop.Core
/// </summary>
public void Dispose()
{
Stopping=true;
Stopping = true;
LoggerThread?.Join();
}
}

View File

@ -1,13 +1,27 @@
using System;
using GTA.Math;
using GTA.Math;
using System;
namespace RageCoop.Core
{
internal static class MathExtensions
{
public const float Deg2Rad=(float)(Math.PI* 2) / 360;
public const float Deg2Rad = (float)(Math.PI * 2) / 360;
public const float Rad2Deg = 360 / (float)(Math.PI * 2);
public static Vector3 ToDirection(this Vector3 rotation)
{
double z = DegToRad(rotation.Z);
double x = DegToRad(rotation.X);
double num = Math.Abs(Math.Cos(x));
return new Vector3
{
X = (float)(-Math.Sin(z) * num),
Y = (float)(Math.Cos(z) * num),
Z = (float)Math.Sin(x)
};
}
/// <summary>
///
/// </summary>
@ -67,14 +81,14 @@ namespace RageCoop.Core
vect = vect.ToRadians();
float rollOver2 = vect.Z * 0.5f;
float sinRollOver2 = (float)Math.Sin((double)rollOver2);
float cosRollOver2 = (float)Math.Cos((double)rollOver2);
float sinRollOver2 = (float)Math.Sin(rollOver2);
float cosRollOver2 = (float)Math.Cos(rollOver2);
float pitchOver2 = vect.Y * 0.5f;
float sinPitchOver2 = (float)Math.Sin((double)pitchOver2);
float cosPitchOver2 = (float)Math.Cos((double)pitchOver2);
float sinPitchOver2 = (float)Math.Sin(pitchOver2);
float cosPitchOver2 = (float)Math.Cos(pitchOver2);
float yawOver2 = vect.X * 0.5f; // pitch
float sinYawOver2 = (float)Math.Sin((double)yawOver2);
float cosYawOver2 = (float)Math.Cos((double)yawOver2);
float sinYawOver2 = (float)Math.Sin(yawOver2);
float cosYawOver2 = (float)Math.Cos(yawOver2);
Quaternion result = new Quaternion()
{
X = cosYawOver2 * cosPitchOver2 * cosRollOver2 + sinYawOver2 * sinPitchOver2 * sinRollOver2,
@ -96,7 +110,11 @@ namespace RageCoop.Core
}
public static Vector3 ToDegree(this Vector3 radian)
{
return radian*(float)(180/Math.PI);
return radian * (float)(180 / Math.PI);
}
public static Vector3 ToEulerDegrees(this Quaternion q)
{
return q.ToEulerAngles().ToDegree();
}
public static Vector3 ToEulerAngles(this Quaternion q)
{
@ -127,16 +145,12 @@ namespace RageCoop.Core
}
private static float CopySign(double x, double y)
{
bool isPositive = y>=0;
if (isPositive)
if (y >= 0)
{
if (x>=0) { return (float)x; } else { return (float)-x; }
return x >= 0 ? (float)x : (float)-x;
}
else
{
if (x>=0) { return (float)-x; } else { return (float)x; }
}
return x >= 0 ? (float)-x : (float)x;
}
public static double AngelTo(this Vector3 v1, Vector3 v2)
{
@ -144,8 +158,7 @@ namespace RageCoop.Core
}
public static float GetCosTheta(this Vector3 v1, Vector3 v2)
{
return Vector3.Dot(v1, v2)/(v1.Length()*v2.Length());
return Vector3.Dot(v1, v2) / (v1.Length() * v2.Length());
}
}

View File

@ -0,0 +1,60 @@
using Lidgren.Network;
using System;
using System.Collections.Generic;
using System.Threading;
namespace RageCoop.Core
{
internal class CoopPeer : NetPeer, IDisposable
{
public EventHandler<NetIncomingMessage> OnMessageReceived;
private readonly Thread ListenerThread;
private bool _stopping = false;
public CoopPeer(NetPeerConfiguration config) : base(config)
{
Start();
NetIncomingMessage msg;
ListenerThread = new Thread(() =>
{
while (!_stopping)
{
msg = WaitMessage(200);
if (msg != null)
{
OnMessageReceived?.Invoke(this, msg);
}
}
});
ListenerThread.Start();
}
/// <summary>
/// Terminate all connections and background thread
/// </summary>
public void Dispose()
{
_stopping = true;
Shutdown("Bye!");
ListenerThread.Join();
}
public void SendTo(Packet p, NetConnection connection, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
{
NetOutgoingMessage outgoingMessage = CreateMessage();
p.Pack(outgoingMessage);
SendMessage(outgoingMessage, connection, method, (int)channel);
}
public void SendTo(Packet p, IList<NetConnection> connections, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
{
NetOutgoingMessage outgoingMessage = CreateMessage();
p.Pack(outgoingMessage);
SendMessage(outgoingMessage, connections, method, (int)channel);
}
public void Send(Packet p, IList<NetConnection> cons, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
{
NetOutgoingMessage outgoingMessage = CreateMessage();
p.Pack(outgoingMessage);
SendMessage(outgoingMessage, cons, method, (int)channel);
}
}
}

View File

@ -0,0 +1,42 @@
using System;
using System.IO;
using System.Net;
using System.Threading;
namespace RageCoop.Core
{
internal static class HttpHelper
{
public static void DownloadFile(string url, string destination, Action<int> progressCallback)
{
if (File.Exists(destination)) { File.Delete(destination); }
AutoResetEvent ae = new AutoResetEvent(false);
WebClient client = new WebClient();
// TLS only
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
client.DownloadProgressChanged += (s, e1) => progressCallback?.Invoke(e1.ProgressPercentage);
client.DownloadFileCompleted += (s, e2) =>
{
ae.Set();
};
client.DownloadFileAsync(new Uri(url), destination);
ae.WaitOne();
}
public static string DownloadString(string url)
{
// TLS only
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 |
SecurityProtocolType.Tls11 |
SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
WebClient client = new WebClient();
return client.DownloadString(url);
}
}
}

View File

@ -0,0 +1,22 @@
using System;
namespace RageCoop.Core
{
internal class PublicKey
{
public PublicKey()
{
}
public static PublicKey FromServerInfo(ServerInfo info)
{
return new PublicKey
{
Modulus = Convert.FromBase64String(info.publicKeyModulus),
Exponent = Convert.FromBase64String(info.publicKeyExponent)
};
}
public byte[] Modulus;
public byte[] Exponent;
}
}

View File

@ -0,0 +1,32 @@
namespace RageCoop.Core
{
/// <summary>
/// A json object representing a server's information as annouced to master server.
/// </summary>
public class ServerInfo
{
#pragma warning disable 1591
public string address { get; set; }
public string port { get; set; }
public string name { get; set; }
public string version { get; set; }
public string players { get; set; }
public string maxPlayers { get; set; }
public string country { get; set; }
public string description { get; set; }
public string website { get; set; }
public string gameMode { get; set; }
public string language { get; set; }
public bool useP2P { get; set; }
public bool useZT { get; set; }
public string ztID { get; set; }
public string ztAddress { get; set; }
public string publicKeyModulus { get; set; }
public string publicKeyExponent { get; set; }
}
}

View File

@ -0,0 +1,138 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
namespace RageCoop.Core
{
internal class ZeroTierNetwork
{
public ZeroTierNetwork(string line)
{
// <nwid> <name> <mac> <status> <type> <dev> <ZT assigned ips>
var v = Regex.Split(line, " ").Skip(2).ToArray();
ID = v[0];
Name = v[1];
Mac = v[2];
Status = v[3];
Type = v[4];
Device = v[5];
foreach (var i in v[6].Split(','))
{
Addresses.Add(i.Split('/')[0]);
}
}
public string ID;
public string Name;
public string Mac;
public string Status;
public string Type;
public string Device;
public List<string> Addresses = new List<string>();
}
internal static class ZeroTierHelper
{
private static readonly string _path = "zerotier-cli";
private static readonly string _arg = "";
static ZeroTierHelper()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var batpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "ZeroTier", "One", "zerotier-cli.bat");
_arg = $"/c \"{batpath}\" ";
_path = "cmd.exe";
}
var status = RunCommand("status");
if (!status.StartsWith("200"))
{
throw new Exception("ZeroTier not ready: " + status);
}
}
public static ZeroTierNetwork Join(string networkId, int timeout = 10000)
{
var p = Run("join " + networkId);
var o = p.StandardOutput.ReadToEnd();
if (!o.StartsWith("200 join OK"))
{
throw new Exception(o + p.StandardError.ReadToEnd());
}
if (timeout == 0) { return Networks[networkId]; }
int i = 0;
while (i <= timeout)
{
i += 100;
if (Networks.TryGetValue(networkId, out var n))
{
if (n.Addresses.Count != 0 && (!n.Addresses.Where(x => x == "-").Any()))
{
return n;
}
System.Threading.Thread.Sleep(100);
}
else
{
break;
}
}
return null;
}
public static void Leave(string networkId)
{
var p = Run("leave " + networkId);
var o = p.StandardOutput.ReadToEnd();
if (!o.StartsWith("200 leave OK"))
{
throw new Exception(o + p.StandardError.ReadToEnd());
}
}
public static Dictionary<string, ZeroTierNetwork> Networks
{
get
{
Dictionary<string, ZeroTierNetwork> networks = new Dictionary<string, ZeroTierNetwork>();
var p = Run("listnetworks");
var lines = Regex.Split(p.StandardOutput.ReadToEnd(), "\n").Skip(1);
foreach (var line in lines)
{
var l = line.Replace("\r", "");
if (!string.IsNullOrWhiteSpace(l))
{
var n = new ZeroTierNetwork(l);
networks.Add(n.ID, n);
}
}
return networks;
}
}
private static Process Run(string args)
{
var p = new Process();
p.StartInfo = new ProcessStartInfo()
{
FileName = _path,
Arguments = _arg + args,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
};
p.Start();
p.WaitForExit();
return p;
}
private static string RunCommand(string command)
{
var p = Run(command);
return p.StandardOutput.ReadToEnd() + p.StandardError.ReadToEnd();
}
public static void Check()
{
}
}
}

View File

@ -0,0 +1,71 @@
using GTA.Math;
using Lidgren.Network;
using System;
using System.Collections.Generic;
using System.Text;
namespace RageCoop.Core
{
internal static class PacketExtensions
{
#region MESSAGE-READ
public static Vector3 ReadVector3(this NetIncomingMessage m)
{
return new Vector3
{
X = m.ReadFloat(),
Y = m.ReadFloat(),
Z = m.ReadFloat(),
};
}
public static Vector2 ReadVector2(this NetIncomingMessage m)
{
return new Vector2
{
X = m.ReadFloat(),
Y = m.ReadFloat(),
};
}
public static Quaternion ReadQuaternion(this NetIncomingMessage m)
{
return new Quaternion
{
X = m.ReadFloat(),
Y = m.ReadFloat(),
Z = m.ReadFloat(),
W = m.ReadFloat(),
};
}
public static byte[] ReadByteArray(this NetIncomingMessage m)
{
return m.ReadBytes(m.ReadInt32());
}
#endregion
#region MESSAGE-WRITE
public static void Write(this NetOutgoingMessage m, Vector3 v)
{
m.Write(v.X);
m.Write(v.Y);
m.Write(v.Z);
}
public static void Write(this NetOutgoingMessage m, Quaternion q)
{
m.Write(q.X);
m.Write(q.Y);
m.Write(q.Z);
m.Write(q.W);
}
public static void WriteByteArray(this NetOutgoingMessage m, byte[] b)
{
m.Write(b.Length);
m.Write(b);
}
#endregion
internal static bool IsSyncEvent(this PacketType p)
{
return (30 <= (byte)p) && ((byte)p <= 40);
}
}
}

View File

@ -0,0 +1,56 @@
using Lidgren.Network;
using System;
namespace RageCoop.Core
{
internal partial class Packets
{
internal class ChatMessage : Packet
{
public override PacketType Type => PacketType.ChatMessage;
private readonly Func<string, byte[]> crypt;
private readonly Func<byte[], byte[]> decrypt;
public ChatMessage(Func<string, byte[]> crypter)
{
crypt = crypter;
}
public ChatMessage(Func<byte[], byte[]> decrypter)
{
decrypt = decrypter;
}
public string Username { get; set; }
public string Message { get; set; }
protected override void Serialize(NetOutgoingMessage m)
{
// Write Username
m.Write(Username);
// Write Message
m.WriteByteArray(crypt(Message));
}
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
// Read username
Username = m.ReadString();
Message = decrypt(m.ReadByteArray()).GetString();
#endregion
}
}
}
}

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using Lidgren.Network;
using Lidgren.Network;
using System;
namespace RageCoop.Core
{
internal partial class Packets
@ -9,89 +7,79 @@ namespace RageCoop.Core
internal class CustomEvent : Packet
{
public CustomEvent(Func<byte,BitReader,object> onResolve = null,bool queued=false)
public override PacketType Type => (_queued ? PacketType.CustomEventQueued : PacketType.CustomEvent);
public CustomEvent(Func<byte, NetIncomingMessage, object> onResolve = null, bool queued = false)
{
_resolve= onResolve;
_queued= queued;
_resolve = onResolve;
_queued = queued;
}
private bool _queued;
private Func<byte, BitReader, object> _resolve { get; set; }
private readonly bool _queued;
private Func<byte, NetIncomingMessage, object> _resolve { get; set; }
public int Hash { get; set; }
public bool IsStaged { get; set; }=false;
public object[] Args { get; set; }
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
Args= Args ?? new object[] { };
message.Write(_queued ? (byte)PacketType.CustomEventQueued: (byte)PacketType.CustomEvent);
Args = Args ?? new object[] { };
List<byte> result = new List<byte>();
result.AddInt(Hash);
result.AddInt(Args.Length);
(byte, byte[]) tup;
m.Write(Hash);
m.Write(Args.Length);
foreach (var arg in Args)
{
tup=CoreUtils.GetBytesFromObject(arg);
if (tup.Item1==0||tup.Item2==null)
{
throw new ArgumentException($"Object of type {arg.GetType()} is not supported");
}
result.Add(tup.Item1);
result.AddRange(tup.Item2);
CoreUtils.GetBytesFromObject(arg, m);
}
message.Write(result.Count);
message.Write(result.ToArray());
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
BitReader reader = new BitReader(array);
Hash = reader.ReadInt();
var len=reader.ReadInt();
Args=new object[len];
Hash = m.ReadInt32();
var len = m.ReadInt32();
Args = new object[len];
for (int i = 0; i < len; i++)
{
byte type = reader.ReadByte();
byte type = m.ReadByte();
switch (type)
{
case 0x01:
Args[i]=reader.ReadByte(); break;
Args[i] = m.ReadByte(); break;
case 0x02:
Args[i]=reader.ReadShort(); break;
Args[i] = m.ReadInt32(); break;
case 0x03:
Args[i]=reader.ReadUShort(); break;
Args[i] = m.ReadUInt16(); break;
case 0x04:
Args[i]=reader.ReadInt(); break;
Args[i] = m.ReadInt32(); break;
case 0x05:
Args[i]=reader.ReadUInt(); break;
Args[i] = m.ReadUInt32(); break;
case 0x06:
Args[i]=reader.ReadLong(); break;
Args[i] = m.ReadInt64(); break;
case 0x07:
Args[i]=reader.ReadULong(); break;
Args[i] = m.ReadUInt64(); break;
case 0x08:
Args[i]=reader.ReadFloat(); break;
Args[i] = m.ReadFloat(); break;
case 0x09:
Args[i]=reader.ReadBool(); break;
Args[i] = m.ReadBoolean(); break;
case 0x10:
Args[i]=reader.ReadString(); break;
case 0x11:
Args[i]=reader.ReadVector3(); break;
Args[i] = m.ReadString(); break;
case 0x11:
Args[i] = m.ReadVector3(); break;
case 0x12:
Args[i]=reader.ReadQuaternion(); break;
Args[i] = m.ReadQuaternion(); break;
case 0x13:
Args[i]=(GTA.Model)reader.ReadInt(); break;
Args[i] = (GTA.Model)m.ReadInt32(); break;
case 0x14:
Args[i]=reader.ReadVector2(); break;
Args[i] = m.ReadVector2(); break;
case 0x15:
Args[i] = m.ReadByteArray(); break;
default:
if (_resolve==null)
if (_resolve == null)
{
throw new InvalidOperationException($"Unexpected type:{type}\r\n{array.Dump()}");
throw new InvalidOperationException($"Unexpected type: {type}");
}
else
{
Args[i]=_resolve(type, reader); break;
Args[i] = _resolve(type, m); break;
}
}
}

View File

@ -1,183 +1,127 @@
using System;
using System.Collections.Generic;
using System.Text;

using Lidgren.Network;
namespace RageCoop.Core
{
internal enum FileResponse:byte
internal enum FileResponse : byte
{
NeedToDownload=0,
AlreadyExists=1,
Completed=2,
Loaded=3,
LoadFailed=4,
NeedToDownload = 0,
AlreadyExists = 1,
Completed = 2,
Loaded = 3,
LoadFailed = 4,
}
internal partial class Packets
{
internal class FileTransferRequest : Packet
{
public override PacketType Type => PacketType.FileTransferRequest;
public int ID { get; set; }
public string Name { get; set; }
public long FileLength { get; set; }
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.FileTransferRequest);
List<byte> byteArray = new List<byte>();
// The ID from the download
byteArray.AddInt(ID);
m.Write(ID);
// The name of the file
byte[] nameBytes = Encoding.UTF8.GetBytes(Name);
byteArray.AddRange(BitConverter.GetBytes(nameBytes.Length));
byteArray.AddRange(nameBytes);
m.Write(Name);
// The length of the file
byteArray.AddRange(BitConverter.GetBytes(FileLength));
m.Write(FileLength);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
ID = reader.ReadInt();
int nameArrayLength = reader.ReadInt();
Name = reader.ReadString(nameArrayLength);
FileLength = reader.ReadLong();
#endregion
ID = m.ReadInt32();
Name = m.ReadString();
FileLength = m.ReadInt64();
}
}
internal class FileTransferResponse : Packet
{
public override PacketType Type => PacketType.FileTransferResponse;
public int ID { get; set; }
public FileResponse Response { get; set; }
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
message.Write((byte)PacketType.FileTransferResponse);
List<byte> byteArray = new List<byte>();
// The ID from the download
byteArray.AddInt(ID);
m.Write(ID);
byteArray.Add((byte)Response);
m.Write((byte)Response);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
BitReader reader = new BitReader(array);
ID = reader.ReadInt();
Response = (FileResponse)reader.ReadByte();
ID = m.ReadInt32();
Response = (FileResponse)m.ReadByte();
}
}
internal class FileTransferChunk : Packet
{
public override PacketType Type => PacketType.FileTransferChunk;
public int ID { get; set; }
public byte[] FileChunk { get; set; }
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.FileTransferChunk);
List<byte> byteArray = new List<byte>();
// The ID from the download
byteArray.AddInt(ID);
m.Write(ID);
m.WriteByteArray(FileChunk);
// The chunk of the file
byteArray.AddRange(BitConverter.GetBytes(FileChunk.Length));
byteArray.AddRange(FileChunk);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
ID = reader.ReadInt();
int chunkLength = reader.ReadInt();
FileChunk = reader.ReadByteArray(chunkLength);
#endregion
ID = m.ReadInt32();
FileChunk = m.ReadByteArray();
}
}
internal class FileTransferComplete : Packet
{
public override PacketType Type => PacketType.FileTransferComplete;
public int ID { get; set; }
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.FileTransferComplete);
List<byte> byteArray = new List<byte>();
// The ID for the download
byteArray.AddInt(ID);
m.Write(ID);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
ID = reader.ReadInt();
#endregion
ID = m.ReadInt32();
}
}
internal class AllResourcesSent : Packet
{
public override void Pack(NetOutgoingMessage message)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.AllResourcesSent);
message.Write(0);
#endregion
}
public override void Unpack(byte[] array)
{
#region NetIncomingMessageToPacket
#endregion
}
public override PacketType Type => PacketType.AllResourcesSent;
}
}
}

View File

@ -0,0 +1,67 @@
using Lidgren.Network;
namespace RageCoop.Core
{
internal partial class Packets
{
internal class HolePunchInit : Packet
{
public override PacketType Type => PacketType.HolePunchInit;
public int TargetID { get; set; }
public string TargetInternal { get; set; }
public string TargetExternal { get; set; }
public bool Connect { get; set; }
protected override void Serialize(NetOutgoingMessage m)
{
m.Write(TargetID);
m.Write(TargetInternal);
m.Write(TargetExternal);
m.Write(Connect);
}
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
TargetID = m.ReadInt32();
TargetInternal = m.ReadString();
TargetExternal = m.ReadString();
Connect = m.ReadBoolean();
#endregion
}
}
internal class HolePunch : Packet
{
public override PacketType Type => PacketType.HolePunch;
public int Puncher { get; set; }
/// <summary>
/// 1:initial, 2:acknowledged, 3:confirmed
/// </summary>
public byte Status { get; set; }
protected override void Serialize(NetOutgoingMessage m)
{
m.Write(Puncher);
m.Write(Status);
}
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
Puncher = m.ReadInt32();
Status = m.ReadByte();
#endregion
}
}
}
}

View File

@ -0,0 +1,48 @@
using Lidgren.Network;
using System.Collections.Generic;
namespace RageCoop.Core
{
internal partial class Packets
{
/// <summary>
/// Request direct connection to another client
/// </summary>
internal class ConnectionRequest : Packet
{
public int TargetID { get; set; }
public override PacketType Type => PacketType.ConnectionRequest;
protected override void Serialize(NetOutgoingMessage m)
{
var data = new List<byte>(10);
m.Write(TargetID);
}
public override void Deserialize(NetIncomingMessage m)
{
TargetID = m.ReadInt32();
}
}
/// <summary>
/// Sent to the host when a direct connection has been established
/// </summary>
internal class P2PConnect : Packet
{
public int ID { get; set; }
public override PacketType Type => PacketType.P2PConnect;
protected override void Serialize(NetOutgoingMessage m)
{
var data = new List<byte>(10);
m.Write(ID);
}
public override void Deserialize(NetIncomingMessage m)
{
ID = m.ReadInt32();
}
}
}
}

View File

@ -1,90 +1,77 @@
using System;
using System.Collections.Generic;
using System.Text;
using Lidgren.Network;
using Newtonsoft.Json;
using GTA.Math;
using Lidgren.Network;
using System;
namespace RageCoop.Core
{
internal enum PacketType:byte
internal enum PacketType : byte
{
Handshake=0,
PlayerConnect=1,
PlayerDisconnect=2,
PlayerInfoUpdate=3,
PublicKeyRequest=4,
PublicKeyResponse=5,
Request=6,
Response=7,
ChatMessage=10,
// NativeCall=11,
// NativeResponse=12,
// Mod=13,
// CleanUpWorld=14,
FileTransferChunk=11,
FileTransferRequest=12,
Handshake = 0,
PlayerConnect = 1,
PlayerDisconnect = 2,
PlayerInfoUpdate = 3,
PublicKeyRequest = 4,
PublicKeyResponse = 5,
Request = 6,
Response = 7,
PingPong = 8,
HandshakeSuccess = 9,
ChatMessage = 10,
FileTransferChunk = 11,
FileTransferRequest = 12,
FileTransferResponse = 13,
FileTransferComplete =14,
AllResourcesSent=15,
FileTransferComplete = 14,
AllResourcesSent = 15,
CustomEvent = 16,
CustomEventQueued = 17,
#region Sync
#region INTERVAL
VehicleSync = 20,
VehicleStateSync = 21,
PedSync = 22,
PedStateSync = 23,
ProjectileSync=24,
ConnectionRequest = 18,
P2PConnect = 19,
HolePunchInit = 20,
HolePunch = 21,
Voice = 22,
#region Sync
PedSync = 23,
VehicleSync = 24,
ProjectileSync = 25,
#endregion
#region EVENT
PedKilled=30,
BulletShot=31,
EnteringVehicle=32,
LeaveVehicle = 33,
EnteredVehicle=34,
OwnerChanged=35,
VehicleBulletShot = 36,
NozzleTransform=37,
PedKilled = 30,
BulletShot = 31,
VehicleBulletShot = 32,
OwnerChanged = 35,
NozzleTransform = 37,
#endregion
#endregion
Unknown=255
Unknown = 255
}
internal static class PacketExtensions
{
internal static bool IsSyncEvent(this PacketType p)
{
return (30<=(byte)p)&&((byte)p<=40);
}
}
internal enum ConnectionChannel
{
Default = 0,
Chat = 5,
Native = 6,
Mod = 7,
File = 8,
Event = 9,
RequestResponse=10,
VehicleSync=20,
PedSync=21,
ProjectileSync = 22,
SyncEvents =30,
Chat = 1,
Voice = 2,
Native = 3,
Mod = 4,
File = 5,
Event = 6,
RequestResponse = 7,
PingPong = 8,
VehicleSync = 9,
PedSync = 10,
ProjectileSync = 11,
SyncEvents = 12,
}
[Flags]
internal enum PedDataFlags:ushort
internal enum PedDataFlags : ushort
{
None=0,
None = 0,
IsAiming = 1 << 0,
IsInStealthMode = 1 << 1,
IsReloading = 1 << 2,
@ -96,12 +83,25 @@ namespace RageCoop.Core
IsOnLadder = 1 << 8,
IsVaulting = 1 << 9,
IsInCover = 1 << 10,
IsInLowCover = 1 << 11,
IsInCoverFacingLeft = 1 << 12,
IsBlindFiring = 1 << 13,
IsInvincible = 1 << 14,
IsFullSync = 1 << 15,
}
#region ===== VEHICLE DATA =====
internal enum VehicleDataFlags:ushort
internal enum ProjectileDataFlags : byte
{
None=0,
None = 0,
Exploded = 1 << 0,
IsAttached = 1 << 1,
IsOrgin = 1 << 2,
IsShotByVehicle = 1 << 3,
}
#region ===== VEHICLE DATA =====
internal enum VehicleDataFlags : ushort
{
None = 0,
IsEngineRunning = 1 << 0,
AreLightsOn = 1 << 1,
AreBrakeLightsOn = 1 << 2,
@ -110,18 +110,21 @@ namespace RageCoop.Core
IsDead = 1 << 5,
IsHornActive = 1 << 6,
IsTransformed = 1 << 7,
RoofOpened = 1 << 8,
OnTurretSeat = 1 << 9,
IsParachuteActive = 1 << 8,
IsRocketBoostActive = 1 << 9,
IsAircraft = 1 << 10,
IsDeluxoHovering=1 << 11,
HasRoof=1 << 12,
IsDeluxoHovering = 1 << 11,
HasRoof = 1 << 12,
IsFullSync = 1 << 13,
IsOnFire = 1 << 14,
Repaired = 1 << 15,
}
internal enum PlayerConfigFlags : byte
{
None = 0,
ShowBlip= 1 << 0,
ShowNameTag= 1 << 1
ShowBlip = 1 << 0,
ShowNameTag = 1 << 1
}
internal struct VehicleDamageModel
@ -135,101 +138,22 @@ namespace RageCoop.Core
}
#endregion
interface IPacket
internal interface IPacket
{
void Pack(NetOutgoingMessage message);
void Unpack(byte[] array);
PacketType Type { get; }
void Deserialize(NetIncomingMessage m);
}
internal abstract class Packet : IPacket
{
public abstract void Pack(NetOutgoingMessage message);
public abstract void Unpack(byte[] array);
}
internal partial class Packets
{
internal class ChatMessage : Packet
public abstract PacketType Type { get; }
public void Pack(NetOutgoingMessage m)
{
public string Username { get; set; }
public string Message { get; set; }
public override void Pack(NetOutgoingMessage message)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.ChatMessage);
List<byte> byteArray = new List<byte>();
byte[] usernameBytes = Encoding.UTF8.GetBytes(Username);
byte[] messageBytes = Encoding.UTF8.GetBytes(Message);
// Write UsernameLength
byteArray.AddRange(BitConverter.GetBytes(usernameBytes.Length));
// Write Username
byteArray.AddRange(usernameBytes);
// Write MessageLength
byteArray.AddRange(BitConverter.GetBytes(messageBytes.Length));
// Write Message
byteArray.AddRange(messageBytes);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read username
int usernameLength = reader.ReadInt();
Username = reader.ReadString(usernameLength);
// Read message
int messageLength = reader.ReadInt();
Message = reader.ReadString(messageLength);
#endregion
}
}
}
internal static class CoopSerializer
{
/// <summary>
/// ?
/// </summary>
public static byte[] Serialize(this object obj)
{
if (obj == null)
{
return null;
}
string jsonString = JsonConvert.SerializeObject(obj);
return System.Text.Encoding.UTF8.GetBytes(jsonString);
}
/// <summary>
/// ?
/// </summary>
public static T Deserialize<T>(this byte[] bytes) where T : class
{
if (bytes == null)
{
return null;
}
var jsonString = System.Text.Encoding.UTF8.GetString(bytes);
return JsonConvert.DeserializeObject<T>(jsonString);
m.Write((byte)Type);
Serialize(m);
}
protected virtual void Serialize(NetOutgoingMessage m) { }
public virtual void Deserialize(NetIncomingMessage m) { }
}
}

View File

@ -1,251 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using GTA.Math;
using GTA;
using Lidgren.Network;
namespace RageCoop.Core
{
internal partial class Packets
{
/// <summary>
/// For non-critical properties, synced every 20 frames.
/// </summary>
internal class PedStateSync : Packet
{
public int ID { get; set; }
public int ModelHash { get; set; }
public byte[] Clothes { get; set; }
public int OwnerID { get; set; }
public Dictionary<uint, bool> WeaponComponents { get; set; }
public byte WeaponTint { get;set; }
public BlipColor BlipColor { get; set; } = (BlipColor)255;
public BlipSprite BlipSprite { get; set; }= 0;
public float BlipScale { get; set; } = 1;
public override void Pack(NetOutgoingMessage message)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.PedStateSync);
List<byte> byteArray = new List<byte>();
// Write ID
byteArray.AddInt(ID);
// Write model hash
byteArray.AddInt(ModelHash);
byteArray.AddRange(Clothes);
//Write OwnerID for this ped
byteArray.AddRange(BitConverter.GetBytes(OwnerID));
// Write player weapon components
if (WeaponComponents != null)
{
byteArray.Add(0x01);
byteArray.AddRange(BitConverter.GetBytes((ushort)WeaponComponents.Count));
foreach (KeyValuePair<uint, bool> component in WeaponComponents)
{
byteArray.AddRange(BitConverter.GetBytes(component.Key));
byteArray.AddRange(BitConverter.GetBytes(component.Value));
}
}
else
{
// Player weapon doesn't have any components
byteArray.Add(0x00);
}
byteArray.Add(WeaponTint);
byteArray.Add((byte)BlipColor);
if ((byte)BlipColor!=255)
{
byteArray.AddUshort((ushort)BlipSprite);
byteArray.AddFloat(BlipScale);
}
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read player netHandle
ID = reader.ReadInt();
// Read player model hash
ModelHash = reader.ReadInt();
// Read player clothes
Clothes =reader.ReadByteArray(36);
// Read ped OwnerID
OwnerID= reader.ReadInt();
// Read player weapon components
if (reader.ReadBool())
{
WeaponComponents = new Dictionary<uint, bool>();
ushort comCount = reader.ReadUShort();
for (ushort i = 0; i < comCount; i++)
{
WeaponComponents.Add(reader.ReadUInt(), reader.ReadBool());
}
}
WeaponTint=reader.ReadByte();
BlipColor=(BlipColor)reader.ReadByte();
if ((byte)BlipColor!=255)
{
BlipSprite=(BlipSprite)reader.ReadUShort();
BlipScale=reader.ReadFloat();
}
#endregion
}
}
internal class PedSync : Packet
{
public int ID { get; set; }
public PedDataFlags Flag { get; set; }
public int Health { get; set; }
public Vector3 Position { get; set; }
public Vector3 Rotation { get; set; }
public Vector3 Velocity { get; set; }
public Vector3 RotationVelocity { get; set; }
public byte Speed { get; set; }
public Vector3 AimCoords { get; set; }
public uint CurrentWeaponHash { get; set; }
public float Heading { get; set; }
public override void Pack(NetOutgoingMessage message)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.PedSync);
List<byte> byteArray = new List<byte>();
// Write ped ID
byteArray.AddInt(ID);
// Write ped flags
byteArray.AddRange(BitConverter.GetBytes((ushort)Flag));
// Write ped health
byteArray.AddRange(BitConverter.GetBytes(Health));
// Write ped position
byteArray.AddVector3(Position);
// Write ped rotation
byteArray.AddVector3(Rotation);
// Write ped velocity
byteArray.AddVector3(Velocity);
if (Flag.HasPedFlag(PedDataFlags.IsRagdoll))
{
byteArray.AddVector3(RotationVelocity);
}
// Write ped speed
byteArray.Add(Speed);
// Write ped weapon hash
byteArray.AddRange(BitConverter.GetBytes(CurrentWeaponHash));
if (Flag.HasPedFlag(PedDataFlags.IsAiming))
{
// Write ped aim coords
byteArray.AddVector3(AimCoords);
}
byteArray.AddFloat(Heading);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read player netHandle
ID = reader.ReadInt();
// Read player flags
Flag = (PedDataFlags)reader.ReadUShort();
// Read player health
Health = reader.ReadInt();
// Read player position
Position = reader.ReadVector3();
// Read player rotation
Rotation = reader.ReadVector3();
// Read player velocity
Velocity = reader.ReadVector3();
// Read rotation velocity if in ragdoll
if (Flag.HasPedFlag(PedDataFlags.IsRagdoll))
{
RotationVelocity=reader.ReadVector3();
}
// Read player speed
Speed = reader.ReadByte();
// Read player weapon hash
CurrentWeaponHash = reader.ReadUInt();
// Try to read aim coords
if (Flag.HasPedFlag(PedDataFlags.IsAiming))
{
// Read player aim coords
AimCoords = reader.ReadVector3();
}
Heading=reader.ReadFloat();
#endregion
}
}
}
}

View File

@ -0,0 +1,213 @@
using GTA;
using GTA.Math;
using Lidgren.Network;
using System.Collections.Generic;
namespace RageCoop.Core
{
internal partial class Packets
{
internal class PedSync : Packet
{
public override PacketType Type => PacketType.PedSync;
public int ID { get; set; }
public int OwnerID { get; set; }
public int VehicleID { get; set; }
public VehicleSeat Seat { get; set; }
public PedDataFlags Flags { get; set; }
public int Health { get; set; }
public Vector3 Position { get; set; }
public Vector3 Rotation { get; set; }
public Vector3 Velocity { get; set; }
#region RAGDOLL
public Vector3 HeadPosition { get; set; }
public Vector3 RightFootPosition { get; set; }
public Vector3 LeftFootPosition { get; set; }
#endregion
public byte Speed { get; set; }
public Vector3 AimCoords { get; set; }
public float Heading { get; set; }
#region FULL
public int ModelHash { get; set; }
public uint CurrentWeaponHash { get; set; }
public byte[] Clothes { get; set; }
public Dictionary<uint, bool> WeaponComponents { get; set; }
public byte WeaponTint { get; set; }
public BlipColor BlipColor { get; set; } = (BlipColor)255;
public BlipSprite BlipSprite { get; set; } = 0;
public float BlipScale { get; set; } = 1;
#endregion
protected override void Serialize(NetOutgoingMessage m)
{
m.Write(ID);
m.Write(OwnerID);
m.Write((ushort)Flags);
m.Write(Health);
m.Write(Speed);
if (Flags.HasPedFlag(PedDataFlags.IsRagdoll))
{
m.Write(HeadPosition);
m.Write(RightFootPosition);
m.Write(LeftFootPosition);
}
else
{
if (Speed >= 4)
{
m.Write(VehicleID);
m.Write((byte)(Seat + 3));
}
m.Write(Position);
}
m.Write(Rotation);
m.Write(Velocity);
if (Flags.HasPedFlag(PedDataFlags.IsAiming))
{
m.Write(AimCoords);
}
m.Write(Heading);
if (Flags.HasPedFlag(PedDataFlags.IsFullSync))
{
m.Write(ModelHash);
m.Write(CurrentWeaponHash);
m.Write(Clothes);
if (WeaponComponents != null)
{
m.Write(true);
m.Write((ushort)WeaponComponents.Count);
foreach (KeyValuePair<uint, bool> component in WeaponComponents)
{
m.Write(component.Key);
m.Write(component.Value);
}
}
else
{
// Player weapon doesn't have any components
m.Write(false);
}
m.Write(WeaponTint);
m.Write((byte)BlipColor);
if ((byte)BlipColor != 255)
{
m.Write((ushort)BlipSprite);
m.Write(BlipScale);
}
}
}
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
ID = m.ReadInt32();
OwnerID = m.ReadInt32();
Flags = (PedDataFlags)m.ReadUInt16();
Health = m.ReadInt32();
Speed = m.ReadByte();
if (Flags.HasPedFlag(PedDataFlags.IsRagdoll))
{
HeadPosition = m.ReadVector3();
RightFootPosition = m.ReadVector3();
LeftFootPosition = m.ReadVector3();
Position = HeadPosition;
}
else
{
// Vehicle related
if (Speed >= 4)
{
VehicleID = m.ReadInt32();
Seat = (VehicleSeat)(m.ReadByte() - 3);
}
// Read player position
Position = m.ReadVector3();
}
Rotation = m.ReadVector3();
Velocity = m.ReadVector3();
if (Flags.HasPedFlag(PedDataFlags.IsAiming))
{
// Read player aim coords
AimCoords = m.ReadVector3();
}
Heading = m.ReadFloat();
if (Flags.HasPedFlag(PedDataFlags.IsFullSync))
{
// Read player model hash
ModelHash = m.ReadInt32();
// Read player weapon hash
CurrentWeaponHash = m.ReadUInt32();
// Read player clothes
Clothes = m.ReadBytes(36);
// Read player weapon components
if (m.ReadBoolean())
{
WeaponComponents = new Dictionary<uint, bool>();
ushort comCount = m.ReadUInt16();
for (ushort i = 0; i < comCount; i++)
{
WeaponComponents.Add(m.ReadUInt32(), m.ReadBoolean());
}
}
WeaponTint = m.ReadByte();
BlipColor = (BlipColor)m.ReadByte();
if ((byte)BlipColor != 255)
{
BlipSprite = (BlipSprite)m.ReadUInt16();
BlipScale = m.ReadFloat();
}
}
#endregion
}
}
}
}

View File

@ -1,15 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
using GTA.Math;
using Lidgren.Network;
using System.Net;
namespace RageCoop.Core
{
internal partial class Packets
{
internal class Handshake : Packet
internal struct PlayerData
{
public int ID;
public string Username;
}
public class Handshake : Packet
{
public override PacketType Type => PacketType.Handshake;
public int PedID { get; set; }
public string Username { get; set; }
@ -29,227 +33,209 @@ namespace RageCoop.Core
/// <summary>
/// The password hash with client Aes
/// </summary>
public byte[] PassHashEncrypted { get; set; }
public byte[] PasswordEncrypted { get; set; }
public override void Pack(NetOutgoingMessage message)
public IPEndPoint InternalEndPoint { get; set; }
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.Handshake);
List<byte> byteArray = new List<byte>();
// Write Player Ped ID
byteArray.AddRange(BitConverter.GetBytes(PedID));
m.Write(PedID);
// Write Username
byte[] usernameBytes = Encoding.UTF8.GetBytes(Username);
byteArray.AddRange(BitConverter.GetBytes(usernameBytes.Length));
byteArray.AddRange(usernameBytes);
m.Write(Username);
// Write ModVersion
byte[] modVersionBytes = Encoding.UTF8.GetBytes(ModVersion);
byteArray.AddRange(BitConverter.GetBytes(modVersionBytes.Length));
byteArray.AddRange(modVersionBytes);
m.Write(ModVersion);
m.Write(InternalEndPoint.ToString());
// Write AesKeyCrypted
byteArray.AddArray(AesKeyCrypted);
m.WriteByteArray(AesKeyCrypted);
// Write AesIVCrypted
byteArray.AddArray(AesIVCrypted);
m.WriteByteArray(AesIVCrypted);
// Write PassHash
byteArray.AddArray(PassHashEncrypted);
m.WriteByteArray(PasswordEncrypted);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read player netHandle
PedID = reader.ReadInt();
PedID = m.ReadInt32();
// Read Username
Username = reader.ReadString(reader.ReadInt());
Username = m.ReadString();
// Read ModVersion
ModVersion = reader.ReadString(reader.ReadInt());
ModVersion = m.ReadString();
AesKeyCrypted=reader.ReadByteArray();
InternalEndPoint = CoreUtils.StringToEndPoint(m.ReadString());
AesIVCrypted=reader.ReadByteArray();
AesKeyCrypted = m.ReadByteArray();
AesIVCrypted = m.ReadByteArray();
PassHashEncrypted=reader.ReadByteArray();
PasswordEncrypted = m.ReadByteArray();
#endregion
}
}
public class HandshakeSuccess : Packet
{
public PlayerData[] Players { get; set; }
public override PacketType Type => PacketType.HandshakeSuccess;
protected override void Serialize(NetOutgoingMessage m)
{
m.Write(Players.Length);
foreach (var p in Players)
{
m.Write(p.ID);
m.Write(p.Username);
}
}
public override void Deserialize(NetIncomingMessage m)
{
Players = new PlayerData[m.ReadInt32()];
for (int i = 0; i < Players.Length; i++)
{
Players[i] = new PlayerData()
{
ID = m.ReadInt32(),
Username = m.ReadString(),
};
}
}
}
public class PlayerConnect : Packet
{
public override PacketType Type => PacketType.PlayerConnect;
public int PedID { get; set; }
public string Username { get; set; }
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.PlayerConnect);
List<byte> byteArray = new List<byte>();
// Write NetHandle
byteArray.AddRange(BitConverter.GetBytes(PedID));
m.Write(PedID);
// Get Username bytes
byte[] usernameBytes = Encoding.UTF8.GetBytes(Username);
// Write UsernameLength
byteArray.AddRange(BitConverter.GetBytes(usernameBytes.Length));
// Write Username
byteArray.AddRange(usernameBytes);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
m.Write(Username);
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read player netHandle
PedID = reader.ReadInt();
PedID = m.ReadInt32();
// Read Username
int usernameLength = reader.ReadInt();
Username = reader.ReadString(usernameLength);
Username = m.ReadString();
#endregion
}
}
public class PlayerDisconnect : Packet
{
public override PacketType Type => PacketType.PlayerDisconnect;
public int PedID { get; set; }
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.PlayerDisconnect);
List<byte> byteArray = new List<byte>();
m.Write(PedID);
byteArray.AddRange(BitConverter.GetBytes(PedID));
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
PedID = reader.ReadInt();
PedID = m.ReadInt32();
#endregion
}
}
public class PlayerInfoUpdate : Packet
{
public override PacketType Type => PacketType.PlayerInfoUpdate;
/// <summary>
/// Ped ID for this Player
/// </summary>
public int PedID { get; set; }
public string Username { get; set; }
public float Latency { get; set; }
public override void Pack(NetOutgoingMessage message)
public Vector3 Position { get; set; }
public bool IsHost;
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.PlayerInfoUpdate);
List<byte> byteArray = new List<byte>();
// Write ID
byteArray.AddRange(BitConverter.GetBytes(PedID));
// Get Username bytes
byte[] usernameBytes = Encoding.UTF8.GetBytes(Username);
// Write UsernameLength
byteArray.AddRange(BitConverter.GetBytes(usernameBytes.Length));
m.Write(PedID);
// Write Username
byteArray.AddRange(usernameBytes);
m.Write(Username);
// Write Latency
byteArray.AddFloat(Latency);
m.Write(Latency);
byte[] result = byteArray.ToArray();
m.Write(Position);
message.Write(result.Length);
message.Write(result);
#endregion
m.Write(IsHost);
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
BitReader reader = new BitReader(array);
// Read player ID
PedID = reader.ReadInt();
PedID = m.ReadInt32();
// Read Username
int usernameLength = reader.ReadInt();
Username = reader.ReadString(usernameLength);
Username = m.ReadString();
Latency=reader.ReadFloat();
Latency = m.ReadFloat();
Position = m.ReadVector3();
IsHost = m.ReadBoolean();
}
}
public class PublicKeyResponse : Packet
{
public override PacketType Type => PacketType.PublicKeyResponse;
public byte[] Modulus;
public byte[] Exponent;
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.PublicKeyResponse);
List<byte> byteArray = new List<byte>();
byteArray.AddArray(Modulus);
byteArray.AddArray(Exponent);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
m.WriteByteArray(Modulus);
m.WriteByteArray(Exponent);
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
var reader=new BitReader(array);
Modulus=reader.ReadByteArray();
Exponent=reader.ReadByteArray();
Modulus = m.ReadByteArray();
Exponent = m.ReadByteArray();
#endregion
}
@ -257,15 +243,7 @@ namespace RageCoop.Core
public class PublicKeyRequest : Packet
{
public override void Pack(NetOutgoingMessage message)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.PublicKeyRequest);
#endregion
}
public override void Unpack(byte[] array)
{
}
public override PacketType Type => PacketType.PublicKeyRequest;
}
}
}

View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using GTA.Math;
using GTA.Math;
using Lidgren.Network;
namespace RageCoop.Core
@ -10,7 +7,7 @@ namespace RageCoop.Core
{
internal class ProjectileSync : Packet
{
public override PacketType Type => PacketType.ProjectileSync;
public int ID { get; set; }
public int ShooterID { get; set; }
@ -22,70 +19,61 @@ namespace RageCoop.Core
public Vector3 Velocity { get; set; }
public bool Exploded { get; set; }
public ProjectileDataFlags Flags { get; set; }
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.ProjectileSync);
List<byte> byteArray = new List<byte>();
// Write id
byteArray.AddInt(ID);
m.Write(ID);
// Write ShooterID
byteArray.AddInt(ShooterID);
m.Write(ShooterID);
byteArray.AddUint(WeaponHash);
m.Write(WeaponHash);
// Write position
byteArray.AddVector3(Position);
m.Write(Position);
// Write rotation
byteArray.AddVector3(Rotation);
m.Write(Rotation);
// Write velocity
byteArray.AddVector3(Velocity);
m.Write(Velocity);
m.Write((byte)Flags);
if (Exploded) { byteArray.Add(1); }
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read id
ID = reader.ReadInt();
ID = m.ReadInt32();
// Read ShooterID
ShooterID= reader.ReadInt();
ShooterID = m.ReadInt32();
WeaponHash= reader.ReadUInt();
WeaponHash = m.ReadUInt32();
// Read position
Position = reader.ReadVector3();
Position = m.ReadVector3();
// Read rotation
Rotation = reader.ReadVector3();
Rotation = m.ReadVector3();
// Read velocity
Velocity =reader.ReadVector3();
Velocity = m.ReadVector3();
if (reader.CanRead(1))
{
Exploded=true;
}
Flags = (ProjectileDataFlags)m.ReadByte();
#endregion
}

View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using GTA.Math;
using GTA.Math;
using Lidgren.Network;
namespace RageCoop.Core
@ -11,6 +8,7 @@ namespace RageCoop.Core
internal class BulletShot : Packet
{
public override PacketType Type => PacketType.BulletShot;
public int OwnerID { get; set; }
public uint WeaponHash { get; set; }
@ -18,49 +16,44 @@ namespace RageCoop.Core
public Vector3 StartPosition { get; set; }
public Vector3 EndPosition { get; set; }
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.BulletShot);
List<byte> byteArray = new List<byte>();
// Write OwnerID
byteArray.AddRange(BitConverter.GetBytes(OwnerID));
m.Write(OwnerID);
// Write weapon hash
byteArray.AddRange(BitConverter.GetBytes(WeaponHash));
m.Write(WeaponHash);
// Write StartPosition
byteArray.AddVector3(StartPosition);
m.Write(StartPosition);
// Write EndPosition
byteArray.AddVector3(EndPosition);
m.Write(EndPosition);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read OwnerID
OwnerID=reader.ReadInt();
OwnerID = m.ReadInt32();
// Read WeponHash
WeaponHash=reader.ReadUInt();
WeaponHash = m.ReadUInt32();
// Read StartPosition
StartPosition=reader.ReadVector3();
StartPosition = m.ReadVector3();
// Read EndPosition
EndPosition=reader.ReadVector3();
EndPosition = m.ReadVector3();
#endregion
}
}

View File

@ -1,54 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Lidgren.Network;
namespace RageCoop.Core
{
internal partial class Packets
{
internal class EnteredVehicle : Packet
{
public int PedID { get; set; }
public int VehicleID { get; set; }
public short VehicleSeat { get; set; }
public override void Pack(NetOutgoingMessage message)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.EnteredVehicle);
List<byte> byteArray = new List<byte>();
byteArray.AddInt(PedID);
byteArray.AddInt(VehicleID);
byteArray.AddInt(VehicleSeat);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
PedID=reader.ReadInt();
VehicleID=reader.ReadInt();
VehicleSeat=reader.ReadShort();
#endregion
}
}
}
}

View File

@ -1,54 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Lidgren.Network;
namespace RageCoop.Core
{
internal partial class Packets
{
internal class EnteringVehicle : Packet
{
public int PedID { get; set; }
public int VehicleID { get; set; }
public short VehicleSeat { get; set; }
public override void Pack(NetOutgoingMessage message)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.EnteringVehicle);
List<byte> byteArray = new List<byte>();
byteArray.AddInt(PedID);
byteArray.AddInt(VehicleID);
byteArray.AddInt(VehicleSeat);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
PedID=reader.ReadInt();
VehicleID=reader.ReadInt();
VehicleSeat=reader.ReadShort();
#endregion
}
}
}
}

View File

@ -1,48 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Lidgren.Network;
namespace RageCoop.Core
{
internal partial class Packets
{
internal class LeaveVehicle : Packet
{
public int ID { get; set; }
public override void Pack(NetOutgoingMessage message)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.LeaveVehicle);
List<byte> byteArray = new List<byte>();
byteArray.AddInt(ID);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
ID=reader.ReadInt();
#endregion
}
}
}
}

View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;

using Lidgren.Network;
namespace RageCoop.Core
@ -10,34 +7,30 @@ namespace RageCoop.Core
{
internal class NozzleTransform : Packet
{
public override PacketType Type => PacketType.NozzleTransform;
public int VehicleID { get; set; }
public bool Hover { get; set; }
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.NozzleTransform);
List<byte> byteArray = new List<byte>();
byteArray.AddInt(VehicleID);
if (Hover) { byteArray.Add(1); }
byte[] result = byteArray.ToArray();
m.Write(VehicleID);
m.Write(Hover);
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
VehicleID=reader.ReadInt();
Hover=reader.CanRead(1);
VehicleID = m.ReadInt32();
Hover = m.ReadBoolean();
#endregion
}
}

View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;

using Lidgren.Network;
namespace RageCoop.Core
@ -11,35 +8,25 @@ namespace RageCoop.Core
internal class OwnerChanged : Packet
{
public override PacketType Type => PacketType.OwnerChanged;
public int ID { get; set; }
public int NewOwnerID { get; set; }
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.OwnerChanged);
List<byte> byteArray = new List<byte>();
byteArray.AddInt(ID);
byteArray.AddInt(NewOwnerID);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
m.Write(ID);
m.Write(NewOwnerID);
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
ID=reader.ReadInt();
NewOwnerID=reader.ReadInt();
ID = m.ReadInt32();
NewOwnerID = m.ReadInt32();
#endregion
}
}

View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;

using Lidgren.Network;
namespace RageCoop.Core
@ -11,29 +8,25 @@ namespace RageCoop.Core
internal class PedKilled : Packet
{
public override PacketType Type => PacketType.PedKilled;
public int VictimID { get; set; }
public override void Pack(NetOutgoingMessage message)
protected override void Serialize(NetOutgoingMessage m)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketType.PedKilled);
List<byte> byteArray = new List<byte>();
byteArray.AddInt(VictimID);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
m.Write(VictimID);
}
public override void Unpack(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
VictimID=reader.ReadInt();
VictimID = m.ReadInt32();
#endregion
}

View File

@ -0,0 +1,52 @@
using GTA.Math;
using Lidgren.Network;
namespace RageCoop.Core
{
internal partial class Packets
{
internal class VehicleBulletShot : Packet
{
public override PacketType Type => PacketType.VehicleBulletShot;
public int OwnerID { get; set; }
public ushort Bone { get; set; }
public uint WeaponHash { get; set; }
public Vector3 StartPosition { get; set; }
public Vector3 EndPosition { get; set; }
protected override void Serialize(NetOutgoingMessage m)
{
m.Write(OwnerID);
m.Write(Bone);
m.Write(WeaponHash);
m.Write(StartPosition);
m.Write(EndPosition);
}
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
OwnerID = m.ReadInt32();
Bone = m.ReadUInt16();
WeaponHash = m.ReadUInt32();
StartPosition = m.ReadVector3();
EndPosition = m.ReadVector3();
#endregion
}
}
}
}

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