Compare commits
492 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 564d1467f6 | |||
| 8bd6ea15a3 | |||
| 3c7f16f7a4 | |||
| 393a401860 | |||
| 39b780e518 | |||
| 4a54851c51 | |||
| f0eefa575c | |||
| 3fc813b2d8 | |||
| fbff72ff14 | |||
| 4e52407591 | |||
| 4e6fde129d | |||
| 92e1a970a8 | |||
| d0eb0b7818 | |||
| 14151d7b2c | |||
| 1f8d70a520 | |||
| 2cb5baf5f7 | |||
| 34e33937e2 | |||
| 9287aba0f9 | |||
| e88e903096 | |||
| 99642fd40c | |||
| 2fbf06b504 | |||
| 13b771ec9f | |||
| 3b987f59e0 | |||
| de96f29097 | |||
| 6136cbfc14 | |||
| ed145aedd6 | |||
| 3f3b5fd2d0 | |||
| 9173e9a99e | |||
| 6e64c458df | |||
| 76f959abe9 | |||
| f2e85d66ab | |||
| e30ef1f4bd | |||
| 6e8f6e78f6 | |||
| f28c83ccbd | |||
| a83821b3d2 | |||
| 3b5436064e | |||
| c4b321324e | |||
| ba8d525ddf | |||
| 884e2f39f0 | |||
| 76c529f1d1 | |||
| df0064bd38 | |||
| f1fc96bbd7 | |||
| 23e9326f5f | |||
| 4621fb4987 | |||
| 6c82895fa7 | |||
| 84b040766f | |||
| f44558cd3b | |||
| accdbbcbc6 | |||
| 2d4107f35e | |||
| bac53fd769 | |||
| 8f63fee5b5 | |||
| 8d0ad0b600 | |||
| dc08c0c1f6 | |||
| faaa856aa5 | |||
| eab64f9254 | |||
| 6c936cb8f9 | |||
| 83a37f8556 | |||
| bb4eacce26 | |||
| d5b71db5d4 | |||
| 89ebd0305c | |||
| b209202292 | |||
| f199241ed8 | |||
| 50229116a7 | |||
| f192caeae1 | |||
| 6005b2ba11 | |||
| 6e213611cc | |||
| 347d65af62 | |||
| 636ee3a33f | |||
| 8ff08e0804 | |||
| 6d7fe58719 | |||
| c7e14ef191 | |||
| 39eb5ef80a | |||
| d25c2539e0 | |||
| eb31a33104 | |||
| 8b3f8ffd9b | |||
| cca09c4178 | |||
| 871bb7e64e | |||
| 02da3ce8af | |||
| 711ba62fc2 | |||
| 8f7d3135db | |||
| cb563a1bf8 | |||
| a84ab42a42 | |||
| b3e285f92f | |||
| 01433f0de6 | |||
| c034cd8aa9 | |||
| 363c2ccb00 | |||
| 7380c162be | |||
| f1c7192029 | |||
| 6720636d48 | |||
| 2af9482da9 | |||
| bf22c17bba | |||
| 01492a0c55 | |||
| c17b234057 | |||
| 739577bbf1 | |||
| 2d2da624e4 | |||
| 9e66762061 | |||
| 84d578366a | |||
| 03bc3a7742 | |||
| 5bfc7f836e | |||
| 54977c79f1 | |||
| 0352bfa328 | |||
| 6fbc386b45 | |||
| 203e3b2528 | |||
| c9aa995224 | |||
| c201b94897 | |||
| 87f873d1a5 | |||
| 6c355b109d | |||
| 2ef3012672 | |||
| 7229574ff4 | |||
| eff9fd50b1 | |||
| e2cbf26360 | |||
| b0f448fd5f | |||
| 721c4d3dee | |||
| 87dfc18d91 | |||
| fa4fe2c10f | |||
| 3a088ddbfc | |||
| 52cc9b647c | |||
| 1aa23901d5 | |||
| 52584d5774 | |||
| 62bf15dede | |||
| 722ca16f57 | |||
| 3e61498366 | |||
| 1ff2fa5691 | |||
| 5088973474 | |||
| b63378f4d0 | |||
| f234830c54 | |||
| 5075289657 | |||
| c20118aac1 | |||
| c4312faf4a | |||
| 7566423889 | |||
| be13e0d102 | |||
| 490802862a | |||
| e369a50b89 | |||
| 13a6431248 | |||
| cb73db7146 | |||
| 9dcd6bb363 | |||
| 842e1435f2 | |||
| 4d03f8e371 | |||
| e040d53cc2 | |||
| 22bfa43ec5 | |||
| 7123bea8e5 | |||
| 973f6873e4 | |||
| efb759b9f9 | |||
| ad3ff96f61 | |||
| e156b2195f | |||
| 73a99e033d | |||
| b44d722b5f | |||
| 307b6365f7 | |||
| a49ee19d3d | |||
| 9c5c1da4c9 | |||
| 0348296dc1 | |||
| adb9439226 | |||
| ae10da874b | |||
| cb91486848 | |||
| 3289c03fd2 | |||
| d4ffb0c929 | |||
| 3c089e2c47 | |||
| 7a4e4182b5 | |||
| aa6c45b20d | |||
| 0943a7992f | |||
| d30e1f6bb3 | |||
| 0c71d4dbaa | |||
| c78fbd89bc | |||
| dc83cd5be9 | |||
| b5f6fc578d | |||
| 4acf964f0a | |||
| 560f092304 | |||
| 8305d9997a | |||
| d68941b3ac | |||
| 67c4646198 | |||
| a7dab1e0e1 | |||
| 2b8a3db6bf | |||
| f9609afd8a | |||
| 609fd90561 | |||
| a7d64d241d | |||
| b436abf131 | |||
| c14221f1a3 | |||
| abbc871d1a | |||
| edb8838455 | |||
| 4cca75ee35 | |||
| 669b457275 | |||
| 2ef0060037 | |||
| 55649f26ae | |||
| 6bb7d5d0fd | |||
| 8f5deaa33b | |||
| 91b0afb6ef | |||
| 4dc3cc5c28 | |||
| f9a411833a | |||
| d24d786fd3 | |||
| edae7a075a | |||
| 85b028e3e7 | |||
| 36de46a2ce | |||
| 6e5f72ee70 | |||
| 8d450813e1 | |||
| 495e5dc6b0 | |||
| 0bd1d2c2a7 | |||
| 339f817c7e | |||
| b583618e6c | |||
| dc0fafbe9e | |||
| b9e22a880f | |||
| cb7f0290ec | |||
| d70c739208 | |||
| 29202906e1 | |||
| 1d3e53f734 | |||
| a26a799a9f | |||
| 033d0a3f2e | |||
| 95e302a698 | |||
| ff9e16bd5e | |||
| 01c668b159 | |||
| 74e51c8070 | |||
| 01524b1796 | |||
| 83d79b0a17 | |||
| c3d7c2b335 | |||
| 6b6125eb09 | |||
| 09bb121ffe | |||
| a50be5b869 | |||
| ca5ef8cf4c | |||
| 4e33956acd | |||
| 9aae315e11 | |||
| 742e7ea998 | |||
| 69bd4c837c | |||
| 8c10d24842 | |||
| 6b681afdee | |||
| 6186497999 | |||
| 2571da594e | |||
| 7c52cad569 | |||
| 303bc940f2 | |||
| eda903abde | |||
| 5d5bc668eb | |||
| 6e5653a168 | |||
| 87343b8255 | |||
| cb21291983 | |||
| 8dd2241590 | |||
| 858fa81ea2 | |||
| 8d6c70b75e | |||
| ffd6ce23c3 | |||
| 5a882d0bc8 | |||
| cb1b4f4970 | |||
| 0de040548d | |||
| 40f4cf88c9 | |||
| 275b39fb1e | |||
| fe5da3cf90 | |||
| 4ed4e37604 | |||
| 10552d119f | |||
| d4e0e6f0ab | |||
| e2fce3cf9b | |||
| ad5ffc22ac | |||
| f980790bd7 | |||
| df8519961a | |||
| 171a6be736 | |||
| 91035d9a3f | |||
| 60e7d91409 | |||
| d05d1dac85 | |||
| 8184b4d155 | |||
| a0d5f9d2df | |||
| 49f7f9e3e1 | |||
| 911d8d5d64 | |||
| 3015ffe3ba | |||
| eb74bcf987 | |||
| b63898d8b9 | |||
| 459cfccff5 | |||
| fdb66cba6d | |||
| 93d705e402 | |||
| c8bbdc69d0 | |||
| 9b1587f334 | |||
| 3e67cc519e | |||
| eee6f614f1 | |||
| 62e5bad6ac | |||
| 163f342d7a | |||
| 370247eef2 | |||
| f22ecb03f2 | |||
| 577857ab5a | |||
| 095d16a57e | |||
| 862c2c0a71 | |||
| d7e9ce8ff1 | |||
| e657a02f7a | |||
| 182ff877f0 | |||
| 521358abb5 | |||
| b62aed5c5a | |||
| 5c4e31806d | |||
| 9f8d695d45 | |||
| e0e5f52d36 | |||
| 9fda563438 | |||
| 6d5bb285c9 | |||
| 7ac405b8f9 | |||
| 45d53bd38c | |||
| cc52f66f5d | |||
| e072c2aee8 | |||
| e52135c343 | |||
| cb53e8a664 | |||
| 44a8445b54 | |||
| b0a197cd18 | |||
| 9ba52b332c | |||
| ecfc77e57a | |||
| 2ba3e33d39 | |||
| 71ecdbd5b9 | |||
| bbe0b21aa4 | |||
| 51dd445a31 | |||
| 264158957c | |||
| 9d8963222c | |||
| c1a35dbab3 | |||
| d3931cc57c | |||
| 3795ced530 | |||
| 1372a5c33f | |||
| 9527da9785 | |||
| 3072db0e21 | |||
| 444e6d7ffa | |||
| 809c935d37 | |||
| 10bd54a785 | |||
| ece899f2a1 | |||
| 5d1a182e47 | |||
| 228ab9e727 | |||
| 2605aafc4f | |||
| 582bb2a7d7 | |||
| 0a3dbb1f59 | |||
| 5d1832fcef | |||
| 30ed509c55 | |||
| 2ad91011c3 | |||
| e40d4695ea | |||
| e4c03f8ccc | |||
| e10a0f5415 | |||
| 2a29011015 | |||
| a37e8869ac | |||
| 038860f158 | |||
| 51e678d760 | |||
| 1e2a9992d8 | |||
| 5b7bb917ef | |||
| 72aff78718 | |||
| cdeef7279c | |||
| 9cb5c557c5 | |||
| 1e1259d0a5 | |||
| 20b326d396 | |||
| b7cad3b8f7 | |||
| cf8b54a3b5 | |||
| edca1e2b98 | |||
| 89410b8b46 | |||
| a9397690e2 | |||
| ea678ece94 | |||
| f28f23f560 | |||
| b2911017d0 | |||
| cda4f702a1 | |||
| b6a0ae7f4a | |||
| b6f3508680 | |||
| ad0368b4c0 | |||
| b1d67bd1c4 | |||
| cda3d37f37 | |||
| abed0f146f | |||
| bdeaeee293 | |||
| b37ce4d0c1 | |||
| e3ff62bdc7 | |||
| eab6c79e15 | |||
| 260678c1bc | |||
| b2d300784f | |||
| 8d1d4f5eb7 | |||
| 25a03c7e27 | |||
| 27ab63ae7a | |||
| 9567e97b31 | |||
| b10a8b47d5 | |||
| 1bc274e2d0 | |||
| dca3420071 | |||
| bc3fc70a95 | |||
| eee983dfd2 | |||
| fbec69cd71 | |||
| 615c49e395 | |||
| 462d68df6b | |||
| 0224abc9bd | |||
| 16fe2fe1ab | |||
| 61c4486551 | |||
| 17ef088492 | |||
| 1111879c4d | |||
| e9d0b73296 | |||
| 8eadbf6fee | |||
| 8ae491d0d5 | |||
| 3dd125f861 | |||
| 01b4753dc6 | |||
| 5a5d78ac27 | |||
| a05eedd68e | |||
| 05304f9461 | |||
| fff5ec4534 | |||
| cf7641cee0 | |||
| a77e0c1fc9 | |||
| f374de2064 | |||
| 8e0620bedb | |||
| 8bb39b1bfa | |||
| 2450956fda | |||
| 56cd17401b | |||
| a53b514fec | |||
| de93af73f2 | |||
| 44f106fd0c | |||
| 8ac5cc40c1 | |||
| 8d7eebd390 | |||
| 0a5bb67c54 | |||
| f866151cc5 | |||
| 08e17b1714 | |||
| fa96f4c073 | |||
| dc5cf2b965 | |||
| f47f0570f9 | |||
| e0c96cc200 | |||
| 17e1ae9ea9 | |||
| 8401d616e0 | |||
| d8ac486984 | |||
| 335ea2ca38 | |||
| c73ff96690 | |||
| 15b23e3a4e | |||
| 47f86c098d | |||
| 6c2c7e881f | |||
| 74a2265200 | |||
| 0b2ec1d626 | |||
| 8ee188cf19 | |||
| eb5b23ae17 | |||
| 77999fe8f3 | |||
| 64fda51917 | |||
| 4165b757a5 | |||
| d31799ab7b | |||
| 8a46bd6b68 | |||
| 58362c2613 | |||
| 7d6c5fe3bd | |||
| f9b9d78b79 | |||
| 7670af88a2 | |||
| 0800361b40 | |||
| cdf3f41127 | |||
| 552bf8d61c | |||
| 2f58e48f42 | |||
| 67035f5d2f | |||
| b48206d942 | |||
| 87d8102a1a | |||
| bd1f0e1713 | |||
| 04c9081851 | |||
| 9cf23cac7f | |||
| 46f75c5a21 | |||
| 6167417bf8 | |||
| 82ab9237f5 | |||
| 82e7cdd785 | |||
| 41385abc7d | |||
| 84171e2949 | |||
| 42c038d8ab | |||
| fe6b42e509 | |||
| 8bc5c11030 | |||
| 76f7157749 | |||
| 52a242c72a | |||
| 8a42f7c626 | |||
| 6e2c0a3037 | |||
| 1b77234cfe | |||
| a15785a02f | |||
| 1a5f594b36 | |||
| 68b6295126 | |||
| 17d6d86194 | |||
| f82134fb12 | |||
| 37edef425c | |||
| 30f7a281b0 | |||
| e1606889f7 | |||
| 33244b930f | |||
| 212c004d31 | |||
| 190f23240a | |||
| 376830d6dc | |||
| 9a9fb2870c | |||
| 2a093d1da0 | |||
| 1a66f14bae | |||
| 887e7f428d | |||
| cc4f5f46ce | |||
| 13883242e4 | |||
| 09a97c43fd | |||
| 671b4f9f6f | |||
| 1ae913f0d2 | |||
| 45f487c9f4 | |||
| 7f1891236d | |||
| 1c981c331c | |||
| 0c9213936d | |||
| 188556991f | |||
| b6450027b8 | |||
| 82cffea6ed | |||
| 734788f310 | |||
| 45c3ff83cf | |||
| c7655573aa | |||
| 88a4f046d4 | |||
| 7ccccabe1d | |||
| 3d6dbd5f2a | |||
| 9407d80858 | |||
| 51eaf4f56d | |||
| 4b5ec37987 | |||
| 3f246a8f7d | |||
| 7f4833be81 | |||
| 755615a887 | |||
| ef32603801 | |||
| fa80b87f7a | |||
| f8b7062c61 | |||
| 95c4c42ff0 | |||
| 13fa206594 | |||
| a1dda2ffa4 | |||
| 0914afc4ed | |||
| 9f2cf2eb03 | |||
| 1607b7025c |
@@ -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']
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
name: Nightly-build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "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 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 bin/Release/Server/linux-x64 -c Release
|
||||
- uses: vimtor/action-zip@v1
|
||||
with:
|
||||
files: bin/Release/Client
|
||||
dest: RageCoop.Client.zip
|
||||
|
||||
- uses: vimtor/action-zip@v1
|
||||
with:
|
||||
files: bin/Release/Server/win-x64
|
||||
dest: RageCoop.Server-win-x64.zip
|
||||
|
||||
- uses: vimtor/action-zip@v1
|
||||
with:
|
||||
files: bin/Release/Server/linux-x64
|
||||
dest: RageCoop.Server-linux-x64.zip
|
||||
|
||||
- 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.Client.zip
|
||||
asset_name: RageCoop.Client.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-win-x64.zip
|
||||
asset_name: RageCoop.Server-win-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-x64.zip
|
||||
asset_name: RageCoop.Server-linux-x64.zip
|
||||
asset_content_type: application/zip
|
||||
max_releases: 7
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
**/bin
|
||||
**/obj
|
||||
**/packages
|
||||
**/.vs
|
||||
**/.vs
|
||||
**/.vscode
|
||||
@@ -1,192 +0,0 @@
|
||||
#undef DEBUG
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using RageCoop.Core;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
public static class COOPAPI
|
||||
{
|
||||
|
||||
#region DELEGATES
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
/// <param name="connected"></param>
|
||||
/// <param name="from">The player's id</param>
|
||||
/// <param name="reason"></param>
|
||||
public delegate void ConnectEvent(bool connected, int from, string reason = null);
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
/// <param name="from"></param>
|
||||
/// <param name="message">The Lidgren-Network net handle</param>
|
||||
/// <param name="args"></param>
|
||||
public delegate void ChatMessage(string from, string message, CancelEventArgs args);
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
/// <param name="from">The Lidgren-Network net handle</param>
|
||||
/// <param name="mod"></param>
|
||||
/// <param name="customID"></param>
|
||||
/// <param name="bytes"></param>
|
||||
public delegate void ModEvent(long from, string mod, byte customID, byte[] bytes);
|
||||
#endregion
|
||||
|
||||
#region EVENTS
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
public static event ConnectEvent OnConnection;
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
public static event ChatMessage OnChatMessage;
|
||||
|
||||
public static void Connected()
|
||||
{
|
||||
OnConnection?.Invoke(true, GetPlayerID());
|
||||
}
|
||||
|
||||
public static void Disconnected(string reason)
|
||||
{
|
||||
OnConnection?.Invoke(false, GetPlayerID(), reason);
|
||||
}
|
||||
|
||||
public static void Connected(int playerID)
|
||||
{
|
||||
OnConnection?.Invoke(true, playerID);
|
||||
}
|
||||
|
||||
public static void Disconnected(int playerID)
|
||||
{
|
||||
OnConnection?.Invoke(false, playerID);
|
||||
}
|
||||
|
||||
public static bool ChatMessageReceived(string from, string message)
|
||||
{
|
||||
CancelEventArgs args = new CancelEventArgs(false);
|
||||
OnChatMessage?.Invoke(from, message, args);
|
||||
return args.Cancel;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Send a local chat message to this player
|
||||
/// </summary>
|
||||
/// <param name="from">Username of the player who sent this message</param>
|
||||
/// <param name="message">The player's message</param>
|
||||
public static void LocalChatMessage(string from, string message)
|
||||
{
|
||||
Main.MainChat.AddMessage(from, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connect to any server
|
||||
/// </summary>
|
||||
/// <param name="serverAddress">The server address to connect. Example: 127.0.0.1:4499</param>
|
||||
public static void Connect(string serverAddress)
|
||||
{
|
||||
Networking.ToggleConnection(serverAddress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
public static void Disconnect()
|
||||
{
|
||||
Networking.ToggleConnection(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the player is already on a server
|
||||
/// </summary>
|
||||
public static bool IsOnServer()
|
||||
{
|
||||
return Networking.IsOnServer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the local player's ID
|
||||
/// </summary>
|
||||
/// <returns>PlayerID</returns>
|
||||
public static int GetPlayerID()
|
||||
{
|
||||
return Main.LocalPlayerID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a RAGECOOP menu is visible
|
||||
/// </summary>
|
||||
public static bool IsMenuVisible()
|
||||
{
|
||||
#if NON_INTERACTIVE
|
||||
return false;
|
||||
#else
|
||||
return Menus.CoopMenu.MenuPool.AreAnyVisible;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the RAGECOOP chat is visible
|
||||
/// </summary>
|
||||
public static bool IsChatFocused()
|
||||
{
|
||||
return Main.MainChat.Focused;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the RAGECOOP list of players is visible
|
||||
/// </summary>
|
||||
public static bool IsPlayerListVisible()
|
||||
{
|
||||
return Util.GetTickCount64() - PlayerList.Pressed < 5000;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the version of RAGECOOP
|
||||
/// </summary>
|
||||
public static string GetCurrentVersion()
|
||||
{
|
||||
return Main.CurrentVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get that player's local username
|
||||
/// </summary>
|
||||
public static string GetUsername()
|
||||
{
|
||||
return Main.Settings.Username;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a new username for this player
|
||||
/// </summary>
|
||||
/// <param name="username">The new username</param>
|
||||
/// <returns>false if the player already joined a server or the username is null or empty otherwise true</returns>
|
||||
public static bool SetUsername(string username)
|
||||
{
|
||||
if (IsOnServer() || string.IsNullOrEmpty(username))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Main.Settings.Username = username;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the client's settings.
|
||||
/// </summary>
|
||||
/// <returns>The client's settings, you should NEVER change settings without notifying the player.</returns>
|
||||
public static Settings Settings()
|
||||
{
|
||||
return Main.Settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using LemonUI;
|
||||
using LemonUI.Menus;
|
||||
using GTA;
|
||||
using System.Drawing;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class DebugMenu
|
||||
{
|
||||
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "Debug", "Debug settings") {
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
public static NativeMenu DiagnosticMenu = new NativeMenu("RAGECOOP", "Diagnostic", "Performence and Diagnostic")
|
||||
{
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
private static NativeItem d1=new NativeItem("PositionPrediction");
|
||||
static DebugMenu()
|
||||
{
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
Menu.Title.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.Clear();
|
||||
DiagnosticMenu.Add(new NativeItem("EntityPool", EntityPool.DumpDebug()));
|
||||
foreach (var pair in Debug.TimeStamps)
|
||||
{
|
||||
DiagnosticMenu.Add(new NativeItem(pair.Key.ToString(), pair.Value.ToString(), pair.Value.ToString()));
|
||||
}
|
||||
};
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void Update()
|
||||
{
|
||||
d1.AltTitle = SyncParameters.PositioinPredictionDefault.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
using System.Drawing;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using GTA;
|
||||
using LemonUI.Menus;
|
||||
|
||||
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")
|
||||
{
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
|
||||
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 _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());
|
||||
|
||||
/// <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);
|
||||
|
||||
_disableTrafficItem.CheckboxChanged += DisableTrafficCheckboxChanged;
|
||||
_disablePauseAlt.CheckboxChanged+=_disablePauseAlt_CheckboxChanged;
|
||||
_flipMenuItem.CheckboxChanged += FlipMenuCheckboxChanged;
|
||||
_showNetworkInfoItem.CheckboxChanged += ShowNetworkInfoCheckboxChanged;
|
||||
_menuKey.Activated+=ChaneMenuKey;
|
||||
_passengerKey.Activated+=ChangePassengerKey;
|
||||
_vehicleSoftLimit.Activated+=vehicleSoftLimit_Activated;
|
||||
|
||||
Menu.Add(_disableTrafficItem);
|
||||
Menu.Add(_disablePauseAlt);
|
||||
Menu.Add(_flipMenuItem);
|
||||
Menu.Add(_showNetworkInfoItem);
|
||||
Menu.Add(_menuKey);
|
||||
Menu.Add(_passengerKey);
|
||||
Menu.Add(_vehicleSoftLimit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void _disablePauseAlt_CheckboxChanged(object sender, EventArgs e)
|
||||
{
|
||||
Main.Settings.DisableAlternatePause=_disablePauseAlt.Checked;
|
||||
Util.SaveSettings();
|
||||
}
|
||||
private static void vehicleSoftLimit_Activated(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.Settings.WorldVehicleSoftLimit =int.Parse(
|
||||
Game.GetUserInput(WindowTitle.EnterMessage20,
|
||||
Main.Settings.WorldVehicleSoftLimit.ToString(), 20));
|
||||
_menuKey.AltTitle=Main.Settings.WorldVehicleSoftLimit.ToString();
|
||||
Util.SaveSettings();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
private static void ChaneMenuKey(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.Settings.MenuKey =(Keys)Enum.Parse(
|
||||
typeof(Keys),
|
||||
Game.GetUserInput(WindowTitle.EnterMessage20,
|
||||
Main.Settings.MenuKey.ToString(), 20));
|
||||
_menuKey.AltTitle=Main.Settings.MenuKey.ToString();
|
||||
Util.SaveSettings();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static void ChangePassengerKey(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.Settings.PassengerKey =(Keys)Enum.Parse(
|
||||
typeof(Keys),
|
||||
Game.GetUserInput(WindowTitle.EnterMessage20,
|
||||
Main.Settings.PassengerKey.ToString(), 20));
|
||||
_passengerKey.AltTitle=Main.Settings.PassengerKey.ToString();
|
||||
Util.SaveSettings();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public static void DisableTrafficCheckboxChanged(object a, System.EventArgs b)
|
||||
{
|
||||
Main.Settings.DisableTraffic = _disableTrafficItem.Checked;
|
||||
Util.SaveSettings() ;
|
||||
}
|
||||
|
||||
public static void FlipMenuCheckboxChanged(object a, System.EventArgs b)
|
||||
{
|
||||
CoopMenu.Menu.Alignment = _flipMenuItem.Checked ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left;
|
||||
|
||||
Menu.Alignment = _flipMenuItem.Checked ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left;
|
||||
Main.Settings.FlipMenu = _flipMenuItem.Checked;
|
||||
Util.SaveSettings();
|
||||
}
|
||||
|
||||
public static void ShowNetworkInfoCheckboxChanged(object a, System.EventArgs b)
|
||||
{
|
||||
Networking.ShowNetworkInfo = _showNetworkInfoItem.Checked;
|
||||
|
||||
if (!Networking.ShowNetworkInfo)
|
||||
{
|
||||
Networking.BytesReceived = 0;
|
||||
Networking.BytesSend = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class DownloadManager
|
||||
{
|
||||
private static readonly List<DownloadFile> _downloadFiles = new List<DownloadFile>();
|
||||
private static readonly Dictionary<byte, FileStream> _streams = new Dictionary<byte, FileStream>();
|
||||
private static readonly List<byte> _filesFinished = new List<byte>();
|
||||
public static bool DownloadComplete = false;
|
||||
|
||||
public static void AddFile(byte id, string name, long length)
|
||||
{
|
||||
string downloadFolder = $"Scripts\\RageCoop\\Resources\\{Main.Settings.LastServerAddress.Replace(":", ".")}";
|
||||
|
||||
if (!Directory.Exists(downloadFolder))
|
||||
{
|
||||
Directory.CreateDirectory(downloadFolder);
|
||||
}
|
||||
|
||||
if (FileAlreadyExists(downloadFolder, name, length))
|
||||
{
|
||||
// Send the server we are already done
|
||||
Networking.SendDownloadFinish(id);
|
||||
|
||||
Cancel(id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!new string[] { ".js", ".xml" }.Any(x => x == Path.GetExtension(name)))
|
||||
{
|
||||
Cancel(id);
|
||||
|
||||
GTA.UI.Notification.Show($"The download of a file from the server was blocked! [{name}]", true);
|
||||
Main.Logger.Error($"The download of a file from the server was blocked! [{name}]");
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_downloadFiles)
|
||||
{
|
||||
_downloadFiles.Add(new DownloadFile()
|
||||
{
|
||||
FileID = id,
|
||||
FileName = name,
|
||||
FileLength = length
|
||||
});
|
||||
}
|
||||
|
||||
lock (_streams)
|
||||
{
|
||||
_streams.Add(id, new FileStream($"{downloadFolder}\\{name}", FileMode.CreateNew, FileAccess.Write, FileShare.ReadWrite));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the file already exists and if the size correct otherwise delete this file
|
||||
/// </summary>
|
||||
/// <param name="folder"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
private static bool FileAlreadyExists(string folder, string name, long length)
|
||||
{
|
||||
string filePath = $"{folder}\\{name}";
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
if (new FileInfo(filePath).Length == length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Delete the file because the length is wrong (maybe the file was updated)
|
||||
File.Delete(filePath);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void RenderProgress()
|
||||
{
|
||||
if (_downloadFiles.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_downloadFiles) lock (_filesFinished)
|
||||
{
|
||||
new LemonUI.Elements.ScaledText(new System.Drawing.PointF(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width / 2, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height - 60), $"Downloading files {_filesFinished.Count()} / {_downloadFiles.Count() + _filesFinished.Count()}", 0.5f) { Alignment = GTA.UI.Alignment.Center }.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(byte id, byte[] chunk)
|
||||
{
|
||||
lock (_filesFinished)
|
||||
{
|
||||
if (_filesFinished.Contains(id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lock (_streams)
|
||||
{
|
||||
FileStream fs = _streams.FirstOrDefault(x => x.Key == id).Value;
|
||||
if (fs == null)
|
||||
{
|
||||
Main.Logger.Error($"Stream for file {id} not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
fs.Write(chunk, 0, chunk.Length);
|
||||
|
||||
lock (_downloadFiles)
|
||||
{
|
||||
DownloadFile file = _downloadFiles.FirstOrDefault(x => x.FileID == id);
|
||||
if (file == null)
|
||||
{
|
||||
Main.Logger.Error($"File {id} couldn't be found in the list!");
|
||||
return;
|
||||
}
|
||||
|
||||
file.FileWritten += chunk.Length;
|
||||
|
||||
if (file.FileWritten >= file.FileLength)
|
||||
{
|
||||
Cancel(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Cancel(byte id)
|
||||
{
|
||||
lock (_streams) lock (_downloadFiles) lock (_filesFinished)
|
||||
{
|
||||
FileStream fs = _streams.ContainsKey(id) ? _streams[id] : null;
|
||||
if (fs != null)
|
||||
{
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
|
||||
_streams.Remove(id);
|
||||
}
|
||||
|
||||
if (_downloadFiles.Any(x => x.FileID == id))
|
||||
{
|
||||
_downloadFiles.Remove(_downloadFiles.First(x => x.FileID == id));
|
||||
}
|
||||
|
||||
_filesFinished.Add(id);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Cleanup(bool everything)
|
||||
{
|
||||
lock (_streams) lock (_downloadFiles) lock (_filesFinished)
|
||||
{
|
||||
foreach (KeyValuePair<byte, FileStream> stream in _streams)
|
||||
{
|
||||
stream.Value.Close();
|
||||
stream.Value.Dispose();
|
||||
}
|
||||
_streams.Clear();
|
||||
_downloadFiles.Clear();
|
||||
_filesFinished.Clear();
|
||||
}
|
||||
|
||||
if (everything)
|
||||
{
|
||||
DownloadComplete = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DownloadFile
|
||||
{
|
||||
public byte FileID { get; set; } = 0;
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
public long FileLength { get; set; } = 0;
|
||||
public long FileWritten { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
using System.Collections.Generic;
|
||||
using RageCoop.Core;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[XmlRoot(ElementName = "Map")]
|
||||
public class CoopMap
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[XmlArray("Props")]
|
||||
[XmlArrayItem("Prop")]
|
||||
public List<CoopProp> Props { get; set; } = new List<CoopProp>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public struct CoopProp
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Vector3 Position { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Vector3 Rotation { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public int Hash { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool Dynamic { get; set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public int Texture { get; set; }
|
||||
}
|
||||
|
||||
public static class MapLoader
|
||||
{
|
||||
// string = file name
|
||||
private static readonly Dictionary<string, CoopMap> _maps = new Dictionary<string, CoopMap>();
|
||||
private static readonly List<int> _createdObjects = new List<int>();
|
||||
|
||||
public static void LoadAll()
|
||||
{
|
||||
string downloadFolder = $"Scripts\\RageCoop\\Resources\\{Main.Settings.LastServerAddress.Replace(":", ".")}";
|
||||
|
||||
if (!Directory.Exists(downloadFolder))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(downloadFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.Logger.Error(ex.Message);
|
||||
|
||||
// Without the directory we can't do the other stuff
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
string[] files = Directory.GetFiles(downloadFolder, "*.xml");
|
||||
lock (_maps)
|
||||
{
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
string filePath = files[i];
|
||||
string fileName = Path.GetFileName(filePath);
|
||||
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(CoopMap));
|
||||
CoopMap map;
|
||||
|
||||
using (var stream = new FileStream(filePath, FileMode.Open))
|
||||
{
|
||||
try
|
||||
{
|
||||
map = (CoopMap)serializer.Deserialize(stream);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.Logger.Error($"The map with the name \"{fileName}\" couldn't be added!");
|
||||
Main.Logger.Error($"{ex.Message}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_maps.Add(fileName, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoadMap(string name)
|
||||
{
|
||||
lock (_maps) lock (_createdObjects)
|
||||
{
|
||||
if (!_maps.ContainsKey(name) || _createdObjects.Count != 0)
|
||||
{
|
||||
GTA.UI.Notification.Show($"The map with the name \"{name}\" couldn't be loaded!");
|
||||
Main.Logger.Error($"The map with the name \"{name}\" couldn't be loaded!");
|
||||
return;
|
||||
}
|
||||
|
||||
CoopMap map = _maps[name];
|
||||
|
||||
foreach (CoopProp prop in map.Props)
|
||||
{
|
||||
Model model = prop.Hash.ModelRequest();
|
||||
if (model == null)
|
||||
{
|
||||
Main.Logger.Error($"Model for object \"{model.Hash}\" couldn't be loaded!");
|
||||
continue;
|
||||
}
|
||||
|
||||
int handle = Function.Call<int>(Hash.CREATE_OBJECT, model.Hash, prop.Position.X, prop.Position.Y, prop.Position.Z, 1, 1, prop.Dynamic);
|
||||
model.MarkAsNoLongerNeeded();
|
||||
if (handle == 0)
|
||||
{
|
||||
Main.Logger.Error($"Object \"{prop.Hash}\" couldn't be created!");
|
||||
continue;
|
||||
}
|
||||
|
||||
_createdObjects.Add(handle);
|
||||
|
||||
if (prop.Texture > 0 && prop.Texture < 16)
|
||||
{
|
||||
Function.Call(Hash._SET_OBJECT_TEXTURE_VARIATION, handle, prop.Texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool AnyMapLoaded()
|
||||
{
|
||||
lock (_createdObjects) return _createdObjects.Any();
|
||||
}
|
||||
|
||||
public static void UnloadMap()
|
||||
{
|
||||
lock (_createdObjects)
|
||||
{
|
||||
foreach (int handle in _createdObjects)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
int tmpHandle = handle;
|
||||
Function.Call(Hash.DELETE_OBJECT, &tmpHandle);
|
||||
}
|
||||
}
|
||||
|
||||
_createdObjects.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void DeleteAll()
|
||||
{
|
||||
UnloadMap();
|
||||
lock (_maps)
|
||||
{
|
||||
_maps.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static partial class Networking
|
||||
{
|
||||
public static NetClient Client;
|
||||
public static float Latency = 0;
|
||||
public static bool ShowNetworkInfo = false;
|
||||
public static int BytesReceived = 0;
|
||||
public static int BytesSend = 0;
|
||||
private static Thread ReceiveThread;
|
||||
|
||||
public static void ToggleConnection(string address)
|
||||
{
|
||||
if (IsOnServer)
|
||||
{
|
||||
Client.Disconnect("Bye!");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
|
||||
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
|
||||
{
|
||||
AutoFlushSendQueue = false
|
||||
};
|
||||
|
||||
config.EnableMessageType(NetIncomingMessageType.ConnectionLatencyUpdated);
|
||||
|
||||
Client = new NetClient(config);
|
||||
|
||||
Client.Start();
|
||||
|
||||
string[] ip = new string[2];
|
||||
|
||||
int idx = address.LastIndexOf(':');
|
||||
if (idx != -1)
|
||||
{
|
||||
ip[0] = address.Substring(0, idx);
|
||||
ip[1] = address.Substring(idx + 1);
|
||||
}
|
||||
|
||||
if (ip.Length != 2)
|
||||
{
|
||||
throw new Exception("Malformed URL");
|
||||
}
|
||||
|
||||
// Send HandshakePacket
|
||||
EntityPool.AddPlayer();
|
||||
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
|
||||
new Packets.Handshake()
|
||||
{
|
||||
PedID = Main.LocalPlayerID,
|
||||
Username = Main.Settings.Username,
|
||||
ModVersion = Main.CurrentVersion,
|
||||
}.Pack(outgoingMessage);
|
||||
|
||||
Client.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
|
||||
}
|
||||
}
|
||||
public static bool IsOnServer
|
||||
{
|
||||
get { return Client?.ConnectionStatus == NetConnectionStatus.Connected; }
|
||||
}
|
||||
public static void Start()
|
||||
{
|
||||
ReceiveThread=new Thread(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Client!=null)
|
||||
{
|
||||
Client.FlushSendQueue();
|
||||
ReceiveMessages();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.Logger.Error(ex);
|
||||
}
|
||||
Thread.Sleep(5);
|
||||
}
|
||||
});
|
||||
ReceiveThread.Start();
|
||||
}
|
||||
|
||||
#region -- GET --
|
||||
#region -- PLAYER --
|
||||
private static void PlayerConnect(Packets.PlayerConnect packet)
|
||||
{
|
||||
var p = new PlayerData
|
||||
{
|
||||
PedID = 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.DumpCharacters();
|
||||
COOPAPI.Connected(packet.PedID);
|
||||
}
|
||||
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
|
||||
{
|
||||
var name=PlayerList.GetPlayer(packet.PedID).Username;
|
||||
GTA.UI.Notification.Show($"{name} left.");
|
||||
COOPAPI.Disconnected(packet.PedID);
|
||||
PlayerList.RemovePlayer(packet.PedID);
|
||||
EntityPool.RemoveAllFromPlayer(packet.PedID);
|
||||
|
||||
|
||||
}
|
||||
private static object DecodeNativeCall(ulong hash, List<object> args, bool returnValue, byte? returnType = null)
|
||||
{
|
||||
List<InputArgument> arguments = new List<InputArgument>();
|
||||
|
||||
if (args == null || args.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (ushort i = 0; i < args.Count; i++)
|
||||
{
|
||||
object x = args.ElementAt(i);
|
||||
switch (x)
|
||||
{
|
||||
case int _:
|
||||
arguments.Add((int)x);
|
||||
break;
|
||||
case bool _:
|
||||
arguments.Add((bool)x);
|
||||
break;
|
||||
case float _:
|
||||
arguments.Add((float)x);
|
||||
break;
|
||||
case string _:
|
||||
arguments.Add((string)x);
|
||||
break;
|
||||
case Vector3 _:
|
||||
Vector3 vector = (Vector3)x;
|
||||
arguments.Add((float)vector.X);
|
||||
arguments.Add((float)vector.Y);
|
||||
arguments.Add((float)vector.Z);
|
||||
break;
|
||||
default:
|
||||
GTA.UI.Notification.Show("[DecodeNativeCall][" + hash + "]: Type of argument not found!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!returnValue)
|
||||
{
|
||||
Function.Call((Hash)hash, arguments.ToArray());
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (returnType.Value)
|
||||
{
|
||||
case 0x00: // int
|
||||
return Function.Call<int>((Hash)hash, arguments.ToArray());
|
||||
case 0x01: // bool
|
||||
return Function.Call<bool>((Hash)hash, arguments.ToArray());
|
||||
case 0x02: // float
|
||||
return Function.Call<float>((Hash)hash, arguments.ToArray());
|
||||
case 0x03: // string
|
||||
return Function.Call<string>((Hash)hash, arguments.ToArray());
|
||||
case 0x04: // vector3
|
||||
return Function.Call<Vector3>((Hash)hash, arguments.ToArray());
|
||||
default:
|
||||
GTA.UI.Notification.Show("[DecodeNativeCall][" + hash + "]: Type of return not found!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void DecodeNativeResponse(Packets.NativeResponse packet)
|
||||
{
|
||||
object result = DecodeNativeCall(packet.Hash, packet.Args, true, packet.ResultType);
|
||||
|
||||
if (Main.CheckNativeHash.ContainsKey(packet.Hash))
|
||||
{
|
||||
foreach (KeyValuePair<ulong, byte> hash in Main.CheckNativeHash)
|
||||
{
|
||||
if (hash.Key == packet.Hash)
|
||||
{
|
||||
lock (Main.ServerItems)
|
||||
{
|
||||
Main.ServerItems.Add((int)result, hash.Value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
|
||||
new Packets.NativeResponse()
|
||||
{
|
||||
Hash = 0,
|
||||
Args = new List<object>() { result },
|
||||
ID = packet.ID
|
||||
}.Pack(outgoingMessage);
|
||||
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Native);
|
||||
Client.FlushSendQueue();
|
||||
}
|
||||
#endregion // -- PLAYER --
|
||||
|
||||
#endregion
|
||||
public static void Tick()
|
||||
{
|
||||
|
||||
|
||||
|
||||
// Sync
|
||||
EntityPool.DoSync();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,423 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using GTA;
|
||||
using RageCoop.Client.Menus;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static partial class Networking
|
||||
{
|
||||
public static void ReceiveMessages()
|
||||
{
|
||||
if (Client == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NetIncomingMessage message;
|
||||
|
||||
while ((message = Client.ReadMessage()) != null)
|
||||
{
|
||||
BytesReceived += message.LengthBytes;
|
||||
|
||||
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
|
||||
Main.QueueAction(() => { GTA.UI.Notification.Show("~y~Trying to connect..."); return true; });
|
||||
break;
|
||||
case NetConnectionStatus.Connected:
|
||||
if (message.SenderConnection.RemoteHailMessage.ReadByte() != (byte)PacketTypes.Handshake)
|
||||
{
|
||||
Client.Disconnect("Wrong packet!");
|
||||
}
|
||||
else
|
||||
{
|
||||
int len = message.SenderConnection.RemoteHailMessage.ReadInt32();
|
||||
byte[] data = message.SenderConnection.RemoteHailMessage.ReadBytes(len);
|
||||
|
||||
Packets.Handshake handshakePacket = new Packets.Handshake();
|
||||
handshakePacket.Unpack(data);
|
||||
|
||||
#if !NON_INTERACTIVE
|
||||
|
||||
#endif
|
||||
|
||||
COOPAPI.Connected();
|
||||
Main.QueueAction(() => {
|
||||
CoopMenu.ConnectedMenuSetting();
|
||||
Main.MainChat.Init();
|
||||
PlayerList.Cleanup();
|
||||
GTA.UI.Notification.Show("~g~Connected!");
|
||||
});
|
||||
|
||||
Main.Logger.Info(">> Connected <<");
|
||||
}
|
||||
break;
|
||||
case NetConnectionStatus.Disconnected:
|
||||
DownloadManager.Cleanup(true);
|
||||
|
||||
// Reset all values
|
||||
Latency = 0;
|
||||
|
||||
Main.QueueAction(() => Main.CleanUpWorld());
|
||||
|
||||
if (Main.MainChat.Focused)
|
||||
{
|
||||
Main.MainChat.Focused = false;
|
||||
}
|
||||
|
||||
Main.QueueAction(() => Main.CleanUp());
|
||||
|
||||
#if !NON_INTERACTIVE
|
||||
CoopMenu.DisconnectedMenuSetting();
|
||||
#endif
|
||||
|
||||
COOPAPI.Disconnected(reason);
|
||||
Main.QueueAction(() =>
|
||||
GTA.UI.Notification.Show("~r~Disconnected: " + reason));
|
||||
|
||||
MapLoader.DeleteAll();
|
||||
|
||||
Main.Logger.Info($">> Disconnected << reason: {reason}");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NetIncomingMessageType.Data:
|
||||
if (message.LengthBytes==0) { continue; }
|
||||
|
||||
var packetType = (PacketTypes)message.ReadByte();
|
||||
try
|
||||
{
|
||||
|
||||
int len = message.ReadInt32();
|
||||
byte[] data = message.ReadBytes(len);
|
||||
switch (packetType)
|
||||
{
|
||||
case PacketTypes.CleanUpWorld:
|
||||
{
|
||||
Main.QueueAction(() => { Main.CleanUpWorld(); return true; });
|
||||
}
|
||||
break;
|
||||
case PacketTypes.PlayerConnect:
|
||||
{
|
||||
|
||||
Packets.PlayerConnect packet = new Packets.PlayerConnect();
|
||||
packet.Unpack(data);
|
||||
|
||||
Main.QueueAction(() =>PlayerConnect(packet));
|
||||
}
|
||||
break;
|
||||
case PacketTypes.PlayerDisconnect:
|
||||
{
|
||||
|
||||
Packets.PlayerDisconnect packet = new Packets.PlayerDisconnect();
|
||||
packet.Unpack(data);
|
||||
Main.QueueAction(() =>PlayerDisconnect(packet));
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketTypes.PlayerInfoUpdate:
|
||||
{
|
||||
var packet = new Packets.PlayerInfoUpdate();
|
||||
packet.Unpack(data);
|
||||
PlayerList.SetPlayer(packet.PedID,packet.Username,packet.Latency);
|
||||
break;
|
||||
}
|
||||
#region ENTITY SYNC
|
||||
case PacketTypes.VehicleSync:
|
||||
{
|
||||
|
||||
Packets.VehicleSync packet = new Packets.VehicleSync();
|
||||
packet.Unpack(data);
|
||||
VehicleSync(packet);
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketTypes.PedSync:
|
||||
{
|
||||
|
||||
Packets.PedSync packet = new Packets.PedSync();
|
||||
packet.Unpack(data);
|
||||
PedSync(packet);
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketTypes.VehicleStateSync:
|
||||
{
|
||||
|
||||
Packets.VehicleStateSync packet = new Packets.VehicleStateSync();
|
||||
packet.Unpack(data);
|
||||
VehicleStateSync(packet);
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketTypes.PedStateSync:
|
||||
{
|
||||
|
||||
|
||||
Packets.PedStateSync packet = new Packets.PedStateSync();
|
||||
packet.Unpack(data);
|
||||
PedStateSync(packet);
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketTypes.ProjectileSync:
|
||||
{
|
||||
Packets.ProjectileSync packet = new Packets.ProjectileSync();
|
||||
packet.Unpack(data);
|
||||
ProjectileSync(packet);
|
||||
break;
|
||||
}
|
||||
#endregion
|
||||
case PacketTypes.ChatMessage:
|
||||
{
|
||||
|
||||
Packets.ChatMessage packet = new Packets.ChatMessage();
|
||||
packet.Unpack(data);
|
||||
|
||||
if (!COOPAPI.ChatMessageReceived(packet.Username, packet.Message))
|
||||
{
|
||||
Main.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message);return true; });
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketTypes.NativeCall:
|
||||
{
|
||||
|
||||
Packets.NativeCall packet = new Packets.NativeCall();
|
||||
packet.Unpack(data);
|
||||
|
||||
DecodeNativeCall(packet.Hash, packet.Args, false);
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketTypes.NativeResponse:
|
||||
{
|
||||
|
||||
Packets.NativeResponse packet = new Packets.NativeResponse();
|
||||
packet.Unpack(data);
|
||||
|
||||
DecodeNativeResponse(packet);
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketTypes.Mod:
|
||||
{
|
||||
Packets.Mod packet = new Packets.Mod();
|
||||
packet.Unpack(data);
|
||||
// Need to do some stuff here
|
||||
}
|
||||
break;
|
||||
case PacketTypes.FileTransferTick:
|
||||
{
|
||||
Packets.FileTransferTick packet = new Packets.FileTransferTick();
|
||||
packet.Unpack(data);
|
||||
|
||||
DownloadManager.Write(packet.ID, packet.FileChunk);
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketTypes.FileTransferRequest:
|
||||
{
|
||||
Packets.FileTransferRequest packet = new Packets.FileTransferRequest();
|
||||
packet.Unpack(data);
|
||||
|
||||
DownloadManager.AddFile(packet.ID, packet.FileName, packet.FileLength);
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketTypes.FileTransferComplete:
|
||||
{
|
||||
Packets.FileTransferComplete packet = new Packets.FileTransferComplete();
|
||||
packet.Unpack(data);
|
||||
|
||||
DownloadManager.Cleanup(false);
|
||||
DownloadManager.DownloadComplete = true;
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketTypes.ServerClientEvent:
|
||||
{
|
||||
Packets.ServerClientEvent packet = new Packets.ServerClientEvent();
|
||||
packet.Unpack(data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (packetType.IsSyncEvent())
|
||||
{
|
||||
// Dispatch to main thread
|
||||
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, data); return true; });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.QueueAction(() => {
|
||||
GTA.UI.Notification.Show("~r~~h~Packet Error");
|
||||
return true;
|
||||
});
|
||||
Main.Logger.Error($"[{packetType}] {ex.Message}");
|
||||
Main.Logger.Error(ex);
|
||||
Client.Disconnect($"Packet Error [{packetType}]");
|
||||
}
|
||||
break;
|
||||
case NetIncomingMessageType.ConnectionLatencyUpdated:
|
||||
Latency = message.ReadFloat();
|
||||
break;
|
||||
case NetIncomingMessageType.DebugMessage:
|
||||
case NetIncomingMessageType.ErrorMessage:
|
||||
case NetIncomingMessageType.WarningMessage:
|
||||
case NetIncomingMessageType.VerboseDebugMessage:
|
||||
#if DEBUG
|
||||
// TODO?
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Client.Recycle(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void PedSync(Packets.PedSync packet)
|
||||
{
|
||||
SyncedPed c = EntityPool.GetPedByID(packet.ID);
|
||||
if (c==null)
|
||||
{
|
||||
Main.Logger.Debug($"Creating character for incoming sync:{packet.ID}");
|
||||
EntityPool.ThreadSafe.Add(c=new SyncedPed(packet.ID));
|
||||
}
|
||||
PedDataFlags flags = packet.Flag;
|
||||
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.HasFlag(PedDataFlags.IsAiming);
|
||||
c.IsReloading = flags.HasFlag(PedDataFlags.IsReloading);
|
||||
c.IsJumping = flags.HasFlag(PedDataFlags.IsJumping);
|
||||
c.IsRagdoll = flags.HasFlag(PedDataFlags.IsRagdoll);
|
||||
c.IsOnFire = flags.HasFlag(PedDataFlags.IsOnFire);
|
||||
c.IsInParachuteFreeFall = flags.HasFlag(PedDataFlags.IsInParachuteFreeFall);
|
||||
c.IsParachuteOpen = flags.HasFlag(PedDataFlags.IsParachuteOpen);
|
||||
c.IsOnLadder = flags.HasFlag(PedDataFlags.IsOnLadder);
|
||||
c.IsVaulting = flags.HasFlag(PedDataFlags.IsVaulting);
|
||||
c.IsInCover = flags.HasFlag(PedDataFlags.IsInCover);
|
||||
c.Heading=packet.Heading;
|
||||
c.LastSynced = Main.Ticked;
|
||||
if (c.IsAiming)
|
||||
{
|
||||
c.AimCoords = packet.AimCoords;
|
||||
}
|
||||
if (c.IsRagdoll)
|
||||
{
|
||||
c.RotationVelocity=packet.RotationVelocity;
|
||||
}
|
||||
}
|
||||
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.ModelHash=packet.ModelHash;
|
||||
c.LastStateSynced = Main.Ticked;
|
||||
}
|
||||
private static void VehicleSync(Packets.VehicleSync packet)
|
||||
{
|
||||
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
|
||||
if (v==null)
|
||||
{
|
||||
EntityPool.ThreadSafe.Add(v=new SyncedVehicle(packet.ID));
|
||||
}
|
||||
if (v.IsMine) { 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.IsMine) { 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.EngineRunning = packet.Flag.HasFlag(VehicleDataFlags.IsEngineRunning);
|
||||
v.LightsOn = packet.Flag.HasFlag(VehicleDataFlags.AreLightsOn);
|
||||
v.BrakeLightsOn = packet.Flag.HasFlag(VehicleDataFlags.AreBrakeLightsOn);
|
||||
v.HighBeamsOn = packet.Flag.HasFlag(VehicleDataFlags.AreHighBeamsOn);
|
||||
v.SireneActive = packet.Flag.HasFlag(VehicleDataFlags.IsSirenActive);
|
||||
v.IsDead = packet.Flag.HasFlag(VehicleDataFlags.IsDead);
|
||||
v.HornActive = packet.Flag.HasFlag(VehicleDataFlags.IsHornActive);
|
||||
v.Transformed = packet.Flag.HasFlag(VehicleDataFlags.IsTransformed);
|
||||
v.Passengers=new Dictionary<VehicleSeat, SyncedPed>();
|
||||
v.LockStatus=packet.LockStatus;
|
||||
v.RadioStation=packet.RadioStation;
|
||||
v.Flags=packet.Flag;
|
||||
foreach (KeyValuePair<int, int> pair in packet.Passengers)
|
||||
{
|
||||
if (EntityPool.PedExists(pair.Value))
|
||||
{
|
||||
v.Passengers.Add((VehicleSeat)pair.Key, EntityPool.GetPedByID(pair.Value));
|
||||
}
|
||||
}
|
||||
v.LastStateSynced= Main.Ticked;
|
||||
|
||||
}
|
||||
private static void ProjectileSync(Packets.ProjectileSync packet)
|
||||
{
|
||||
var p = EntityPool.GetProjectileByID(packet.ID);
|
||||
if (p==null)
|
||||
{
|
||||
if (packet.Exploded) { return; }
|
||||
Main.Logger.Debug($"Creating new projectile: {(WeaponHash)packet.WeaponHash}");
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using GTA.Math;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static partial class Networking
|
||||
{
|
||||
|
||||
|
||||
#region -- SEND --
|
||||
/// <summary>
|
||||
/// Pack the packet then send to server.
|
||||
/// </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)
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
|
||||
p.Pack(outgoingMessage);
|
||||
Client.SendMessage(outgoingMessage, method, (int)channel);
|
||||
}
|
||||
|
||||
public static void SendPed(SyncedPed c)
|
||||
{
|
||||
Ped p = c.MainPed;
|
||||
var packet=new Packets.PedSync()
|
||||
{
|
||||
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.HasFlag(PedDataFlags.IsAiming))
|
||||
{
|
||||
packet.AimCoords = p.GetAimCoord();
|
||||
}
|
||||
if (packet.Flag.HasFlag(PedDataFlags.IsRagdoll))
|
||||
{
|
||||
packet.RotationVelocity=p.RotationVelocity;
|
||||
}
|
||||
Send(packet, ConnectionChannel.PedSync);
|
||||
}
|
||||
public static void SendPedState(SyncedPed c)
|
||||
{
|
||||
Ped p = c.MainPed;
|
||||
|
||||
var packet=new Packets.PedStateSync()
|
||||
{
|
||||
ID = c.ID,
|
||||
OwnerID=c.OwnerID,
|
||||
Clothes=p.GetPedClothes(),
|
||||
ModelHash=p.Model.Hash,
|
||||
WeaponComponents=p.Weapons.Current.GetWeaponComponents(),
|
||||
};
|
||||
|
||||
Send(packet, ConnectionChannel.PedSync);
|
||||
}
|
||||
public static void SendVehicle(SyncedVehicle v)
|
||||
{
|
||||
Vehicle veh = v.MainVehicle;
|
||||
var packet = new Packets.VehicleSync()
|
||||
{
|
||||
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);
|
||||
}
|
||||
var packet=new Packets.VehicleStateSync()
|
||||
{
|
||||
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,
|
||||
Mods = veh.Mods.GetVehicleMods(),
|
||||
ModelHash=veh.Model.Hash,
|
||||
EngineHealth=veh.EngineHealth,
|
||||
Passengers=veh.GetPassengers(),
|
||||
LockStatus=veh.LockStatus,
|
||||
};
|
||||
if (v.MainVehicle==Game.Player.LastVehicle)
|
||||
{
|
||||
packet.RadioStation=Util.GetPlayerRadioIndex();
|
||||
}
|
||||
Send(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);
|
||||
}
|
||||
|
||||
|
||||
#region SYNC EVENTS
|
||||
public static void SendBulletShot(Vector3 start,Vector3 end,uint weapon,int ownerID)
|
||||
{
|
||||
Send(new Packets.BulletShot()
|
||||
{
|
||||
StartPosition = start,
|
||||
EndPosition = end,
|
||||
OwnerID = ownerID,
|
||||
WeaponHash=weapon,
|
||||
}, ConnectionChannel.SyncEvents);
|
||||
}
|
||||
#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
|
||||
if (ShowNetworkInfo)
|
||||
{
|
||||
BytesSend += outgoingMessage.LengthBytes;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
public static void SendDownloadFinish(byte id)
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
|
||||
|
||||
new Packets.FileTransferComplete() { ID = id }.Pack(outgoingMessage);
|
||||
|
||||
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableUnordered, (byte)ConnectionChannel.File);
|
||||
Client.FlushSendQueue();
|
||||
|
||||
#if DEBUG
|
||||
if (ShowNetworkInfo)
|
||||
{
|
||||
BytesSend += outgoingMessage.LengthBytes;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RageCoop.Core;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
public static class PlayerList
|
||||
{
|
||||
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 ulong _lastUpdate = Util.GetTickCount64();
|
||||
public static ulong Pressed { get; set; }
|
||||
|
||||
public static bool LeftAlign = true;
|
||||
public static List<PlayerData> Players=new List<PlayerData> { };
|
||||
public static void Tick()
|
||||
{
|
||||
if (!Networking.IsOnServer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((Util.GetTickCount64() - _lastUpdate) >= 1000)
|
||||
{
|
||||
Update( Main.Settings.Username);
|
||||
}
|
||||
|
||||
if ((Util.GetTickCount64() - Pressed) < 5000 && !Main.MainChat.Focused
|
||||
#if !NON_INTERACTIVE
|
||||
&& !Menus.CoopMenu.MenuPool.AreAnyVisible
|
||||
#endif
|
||||
)
|
||||
{
|
||||
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)
|
||||
{
|
||||
_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)
|
||||
{
|
||||
_mainScaleform.CallFunction("SET_DATA_SLOT", i++, $"{player.Latency * 1000:N0}ms", player.Username, 116, 0, i - 1, "", "", 2, "", "", ' ');
|
||||
}
|
||||
|
||||
_mainScaleform.CallFunction("SET_TITLE", "Player list", $"{Players.Count+1} players");
|
||||
_mainScaleform.CallFunction("DISPLAY_VIEW");
|
||||
}
|
||||
public static void SetPlayer(int id, string username,float latency=0)
|
||||
{
|
||||
|
||||
var toset = Players.Where(x => x.PedID==id);
|
||||
if (toset.Any())
|
||||
{
|
||||
var p=toset.First();
|
||||
p.Username=username;
|
||||
p.PedID=id;
|
||||
p.Latency=latency;
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerData p = new PlayerData { PedID=id, Username=username,Latency=latency };
|
||||
Players.Add(p);
|
||||
}
|
||||
}
|
||||
public static PlayerData GetPlayer(int id)
|
||||
{
|
||||
return Players.Find(x => x.PedID==id);
|
||||
}
|
||||
public static void RemovePlayer(int id)
|
||||
{
|
||||
var p = Players.Where(x => x.PedID==id);
|
||||
if (p.Any())
|
||||
{
|
||||
Players.Remove(p.First());
|
||||
}
|
||||
}
|
||||
public static void Cleanup()
|
||||
{
|
||||
Players=new List<PlayerData> { };
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("RageCoop.Client")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("RageCoop.Client")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("ef56d109-1f22-43e0-9dff-cfcfb94e0681")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.4.1.0")]
|
||||
[assembly: AssemblyFileVersion("0.4.1.0")]
|
||||
@@ -1,124 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<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)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>D:\Games\Grand Theft Auto V\Scripts\RageCoop\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="LemonUI.SHVDN3, Version=1.5.1.0, Culture=neutral, processorArchitecture=AMD64">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Libs\Release\scripts\LemonUI.SHVDN3.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Lidgren.Network, Version=2012.1.7.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Libs\Release\scripts\Lidgren.Network.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Libs\Release\scripts\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ScriptHookVDotNet3, Version=3.3.2.0, Culture=neutral, processorArchitecture=AMD64">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Libs\Release\ScriptHookVDotNet3.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Security" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DevTools\DevTool.cs" />
|
||||
<Compile Include="Menus\Sub\DevToolMenu.cs" />
|
||||
<Compile Include="Menus\Sub\ServersMenu.cs" />
|
||||
<Compile Include="Scripting\ClientScript.cs" />
|
||||
<Compile Include="Scripting\Engine.cs" />
|
||||
<Compile Include="Util\MathExtensions.cs" />
|
||||
<Compile Include="Util\PedConfigFlags.cs" />
|
||||
<Compile Include="Util\Util.cs" />
|
||||
<Compile Include="Util\VehicleExtensions.cs" />
|
||||
<Compile Include="Util\WeaponUtil.cs" />
|
||||
<Compile Include="Networking\Chat.cs" />
|
||||
<Compile Include="COOPAPI.cs" />
|
||||
<Compile Include="Debug.cs" />
|
||||
<Compile Include="Networking\DownloadManager.cs" />
|
||||
<Compile Include="Util\TaskType.cs" />
|
||||
<Compile Include="Menus\Sub\DebugMenu.cs" />
|
||||
<Compile Include="Networking\Receive.cs" />
|
||||
<Compile Include="Networking\Send.cs" />
|
||||
<Compile Include="Sync\Entities\SyncedPed.cs" />
|
||||
<None Include="app.config" />
|
||||
<Compile Include="Sync\Entities\SyncedProjectile.cs" />
|
||||
<Compile Include="Sync\EntityPool.cs" />
|
||||
<Compile Include="Sync\SyncEvents.cs" />
|
||||
<Compile Include="Sync\Entities\SyncedEntity.cs" />
|
||||
<Compile Include="Sync\Entities\SyncedVehicle.cs" />
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="Networking\MapLoader.cs" />
|
||||
<Compile Include="Menus\CoopMenu.cs" />
|
||||
<Compile Include="Menus\Sub\SettingsMenu.cs" />
|
||||
<Compile Include="Networking\Networking.cs" />
|
||||
<Compile Include="PlayerList.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Sync\SyncParameters.cs" />
|
||||
<Compile Include="Util\PedExtensions.cs" />
|
||||
<Compile Include="WorldThread.cs" />
|
||||
<Compile Include="Settings.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Core\RageCoop.Core.csproj">
|
||||
<Project>{cc2e8102-e568-4524-aa1f-f8e0f1cfe58a}</Project>
|
||||
<Name>RageCoop.Core</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -1,15 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RageCoop.Client.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Inherit from this class, constructor will be called when the script is loaded.
|
||||
/// </summary>
|
||||
public abstract class ClientScript
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.CodeDom.Compiler;
|
||||
|
||||
namespace RageCoop.Client.Scripting
|
||||
{
|
||||
internal class Engine : Core.Scripting.ScriptingEngine
|
||||
{
|
||||
public Engine() : base(typeof(ClientScript), Main.Logger) { }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal abstract class SyncedEntity
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current player is responsible for syncing this entity.
|
||||
/// </summary>
|
||||
public bool IsMine
|
||||
{
|
||||
get
|
||||
{
|
||||
return OwnerID==Main.LocalPlayerID;
|
||||
}
|
||||
}
|
||||
|
||||
public int ID { get; set; }
|
||||
public int OwnerID { get;set; }
|
||||
public bool IsOutOfSync
|
||||
{
|
||||
get
|
||||
{
|
||||
return Main.Ticked-LastSynced>200;
|
||||
}
|
||||
}
|
||||
public bool IsReady
|
||||
{
|
||||
get {return !(LastSynced==0||LastStateSynced==0);}
|
||||
}
|
||||
public bool NeedUpdate
|
||||
{
|
||||
get { return LastSynced>LastUpdated; }
|
||||
}
|
||||
#region LAST STATE
|
||||
/// <summary>
|
||||
/// Last time a new sync message arrived.
|
||||
/// </summary>
|
||||
public ulong LastSynced { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// Last time a new sync message arrived.
|
||||
/// </summary>
|
||||
public ulong LastStateSynced { get; internal set; } = 0;
|
||||
/// <summary>
|
||||
/// Last time the local entity has been updated,
|
||||
/// </summary>
|
||||
public ulong LastUpdated { get; set; } = 0;
|
||||
#endregion
|
||||
|
||||
public Vector3 Position { get; set; }
|
||||
public Vector3 Rotation { get; set; }
|
||||
public Quaternion Quaternion { get; set; }
|
||||
public Vector3 Velocity { get; set; }
|
||||
public abstract void Update();
|
||||
public void PauseUpdate(ulong frames)
|
||||
{
|
||||
LastUpdated=Main.Ticked+frames;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class SyncedProjectile : SyncedEntity
|
||||
{
|
||||
public SyncedProjectile(Projectile p)
|
||||
{
|
||||
ID=EntityPool.RequestNewID();
|
||||
IsMine=true;
|
||||
MainProjectile = p;
|
||||
Origin=p.Position;
|
||||
var shooter = EntityPool.GetPedByHandle((p.Owner?.Handle).GetValueOrDefault());
|
||||
if(shooter != null)
|
||||
{
|
||||
ShooterID=shooter.ID;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
ShooterID=shooterVeh.MainVehicle.Driver.GetSyncEntity().ID;
|
||||
}
|
||||
else
|
||||
{
|
||||
Main.Logger.Warning($"Could not find owner for projectile:{Hash}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public SyncedProjectile(int id)
|
||||
{
|
||||
ID= id;
|
||||
IsMine=false;
|
||||
}
|
||||
public new bool IsMine { get; private set; }
|
||||
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; }
|
||||
|
||||
/// <summary>
|
||||
/// Invalid property for projectile.
|
||||
/// </summary>
|
||||
private new int OwnerID{ set { } }
|
||||
public WeaponHash Hash { get; set; }
|
||||
private WeaponAsset Asset { get; set; }
|
||||
public override void Update()
|
||||
{
|
||||
|
||||
// Skip update if no new sync message has arrived.
|
||||
if (!NeedUpdate){ return; }
|
||||
|
||||
if (MainProjectile == null || !MainProjectile.Exists())
|
||||
{
|
||||
CreateProjectile();
|
||||
return;
|
||||
}
|
||||
MainProjectile.PositionNoOffset=Position+Velocity*Networking.Latency;
|
||||
MainProjectile.Velocity=Velocity;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
EntityPool.Add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,407 +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
|
||||
{
|
||||
internal class SyncedVehicle : SyncedEntity
|
||||
{
|
||||
|
||||
#region -- CONSTRUCTORS --
|
||||
|
||||
/// <summary>
|
||||
/// Create a local entity (outgoing sync)
|
||||
/// </summary>
|
||||
/// <param name="p"></param>
|
||||
public SyncedVehicle(Vehicle v)
|
||||
{
|
||||
|
||||
ID=EntityPool.RequestNewID();
|
||||
MainVehicle=v;
|
||||
MainVehicle.CanPretendOccupants=false;
|
||||
OwnerID=Main.LocalPlayerID;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty VehicleEntity
|
||||
/// </summary>
|
||||
public SyncedVehicle()
|
||||
{
|
||||
|
||||
}
|
||||
public SyncedVehicle(int id)
|
||||
{
|
||||
ID=id;
|
||||
LastSynced=Main.Ticked;
|
||||
}
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// VehicleSeat,ID
|
||||
/// </summary>
|
||||
public Vehicle MainVehicle { get; set; }
|
||||
|
||||
|
||||
#region LAST STATE STORE
|
||||
|
||||
|
||||
private byte[] _lastVehicleColors = new byte[] { 0, 0 };
|
||||
private Dictionary<int, int> _lastVehicleMods = new Dictionary<int, int>();
|
||||
private byte _lastRadioIndex=255;
|
||||
#endregion
|
||||
|
||||
#region -- CRITICAL STUFF --
|
||||
public Vector3 RotationVelocity { get; set; }
|
||||
public float SteeringAngle { get; set; }
|
||||
public float ThrottlePower { get; set; }
|
||||
public float BrakePower { get; set; }
|
||||
public float DeluxoWingRatio { get; set; } = -1;
|
||||
#endregion
|
||||
|
||||
#region -- VEHICLE STATE --
|
||||
public VehicleDataFlags Flags { get; set; }
|
||||
public bool EngineRunning { get; set; }
|
||||
private bool _lastTransformed = false;
|
||||
public bool Transformed { get; set; }
|
||||
private bool _lastHornActive = false;
|
||||
public bool HornActive { get; set; }
|
||||
public bool LightsOn { get; set; }
|
||||
public bool BrakeLightsOn { get; set; } = false;
|
||||
public bool HighBeamsOn { get; set; }
|
||||
public byte LandingGear { get; set; }
|
||||
public bool RoofOpened { get; set; }
|
||||
public bool SireneActive { get; set; }
|
||||
public VehicleDamageModel DamageModel { get; set; }
|
||||
public int ModelHash { get; set; }
|
||||
public byte[] Colors { get; set; }
|
||||
public Dictionary<int, int> Mods { get; set; }
|
||||
public bool IsDead { get; set; }
|
||||
public float EngineHealth { get; set; }
|
||||
public VehicleLockStatus LockStatus{get;set;}
|
||||
/// <summary>
|
||||
/// VehicleSeat,PedID
|
||||
/// </summary>
|
||||
public Dictionary<VehicleSeat, SyncedPed> Passengers { get; set; }
|
||||
public byte RadioStation = 255;
|
||||
private long _lastPositionCalibrated { get; set; }
|
||||
|
||||
#endregion
|
||||
public 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);
|
||||
}
|
||||
if (MainVehicle.ThrottlePower!=ThrottlePower)
|
||||
{
|
||||
MainVehicle.ThrottlePower=ThrottlePower;
|
||||
}
|
||||
if (MainVehicle.BrakePower!=BrakePower)
|
||||
{
|
||||
MainVehicle.BrakePower=BrakePower;
|
||||
}
|
||||
if (MainVehicle.Position.DistanceTo(Position)<5)
|
||||
{
|
||||
MainVehicle.Velocity = Velocity+5*(Position+Velocity*SyncParameters.PositioinPredictionDefault - MainVehicle.Position);
|
||||
MainVehicle.Quaternion=Quaternion.Slerp(MainVehicle.Quaternion, Quaternion, 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainVehicle.Position=Position;
|
||||
MainVehicle.Velocity=Velocity;
|
||||
MainVehicle.Quaternion=Quaternion;
|
||||
}
|
||||
// Vector3 r = GetCalibrationRotation();
|
||||
MainVehicle.RotationVelocity = RotationVelocity;
|
||||
if (DeluxoWingRatio!=-1)
|
||||
{
|
||||
MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
|
||||
}
|
||||
#endregion
|
||||
if (LastStateSynced>LastUpdated)
|
||||
{
|
||||
#region -- SYNC STATE --
|
||||
#region -- PASSENGER SYNC --
|
||||
|
||||
// check passengers (and driver).
|
||||
|
||||
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!=_lastRadioIndex))
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (seat==VehicleSeat.Driver &&MainVehicle.Driver.IsSittingInVehicle())
|
||||
{
|
||||
MainVehicle.Driver.Task.WarpOutOfVehicle(MainVehicle);
|
||||
}
|
||||
else
|
||||
{
|
||||
var p = MainVehicle.Passengers.Where(x => x.SeatIndex==seat).FirstOrDefault();
|
||||
if ((p!=null)&&p.IsSittingInVehicle())
|
||||
{
|
||||
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)
|
||||
{
|
||||
bool roofOpened = MainVehicle.RoofState == VehicleRoofState.Opened || MainVehicle.RoofState == VehicleRoofState.Opening;
|
||||
if (roofOpened != RoofOpened)
|
||||
{
|
||||
MainVehicle.RoofState = RoofOpened ? VehicleRoofState.Opening : VehicleRoofState.Closing;
|
||||
}
|
||||
}
|
||||
|
||||
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
|
||||
MainVehicle.SetDamageModel(DamageModel);
|
||||
|
||||
}
|
||||
MainVehicle.LockStatus=LockStatus;
|
||||
if (Flags.HasFlag(VehicleDataFlags.IsDeluxoHovering))
|
||||
{
|
||||
if (!MainVehicle.IsDeluxoHovering())
|
||||
{
|
||||
MainVehicle.SetDeluxoHoverState(true);
|
||||
}
|
||||
}
|
||||
else if(ModelHash==1483171323)
|
||||
{
|
||||
if (MainVehicle.IsDeluxoHovering())
|
||||
{
|
||||
MainVehicle.SetDeluxoHoverState(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
LastUpdated=Main.Ticked;
|
||||
}
|
||||
private Vector3 GetCalibrationRotation()
|
||||
{
|
||||
return (Quaternion-MainVehicle.Quaternion).ToEulerAngles().ToDegree();
|
||||
/*
|
||||
var r = Rotation-MainVehicle.Rotation;
|
||||
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)
|
||||
{
|
||||
bool roofOpened = MainVehicle.RoofState == VehicleRoofState.Opened || MainVehicle.RoofState == VehicleRoofState.Opening;
|
||||
if (roofOpened != RoofOpened)
|
||||
{
|
||||
MainVehicle.RoofState = RoofOpened ? VehicleRoofState.Opened : VehicleRoofState.Closed;
|
||||
}
|
||||
}
|
||||
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
|
||||
public float LastNozzleAngle { get; set; }
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,561 +0,0 @@
|
||||
|
||||
using System;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using RageCoop.Core;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class EntityPool
|
||||
{
|
||||
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>();
|
||||
|
||||
|
||||
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 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 void Cleanup(bool keepPlayer=true,bool keepMine=true)
|
||||
{
|
||||
foreach(int id in new List<int>(ID_Peds.Keys))
|
||||
{
|
||||
if (keepPlayer&&(id==Main.LocalPlayerID)) { continue; }
|
||||
if (keepMine&&(ID_Peds[id].OwnerID==Main.LocalPlayerID)) { continue; }
|
||||
RemovePed(id);
|
||||
}
|
||||
ID_Peds.Clear();
|
||||
Handle_Peds.Clear();
|
||||
|
||||
foreach (int id in new List<int>(ID_Vehicles.Keys))
|
||||
{
|
||||
if (keepMine&&(ID_Vehicles[id].OwnerID==Main.LocalPlayerID)) { continue; }
|
||||
RemoveVehicle(id);
|
||||
}
|
||||
ID_Vehicles.Clear();
|
||||
Handle_Vehicles.Clear();
|
||||
|
||||
foreach(var p in ID_Projectiles.Values)
|
||||
{
|
||||
if (p.ShooterID!=Main.LocalPlayerID && p.MainProjectile!=null && p.MainProjectile.Exists())
|
||||
{
|
||||
p.MainProjectile.Delete();
|
||||
}
|
||||
}
|
||||
ID_Projectiles.Clear();
|
||||
Handle_Projectiles.Clear();
|
||||
}
|
||||
|
||||
#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 bool AddPlayer()
|
||||
{
|
||||
Ped p = Game.Player.Character;
|
||||
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
|
||||
{
|
||||
Main.Logger.Debug($"Creating SyncEntity for player, handle:{p.Handle}");
|
||||
SyncedPed c = new SyncedPed(p);
|
||||
Main.LocalPlayerID=c.OwnerID=c.ID;
|
||||
Add(c);
|
||||
Main.Logger.Debug($"My player ID is:{c.ID}");
|
||||
PlayerList.SetPlayer(c.ID, Main.Settings.Username );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static void Add(SyncedPed c)
|
||||
{
|
||||
if (ID_Peds.ContainsKey(c.ID))
|
||||
{
|
||||
ID_Peds[c.ID]=c;
|
||||
}
|
||||
else
|
||||
{
|
||||
ID_Peds.Add(c.ID, c);
|
||||
}
|
||||
if (c.MainPed==null) { return; }
|
||||
if (Handle_Peds.ContainsKey(c.MainPed.Handle))
|
||||
{
|
||||
Handle_Peds[c.MainPed.Handle]=c;
|
||||
}
|
||||
else
|
||||
{
|
||||
Handle_Peds.Add(c.MainPed.Handle, c);
|
||||
}
|
||||
}
|
||||
public static void RemovePed(int id,string reason="Cleanup")
|
||||
{
|
||||
if (ID_Peds.ContainsKey(id))
|
||||
{
|
||||
SyncedPed c = ID_Peds[id];
|
||||
var p = c.MainPed;
|
||||
if (p!=null)
|
||||
{
|
||||
if (Handle_Peds.ContainsKey(p.Handle))
|
||||
{
|
||||
Handle_Peds.Remove(p.Handle);
|
||||
}
|
||||
Main.Logger.Debug($"Removing ped {c.ID}. Reason:{reason}");
|
||||
p.AttachedBlip?.Delete();
|
||||
p.Kill();
|
||||
p.MarkAsNoLongerNeeded();
|
||||
p.Delete();
|
||||
}
|
||||
c.PedBlip?.Delete();
|
||||
c.ParachuteProp?.Delete();
|
||||
ID_Peds.Remove(id);
|
||||
}
|
||||
}
|
||||
#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 void Add(SyncedVehicle v)
|
||||
{
|
||||
if (ID_Vehicles.ContainsKey(v.ID))
|
||||
{
|
||||
ID_Vehicles[v.ID]=v;
|
||||
}
|
||||
else
|
||||
{
|
||||
ID_Vehicles.Add(v.ID, v);
|
||||
}
|
||||
if (v.MainVehicle==null) { return; }
|
||||
if (Handle_Vehicles.ContainsKey(v.MainVehicle.Handle))
|
||||
{
|
||||
Handle_Vehicles[v.MainVehicle.Handle]=v;
|
||||
}
|
||||
else
|
||||
{
|
||||
Handle_Vehicles.Add(v.MainVehicle.Handle, v);
|
||||
}
|
||||
}
|
||||
public static void RemoveVehicle(int id,string reason = "Cleanup")
|
||||
{
|
||||
if (ID_Vehicles.ContainsKey(id))
|
||||
{
|
||||
SyncedVehicle v = ID_Vehicles[id];
|
||||
var veh = v.MainVehicle;
|
||||
if (veh!=null)
|
||||
{
|
||||
if (Handle_Vehicles.ContainsKey(veh.Handle))
|
||||
{
|
||||
Handle_Vehicles.Remove(veh.Handle);
|
||||
}
|
||||
Main.Logger.Debug($"Removing vehicle {v.ID}. Reason:{reason}");
|
||||
veh.AttachedBlip?.Delete();
|
||||
veh.MarkAsNoLongerNeeded();
|
||||
veh.Delete();
|
||||
}
|
||||
ID_Vehicles.Remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PROJECTILES
|
||||
public static SyncedProjectile GetProjectileByID(int id)
|
||||
{
|
||||
return ID_Projectiles.ContainsKey(id) ? ID_Projectiles[id] : null;
|
||||
}
|
||||
public static void Add(SyncedProjectile p)
|
||||
{
|
||||
if (ID_Projectiles.ContainsKey(p.ID))
|
||||
{
|
||||
ID_Projectiles[p.ID]=p;
|
||||
}
|
||||
else
|
||||
{
|
||||
ID_Projectiles.Add(p.ID, p);
|
||||
}
|
||||
if (p.MainProjectile==null) { return; }
|
||||
if (Handle_Projectiles.ContainsKey(p.MainProjectile.Handle))
|
||||
{
|
||||
Handle_Projectiles[p.MainProjectile.Handle]=p;
|
||||
}
|
||||
else
|
||||
{
|
||||
Handle_Projectiles.Add(p.MainProjectile.Handle, p);
|
||||
}
|
||||
}
|
||||
public static void RemoveProjectile(int id, string reason)
|
||||
{
|
||||
if (ID_Projectiles.ContainsKey(id))
|
||||
{
|
||||
SyncedProjectile sp = ID_Projectiles[id];
|
||||
var p = sp.MainProjectile;
|
||||
if (p!=null)
|
||||
{
|
||||
if (Handle_Projectiles.ContainsKey(p.Handle))
|
||||
{
|
||||
Handle_Projectiles.Remove(p.Handle);
|
||||
}
|
||||
Main.Logger.Debug($"Removing projectile {sp.ID}. Reason:{reason}");
|
||||
p.Explode();
|
||||
}
|
||||
ID_Projectiles.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);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public static void DoSync()
|
||||
{
|
||||
#if BENCHMARK
|
||||
PerfCounter.Restart();
|
||||
Debug.TimeStamps[TimeStamp.CheckProjectiles]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
var allPeds = World.GetAllPeds();
|
||||
var allVehicles=World.GetAllVehicles();
|
||||
var allProjectiles=World.GetAllProjectiles();
|
||||
if (Main.Settings.WorldVehicleSoftLimit>-1)
|
||||
{
|
||||
if (Main.Ticked%100==0) { if (allVehicles.Length>Main.Settings.WorldVehicleSoftLimit) { SetBudget(0); } else { SetBudget(1); } }
|
||||
}
|
||||
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.GetAllEntities]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
|
||||
lock (ProjectilesLock)
|
||||
{
|
||||
|
||||
foreach (Projectile p in allProjectiles)
|
||||
{
|
||||
if (!Handle_Projectiles.ContainsKey(p.Handle))
|
||||
{
|
||||
Add(new SyncedProjectile(p));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
foreach (SyncedProjectile p in ID_Projectiles.Values.ToArray())
|
||||
{
|
||||
|
||||
// Outgoing sync
|
||||
if (p.IsMine)
|
||||
{
|
||||
if (p.MainProjectile.AttachedEntity==null)
|
||||
{
|
||||
|
||||
/// Prevent projectiles from exploding next to vehicle
|
||||
if (WeaponUtil.VehicleProjectileWeapons.Contains((VehicleWeaponHash)p.MainProjectile.WeaponHash))
|
||||
{
|
||||
if (p.MainProjectile.WeaponHash!=(WeaponHash)VehicleWeaponHash.Tank && p.Origin.DistanceTo(p.MainProjectile.Position)<2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Networking.SendProjectile(p);
|
||||
}
|
||||
}
|
||||
else // Incoming sync
|
||||
{
|
||||
if (p.Exploded || p.IsOutOfSync)
|
||||
{
|
||||
RemoveProjectile(p.ID, "OutOfSync | Exploded");
|
||||
}
|
||||
else
|
||||
{
|
||||
p.Update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
lock (PedsLock)
|
||||
{
|
||||
EntityPool.AddPlayer();
|
||||
|
||||
foreach (Ped p in allPeds)
|
||||
{
|
||||
SyncedPed c = EntityPool.GetPedByHandle(p.Handle);
|
||||
if (c==null && (p!=Game.Player.Character))
|
||||
{
|
||||
Main.Logger.Trace($"Creating SyncEntity for ped, handle:{p.Handle}");
|
||||
c=new SyncedPed(p);
|
||||
|
||||
EntityPool.Add(c);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.AddPeds]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
|
||||
foreach (SyncedPed c in ID_Peds.Values.ToArray())
|
||||
{
|
||||
if ((c.MainPed!=null)&&(!c.MainPed.Exists()))
|
||||
{
|
||||
EntityPool.RemovePed(c.ID, "non-existent");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Outgoing sync
|
||||
if (c.IsMine)
|
||||
{
|
||||
#if BENCHMARK
|
||||
var start = PerfCounter2.ElapsedTicks;
|
||||
#endif
|
||||
// event check
|
||||
SyncEvents.Check(c);
|
||||
|
||||
if (Main.Ticked%20==0)
|
||||
{
|
||||
Networking.SendPed(c);
|
||||
Networking.SendPedState(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
Networking.SendPed(c);
|
||||
}
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.SendPed]=PerfCounter2.ElapsedTicks-start;
|
||||
#endif
|
||||
}
|
||||
else // Incoming sync
|
||||
{
|
||||
#if BENCHMARK
|
||||
var start = PerfCounter2.ElapsedTicks;
|
||||
#endif
|
||||
c.Update();
|
||||
if (c.IsOutOfSync)
|
||||
{
|
||||
RemovePed(c.ID, "OutOfSync");
|
||||
}
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.UpdatePed]=PerfCounter2.ElapsedTicks-start;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.PedTotal]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
}
|
||||
lock (VehiclesLock)
|
||||
{
|
||||
|
||||
foreach (Vehicle veh in allVehicles)
|
||||
{
|
||||
if (!Handle_Vehicles.ContainsKey(veh.Handle))
|
||||
{
|
||||
Main.Logger.Debug($"Creating SyncEntity for vehicle, handle:{veh.Handle}");
|
||||
|
||||
EntityPool.Add(new SyncedVehicle(veh));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.AddVehicles]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
foreach (SyncedVehicle v in ID_Vehicles.Values.ToArray())
|
||||
{
|
||||
if ((v.MainVehicle!=null)&&(!v.MainVehicle.Exists()))
|
||||
{
|
||||
EntityPool.RemoveVehicle(v.ID,"non-existent");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Outgoing sync
|
||||
if (v.IsMine)
|
||||
{
|
||||
SyncEvents.Check(v);
|
||||
if (Main.Ticked%20==0)
|
||||
{
|
||||
Networking.SendVehicle(v);
|
||||
Networking.SendVehicleState(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
Networking.SendVehicle(v);
|
||||
}
|
||||
|
||||
}
|
||||
else // Incoming sync
|
||||
{
|
||||
|
||||
|
||||
v.Update();
|
||||
if (v.IsOutOfSync)
|
||||
{
|
||||
RemoveVehicle(v.ID, "OutOfSync");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#if BENCHMARK
|
||||
Debug.TimeStamps[TimeStamp.VehicleTotal]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void RemoveAllFromPlayer(int playerPedId)
|
||||
{
|
||||
foreach(SyncedPed p in ID_Peds.Values.ToArray())
|
||||
{
|
||||
if (p.OwnerID==playerPedId)
|
||||
{
|
||||
RemovePed(p.ID);
|
||||
}
|
||||
}
|
||||
foreach (SyncedVehicle v in ID_Vehicles.Values.ToArray())
|
||||
{
|
||||
if (v.OwnerID==playerPedId)
|
||||
{
|
||||
RemoveVehicle(v.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int RequestNewID()
|
||||
{
|
||||
int ID=0;
|
||||
while ((ID==0)
|
||||
|| ID_Peds.ContainsKey(ID)
|
||||
|| ID_Vehicles.ContainsKey(ID)
|
||||
|| ID_Projectiles.ContainsKey(ID))
|
||||
{
|
||||
byte[] rngBytes = new byte[4];
|
||||
|
||||
RandomNumberGenerator.Create().GetBytes(rngBytes);
|
||||
|
||||
// Convert the bytes into an integer
|
||||
ID = BitConverter.ToInt32(rngBytes, 0);
|
||||
}
|
||||
return ID;
|
||||
}
|
||||
private static void SetBudget(int b)
|
||||
{
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, b); // 0 - 3
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, b); // 0 - 3
|
||||
}
|
||||
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;
|
||||
return s;
|
||||
}
|
||||
public static class ThreadSafe
|
||||
{
|
||||
public static void Add(SyncedVehicle v)
|
||||
{
|
||||
lock (EntityPool.VehiclesLock)
|
||||
{
|
||||
EntityPool.Add(v);
|
||||
}
|
||||
}
|
||||
public static void Add(SyncedPed p)
|
||||
{
|
||||
lock (EntityPool.PedsLock)
|
||||
{
|
||||
EntityPool.Add(p);
|
||||
}
|
||||
}
|
||||
public static void Add(SyncedProjectile sp)
|
||||
{
|
||||
lock (EntityPool.ProjectilesLock)
|
||||
{
|
||||
EntityPool.Add(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,416 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using RageCoop.Core;
|
||||
using GTA.Native;
|
||||
using System.Threading;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
Networking.Send(new Packets.OwnerChanged()
|
||||
{
|
||||
ID= c.ID,
|
||||
NewOwnerID= newOwnerID,
|
||||
}, ConnectionChannel.SyncEvents);
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Reduce latency
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
public static void TriggerNozzleTransform(int vehID,bool hover)
|
||||
{
|
||||
Networking.Send(new Packets.NozzleTransform() { VehicleID=vehID, Hover=hover }, ConnectionChannel.SyncEvents);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region HANDLE
|
||||
|
||||
public static ParticleEffectAsset CorePFXAsset = new ParticleEffectAsset("core");
|
||||
|
||||
static WeaponAsset _weaponAsset = default;
|
||||
static uint _lastWeaponHash;
|
||||
|
||||
private static void HandleLeaveVehicle(Packets.LeaveVehicle p)
|
||||
{
|
||||
var ped = EntityPool.GetPedByID(p.ID);
|
||||
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) ;
|
||||
}
|
||||
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
|
||||
}
|
||||
private static void HandleNozzleTransform(Packets.NozzleTransform p)
|
||||
{
|
||||
EntityPool.GetVehicleByID(p.VehicleID)?.MainVehicle?.SetNozzleAngel(p.Hover ? 1 : 0);
|
||||
}
|
||||
private static void HandleBulletShot(Vector3 start, Vector3 end, uint weaponHash, int ownerID)
|
||||
{
|
||||
switch (weaponHash)
|
||||
{
|
||||
// Minigun, not working for some reason
|
||||
case (uint)WeaponHash.Minigun:
|
||||
weaponHash=1176362416;
|
||||
break;
|
||||
|
||||
// Valkyire, not working for some reason
|
||||
case 2756787765:
|
||||
weaponHash=1176362416;
|
||||
break;
|
||||
|
||||
// SAVAGE
|
||||
case 1638077257:
|
||||
weaponHash=(uint)VehicleWeaponHash.PlayerLazer;
|
||||
break;
|
||||
|
||||
case (uint)VehicleWeaponHash.PlayerBuzzard:
|
||||
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 (!CorePFXAsset.IsLoaded) { CorePFXAsset.Request(); }
|
||||
if (_lastWeaponHash!=weaponHash)
|
||||
{
|
||||
_weaponAsset.MarkAsNoLongerNeeded();
|
||||
_weaponAsset=new WeaponAsset(weaponHash);
|
||||
_lastWeaponHash=weaponHash;
|
||||
}
|
||||
if (!_weaponAsset.IsLoaded) { _weaponAsset.Request(); }
|
||||
World.ShootBullet(start, end, p, _weaponAsset, p.GetWeaponDamage(weaponHash));
|
||||
Prop w;
|
||||
if(((w = p.Weapons.CurrentWeaponObject) != null)&&(p.VehicleWeapon==VehicleWeaponHash.Invalid))
|
||||
{
|
||||
if (p.Weapons.Current.Components.GetSuppressorComponent().Active)
|
||||
{
|
||||
World.CreateParticleEffectNonLooped(CorePFXAsset, "muz_pistol_silencer", p.GetMuzzlePosition(), w.Rotation, 1);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void HandleEvent(PacketTypes type,byte[] data)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PacketTypes.BulletShot:
|
||||
{
|
||||
Packets.BulletShot p = new Packets.BulletShot();
|
||||
p.Unpack(data);
|
||||
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
|
||||
break;
|
||||
}
|
||||
case PacketTypes.EnteringVehicle:
|
||||
{
|
||||
Packets.EnteringVehicle p = new Packets.EnteringVehicle();
|
||||
p.Unpack(data);
|
||||
HandleEnteringVehicle(EntityPool.GetPedByID(p.PedID), EntityPool.GetVehicleByID(p.VehicleID), (VehicleSeat)p.VehicleSeat);
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketTypes.LeaveVehicle:
|
||||
{
|
||||
Packets.LeaveVehicle packet = new Packets.LeaveVehicle();
|
||||
packet.Unpack(data);
|
||||
HandleLeaveVehicle(packet);
|
||||
}
|
||||
break;
|
||||
case PacketTypes.OwnerChanged:
|
||||
{
|
||||
Packets.OwnerChanged packet = new Packets.OwnerChanged();
|
||||
packet.Unpack(data);
|
||||
HandleOwnerChanged(packet);
|
||||
}
|
||||
break;
|
||||
case PacketTypes.PedKilled:
|
||||
{
|
||||
var packet = new Packets.PedKilled();
|
||||
packet.Unpack(data);
|
||||
HandlePedKilled(packet);
|
||||
}
|
||||
break;
|
||||
case PacketTypes.EnteredVehicle:
|
||||
{
|
||||
var packet = new Packets.EnteredVehicle();
|
||||
packet.Unpack(data);
|
||||
HandleEnteredVehicle(packet.PedID,packet.VehicleID,(VehicleSeat)packet.VehicleSeat);
|
||||
break;
|
||||
}
|
||||
case PacketTypes.NozzleTransform:
|
||||
{
|
||||
var packet = new Packets.NozzleTransform();
|
||||
packet.Unpack(data);
|
||||
HandleNozzleTransform(packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static int GetWeaponDamage(this Ped p,uint hash)
|
||||
{
|
||||
if(p.IsInVehicle() && (hash!=(uint)p.Weapons.Current.Hash))
|
||||
{
|
||||
// This is a vehicle weapon
|
||||
p.VehicleWeapon=(VehicleWeaponHash)hash;
|
||||
return 100;
|
||||
}
|
||||
switch (p.Weapons.Current.Group)
|
||||
{
|
||||
case WeaponGroup.Pistol: return 30;
|
||||
case WeaponGroup.AssaultRifle: return 30;
|
||||
case WeaponGroup.SMG: return 20;
|
||||
case WeaponGroup.MG: return 40;
|
||||
case WeaponGroup.Shotgun: return 30;
|
||||
case WeaponGroup.Sniper: return 200;
|
||||
case WeaponGroup.Heavy: return 30;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region CHECK EVENTS
|
||||
|
||||
|
||||
public static void Check(SyncedPed c)
|
||||
{
|
||||
Ped subject = c.MainPed;
|
||||
|
||||
// Check bullets
|
||||
if (subject.IsShooting)
|
||||
{
|
||||
if (!subject.IsUsingProjectileWeapon())
|
||||
{
|
||||
int i = 0;
|
||||
Func<bool> getBulletImpact = (() =>
|
||||
{
|
||||
Vector3 endPos = subject.LastWeaponImpactPosition;
|
||||
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 (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;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
if (!getBulletImpact())
|
||||
{
|
||||
Main.QueueAction(getBulletImpact);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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.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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,471 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
// Potential names and hash collisions included as comments
|
||||
public 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,
|
||||
}
|
||||
}
|
||||
@@ -1,438 +0,0 @@
|
||||
// WARNING: values can change after a game update
|
||||
// if R* adds in the middle!
|
||||
// This is up-to-date for b2372
|
||||
public 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
|
||||
};
|
||||
@@ -1,200 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA.Math;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using System.IO;
|
||||
using System.Xml.Serialization;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class Util
|
||||
{
|
||||
#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)
|
||||
{
|
||||
IntPtr address = new IntPtr((long)veh.MemoryAddress);
|
||||
if (address == IntPtr.Zero || _steeringAngleOffset == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*(float*)(address + _steeringAngleOffset).ToPointer() = value;
|
||||
}
|
||||
#endregion
|
||||
#region MATH
|
||||
public static Vector3 LinearVectorLerp(Vector3 start, Vector3 end, ulong currentTime, int duration)
|
||||
{
|
||||
return new Vector3()
|
||||
{
|
||||
X = LinearFloatLerp(start.X, end.X, currentTime, duration),
|
||||
Y = LinearFloatLerp(start.Y, end.Y, currentTime, duration),
|
||||
Z = LinearFloatLerp(start.Z, end.Z, currentTime, duration),
|
||||
};
|
||||
}
|
||||
|
||||
public static float LinearFloatLerp(float start, float end, ulong currentTime, int duration)
|
||||
{
|
||||
return (end - start) * currentTime / duration + start;
|
||||
}
|
||||
|
||||
public static float Lerp(float from, float to, float fAlpha)
|
||||
{
|
||||
return (from * (1.0f - fAlpha)) + (to * fAlpha); //from + (to - from) * fAlpha
|
||||
}
|
||||
|
||||
public static Vector3 RotationToDirection(Vector3 rotation)
|
||||
{
|
||||
double z = MathExtensions.DegToRad(rotation.Z);
|
||||
double x = MathExtensions.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)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
public static Settings ReadSettings()
|
||||
{
|
||||
XmlSerializer ser = new XmlSerializer(typeof(Settings));
|
||||
|
||||
string path = Directory.GetCurrentDirectory() + "\\Scripts\\RageCoop\\RageCoop.Client.Settings.xml";
|
||||
Settings settings = null;
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (FileStream stream = File.OpenWrite(path))
|
||||
{
|
||||
ser.Serialize(stream, settings = new Settings());
|
||||
}
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
public static void SaveSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
string path = Directory.GetCurrentDirectory() + "\\Scripts\\RageCoop\\RageCoop.Client.Settings.xml";
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GTA.UI.Notification.Show("Error saving player settings: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern ulong GetTickCount64();
|
||||
public static Vector3 PredictPosition(this Entity e, bool applyDefault = true)
|
||||
{
|
||||
return e.Position+e.Velocity*((applyDefault ? SyncParameters.PositioinPredictionDefault : 0)+Networking.Latency);
|
||||
}
|
||||
|
||||
public static Model ModelRequest(this int hash)
|
||||
{
|
||||
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;
|
||||
}
|
||||
public static void SetOnFire(this Entity e, bool toggle)
|
||||
{
|
||||
if (toggle)
|
||||
{
|
||||
Function.Call(Hash.START_ENTITY_FIRE, e.Handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
Function.Call(Hash.STOP_ENTITY_FIRE, e.Handle);
|
||||
}
|
||||
}
|
||||
|
||||
public static SyncedPed GetSyncEntity(this Ped p)
|
||||
{
|
||||
if (p == null) { return null; }
|
||||
var c = EntityPool.GetPedByHandle(p.Handle);
|
||||
if (c==null) { EntityPool.Add(c=new SyncedPed(p)); }
|
||||
return c;
|
||||
}
|
||||
|
||||
public static SyncedVehicle GetSyncEntity(this Vehicle veh)
|
||||
{
|
||||
if (veh == null) { return null; }
|
||||
var v = EntityPool.GetVehicleByHandle(veh.Handle);
|
||||
if (v==null) { EntityPool.Add(v=new SyncedVehicle(veh)); }
|
||||
return v;
|
||||
}
|
||||
|
||||
public static byte GetPlayerRadioIndex()
|
||||
{
|
||||
return (byte)Function.Call<int>(Hash.GET_PLAYER_RADIO_STATION_INDEX);
|
||||
}
|
||||
public static void SetPlayerRadioIndex(int index)
|
||||
{
|
||||
Function.Call(Hash.SET_RADIO_TO_STATION_INDEX, index);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class MuzzleInfo
|
||||
{
|
||||
public MuzzleInfo(Vector3 pos,Vector3 forward)
|
||||
{
|
||||
Position = pos;
|
||||
ForawardVector=forward;
|
||||
}
|
||||
public Vector3 Position;
|
||||
public Vector3 ForawardVector;
|
||||
}
|
||||
internal static class WeaponUtil
|
||||
{
|
||||
public static Vector3 GetMuzzlePosition(this Ped p)
|
||||
{
|
||||
var w = p.Weapons.CurrentWeaponObject;
|
||||
if (w!=null)
|
||||
{
|
||||
var hash = p.Weapons.Current.Hash;
|
||||
if (MuzzleBoneIndexes.ContainsKey(hash)) { return w.Bones[MuzzleBoneIndexes[hash]].Position; }
|
||||
return w.Position;
|
||||
}
|
||||
return p.Bones[Bone.SkelRightHand].Position;
|
||||
}
|
||||
static long BulletsShot=0;
|
||||
public static MuzzleInfo GetMuzzleInfo(this Vehicle v)
|
||||
{
|
||||
BulletsShot++;
|
||||
int i;
|
||||
switch (v.Model.Hash)
|
||||
{
|
||||
// SCRAMJET
|
||||
case -638562243:
|
||||
i=BulletsShot%2==0 ? 44 : 45;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// VIGILANTE
|
||||
case -1242608589:
|
||||
i=BulletsShot%2==0 ? 42 : 43;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// ZR380
|
||||
case 540101442:
|
||||
i=BulletsShot%2==0 ? 57 : 63;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// ZR3802
|
||||
case -1106120762:
|
||||
i=BulletsShot%2==0 ? 57 : 63;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// ZR3803
|
||||
case -1478704292:
|
||||
i=BulletsShot%2==0 ? 53 : 59;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// STROMBERG
|
||||
case 886810209:
|
||||
i=BulletsShot%2==0 ? 85 : 84;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// SLAMVAN4
|
||||
case -2061049099:
|
||||
i=BulletsShot%2==0 ? 76 : 78;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// IMPERATOR
|
||||
case 444994115:
|
||||
i=BulletsShot%2==0 ? 88 : 86;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// IMPALER2
|
||||
case 1009171724:
|
||||
i=BulletsShot%2==0 ? 63 : 64;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// DOMINATOR4
|
||||
case -688189648:
|
||||
i=BulletsShot%2==0 ? 59 : 60;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// SAVAGE
|
||||
case -82626025:
|
||||
return new MuzzleInfo(v.Bones[30].Position, v.Bones[30].ForwardVector);
|
||||
|
||||
// BUZZARD
|
||||
case 788747387:
|
||||
i=BulletsShot%2==0 ? 28 : 23;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// ANNIHL
|
||||
case 837858166:
|
||||
i=(int)BulletsShot%4+35;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// HYDRA
|
||||
case 970385471:
|
||||
i=BulletsShot%2==0 ? 29 : 28;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// STARLING
|
||||
case -1700874274:
|
||||
i=BulletsShot%2==0 ? 24 : 12;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// RHINO
|
||||
case 782665360:
|
||||
return new MuzzleInfo(v.Bones[35].Position,v.Bones[35].ForwardVector);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsUsingProjectileWeapon(this Ped p)
|
||||
{
|
||||
var vp = p.VehicleWeapon;
|
||||
if (vp!=VehicleWeaponHash.Invalid)
|
||||
{
|
||||
return VehicleProjectileWeapons.Contains(vp);
|
||||
}
|
||||
else
|
||||
{
|
||||
var w = p.Weapons.Current;
|
||||
return w.Group==WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly Dictionary<WeaponHash, int> MuzzleBoneIndexes = new Dictionary<WeaponHash, int>
|
||||
{
|
||||
{WeaponHash.HeavySniper,6},
|
||||
{WeaponHash.MarksmanRifle,9},
|
||||
{WeaponHash.SniperRifle,9},
|
||||
{WeaponHash.AdvancedRifle,5},
|
||||
{WeaponHash.SpecialCarbine,9},
|
||||
{WeaponHash.BullpupRifle,7},
|
||||
{WeaponHash.AssaultRifle,9},
|
||||
{WeaponHash.CarbineRifle,6},
|
||||
{WeaponHash.MachinePistol,5},
|
||||
{WeaponHash.SMG,5},
|
||||
{WeaponHash.AssaultSMG,6},
|
||||
{WeaponHash.CombatPDW,5},
|
||||
{WeaponHash.MG,6},
|
||||
{WeaponHash.CombatMG,7},
|
||||
{WeaponHash.Gusenberg,7},
|
||||
{WeaponHash.MicroSMG,10},
|
||||
{WeaponHash.APPistol,8},
|
||||
{WeaponHash.StunGun,4},
|
||||
{WeaponHash.Pistol,8},
|
||||
{WeaponHash.CombatPistol,8},
|
||||
{WeaponHash.Pistol50,7},
|
||||
{WeaponHash.SNSPistol,8},
|
||||
{WeaponHash.HeavyPistol,8},
|
||||
{WeaponHash.VintagePistol,8},
|
||||
{WeaponHash.Railgun,9},
|
||||
{WeaponHash.Minigun,5},
|
||||
{WeaponHash.Musket,3},
|
||||
{WeaponHash.HeavyShotgun,10},
|
||||
{WeaponHash.PumpShotgun,11},
|
||||
{WeaponHash.SawnOffShotgun,8},
|
||||
{WeaponHash.BullpupShotgun,8},
|
||||
{WeaponHash.AssaultShotgun,9},
|
||||
{WeaponHash.HeavySniperMk2,11},
|
||||
{WeaponHash.MarksmanRifleMk2,9},
|
||||
{WeaponHash.CarbineRifleMk2,13},
|
||||
{WeaponHash.SpecialCarbineMk2,16},
|
||||
{WeaponHash.BullpupRifleMk2,8},
|
||||
{WeaponHash.CompactRifle,7},
|
||||
{WeaponHash.MilitaryRifle,11},
|
||||
{WeaponHash.AssaultrifleMk2,17},
|
||||
{WeaponHash.MiniSMG,5},
|
||||
{WeaponHash.SMGMk2,6},
|
||||
{WeaponHash.CombatMGMk2,16},
|
||||
{WeaponHash.UnholyHellbringer,4},
|
||||
{WeaponHash.PistolMk2,12},
|
||||
{WeaponHash.SNSPistolMk2,15},
|
||||
{WeaponHash.CeramicPistol,10},
|
||||
{WeaponHash.MarksmanPistol,4},
|
||||
{WeaponHash.Revolver,7},
|
||||
{WeaponHash.RevolverMk2,7},
|
||||
{WeaponHash.DoubleActionRevolver,7},
|
||||
{WeaponHash.NavyRevolver,7},
|
||||
{WeaponHash.PericoPistol,4},
|
||||
{WeaponHash.FlareGun,4},
|
||||
{WeaponHash.UpNAtomizer,4},
|
||||
{WeaponHash.HomingLauncher,5},
|
||||
{WeaponHash.CompactGrenadeLauncher,8},
|
||||
{WeaponHash.Widowmaker,6},
|
||||
{WeaponHash.GrenadeLauncher,3},
|
||||
{WeaponHash.RPG,9},
|
||||
{WeaponHash.DoubleBarrelShotgun,8},
|
||||
{WeaponHash.SweeperShotgun,7},
|
||||
{WeaponHash.CombatShotgun,7},
|
||||
{WeaponHash.PumpShotgunMk2,7},
|
||||
|
||||
};
|
||||
|
||||
|
||||
public static readonly HashSet<WeaponHash> ProjectileWeapons = new HashSet<WeaponHash> {
|
||||
WeaponHash.HomingLauncher,
|
||||
WeaponHash.RPG,
|
||||
WeaponHash.Firework,
|
||||
WeaponHash.UpNAtomizer,
|
||||
WeaponHash.GrenadeLauncher,
|
||||
WeaponHash.GrenadeLauncherSmoke,
|
||||
WeaponHash.CompactGrenadeLauncher,
|
||||
WeaponHash.FlareGun,
|
||||
};
|
||||
public static readonly HashSet<VehicleWeaponHash> VehicleProjectileWeapons = new HashSet<VehicleWeaponHash> {
|
||||
VehicleWeaponHash.PlaneRocket,
|
||||
VehicleWeaponHash.SpaceRocket,
|
||||
VehicleWeaponHash.Tank,
|
||||
(VehicleWeaponHash)3565779982, // STROMBERG missiles
|
||||
(VehicleWeaponHash)3169388763, // SCRAMJET missiles
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
@@ -1,127 +0,0 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using GTA.Math;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public class BitReader
|
||||
{
|
||||
public int CurrentIndex { get; set; }
|
||||
|
||||
private byte[] ResultArray;
|
||||
|
||||
public BitReader(byte[] array)
|
||||
{
|
||||
CurrentIndex = 0;
|
||||
ResultArray = array;
|
||||
}
|
||||
|
||||
~BitReader()
|
||||
{
|
||||
ResultArray = null;
|
||||
}
|
||||
|
||||
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 = ResultArray.Skip(CurrentIndex).Take(length).ToArray();
|
||||
CurrentIndex += length;
|
||||
return value;
|
||||
}
|
||||
|
||||
public short ReadShort()
|
||||
{
|
||||
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 Vector3 ReadVector3()
|
||||
{
|
||||
return new Vector3()
|
||||
{
|
||||
X = ReadFloat(),
|
||||
Y = ReadFloat(),
|
||||
Z = ReadFloat()
|
||||
};
|
||||
}
|
||||
public Quaternion ReadQuaternion()
|
||||
{
|
||||
return new Quaternion()
|
||||
{
|
||||
X = ReadFloat(),
|
||||
Y = ReadFloat(),
|
||||
Z = ReadFloat(),
|
||||
W = ReadFloat()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA.Math;
|
||||
using System.Net;
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public class CoreUtils
|
||||
{
|
||||
|
||||
public static (byte, byte[]) GetBytesFromObject(object obj)
|
||||
{
|
||||
switch (obj)
|
||||
{
|
||||
case byte _:
|
||||
return (0x01, BitConverter.GetBytes((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));
|
||||
default:
|
||||
return (0x0, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public 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 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 byte ToByte(this bool[] source)
|
||||
{
|
||||
byte result = 0;
|
||||
// This assumes the array never contains more than 8 elements!
|
||||
int index = 8 - source.Length;
|
||||
|
||||
// Loop through the array
|
||||
foreach (bool b in source)
|
||||
{
|
||||
// if the element is 'true' set the bit at that position
|
||||
if (b)
|
||||
result |= (byte)(1 << (7 - index));
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
public static bool[] ToBoolArray(this byte b)
|
||||
{
|
||||
bool[] result = new bool[8];
|
||||
|
||||
// check each bit in the byte. if 1 set to true, if 0 set to false
|
||||
for (int i = 0; i < 8; i++)
|
||||
result[i] = (b & (1 << i)) != 0;
|
||||
|
||||
// reverse the array
|
||||
Array.Reverse(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace RageCoop.Core.Logging
|
||||
{
|
||||
public class Logger :IDisposable
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 0:Trace, 1:Debug, 2:Info, 3:Warning, 4:Error
|
||||
/// </summary>
|
||||
public int LogLevel = 0;
|
||||
public string LogPath;
|
||||
public bool UseConsole = false;
|
||||
private static StreamWriter logWriter;
|
||||
|
||||
private string Buffer="";
|
||||
private Thread LoggerThread;
|
||||
private bool Stopping=false;
|
||||
|
||||
public Logger(bool overwrite=true)
|
||||
{
|
||||
if (File.Exists(LogPath)&&overwrite) { File.Delete(LogPath); }
|
||||
LoggerThread=new Thread(() =>
|
||||
{
|
||||
while (!Stopping)
|
||||
{
|
||||
Flush();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
});
|
||||
LoggerThread.Start();
|
||||
}
|
||||
|
||||
public void Info(string message)
|
||||
{
|
||||
if (LogLevel>2) { return; }
|
||||
lock (Buffer)
|
||||
{
|
||||
string msg = string.Format("[{0}][{2}] [INF] {1}", Date(), message, Process.GetCurrentProcess().Id);
|
||||
|
||||
Buffer+=msg+"\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
public void Warning(string message)
|
||||
{
|
||||
if (LogLevel>3) { return; }
|
||||
lock (Buffer)
|
||||
{
|
||||
string msg = string.Format("[{0}][{2}] [WRN] {1}", Date(), message, Process.GetCurrentProcess().Id);
|
||||
|
||||
Buffer+=msg+"\r\n";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void Error(string message)
|
||||
{
|
||||
if (LogLevel>4) { return; }
|
||||
lock (Buffer)
|
||||
{
|
||||
string msg = string.Format("[{0}][{2}] [ERR] {1}", Date(), message, Process.GetCurrentProcess().Id);
|
||||
|
||||
Buffer+=msg+"\r\n";
|
||||
}
|
||||
}
|
||||
public void Error(Exception ex)
|
||||
{
|
||||
if (LogLevel>4) { return; }
|
||||
lock (Buffer)
|
||||
{
|
||||
string msg = string.Format("[{0}][{2}] [ERR] {1}", Date(),string.Join("\r\n",ex.Message,ex.StackTrace,ex.ToString()), Process.GetCurrentProcess().Id);
|
||||
|
||||
Buffer+=msg+"\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
public void Debug(string message)
|
||||
{
|
||||
|
||||
if (LogLevel>1) { return; }
|
||||
lock (Buffer)
|
||||
{
|
||||
string msg = string.Format("[{0}][{2}] [DBG] {1}", Date(), message,Process.GetCurrentProcess().Id);
|
||||
|
||||
Buffer+=msg+"\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
public void Trace(string message)
|
||||
{
|
||||
if (LogLevel>0) { return; }
|
||||
lock (Buffer)
|
||||
{
|
||||
string msg = string.Format("[{0}][{2}] [TRC] {1}", Date(), message, Process.GetCurrentProcess().Id);
|
||||
|
||||
Buffer+=msg+"\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
private string Date()
|
||||
{
|
||||
return DateTime.Now.ToString();
|
||||
}
|
||||
public void Flush()
|
||||
{
|
||||
lock (Buffer)
|
||||
{
|
||||
if (Buffer!="")
|
||||
{
|
||||
if (UseConsole)
|
||||
{
|
||||
Console.Write(Buffer);
|
||||
Buffer="";
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
logWriter=new StreamWriter(LogPath, true, Encoding.UTF8);
|
||||
logWriter.Write(Buffer);
|
||||
logWriter.Close();
|
||||
Buffer="";
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
Stopping=true;
|
||||
LoggerThread?.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public partial class Packets
|
||||
{
|
||||
public class FileTransferRequest : Packet
|
||||
{
|
||||
public byte ID { get; set; }
|
||||
|
||||
public string FileName { get; set; }
|
||||
|
||||
public long FileLength { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.FileTransferRequest);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// The ID from the download
|
||||
byteArray.Add(ID);
|
||||
|
||||
// The name of the file
|
||||
byte[] nameBytes = Encoding.UTF8.GetBytes(FileName);
|
||||
byteArray.AddRange(BitConverter.GetBytes(nameBytes.Length));
|
||||
byteArray.AddRange(nameBytes);
|
||||
|
||||
// The length of the file
|
||||
byteArray.AddRange(BitConverter.GetBytes(FileLength));
|
||||
|
||||
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.ReadByte();
|
||||
int nameArrayLength = reader.ReadInt();
|
||||
FileName = reader.ReadString(nameArrayLength);
|
||||
FileLength = reader.ReadLong();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
public class FileTransferTick : Packet
|
||||
{
|
||||
public byte ID { get; set; }
|
||||
|
||||
public byte[] FileChunk { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.FileTransferTick);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// The ID from the download
|
||||
byteArray.Add(ID);
|
||||
|
||||
// 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)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
ID = reader.ReadByte();
|
||||
int chunkLength = reader.ReadInt();
|
||||
FileChunk = reader.ReadByteArray(chunkLength);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
public class FileTransferComplete : Packet
|
||||
{
|
||||
public byte ID { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.FileTransferComplete);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// The ID from the download
|
||||
byteArray.Add(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.ReadByte();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,699 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Lidgren.Network;
|
||||
using Newtonsoft.Json;
|
||||
using GTA.Math;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
/*
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public struct LVector3
|
||||
{
|
||||
#region CLIENT-ONLY
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Vector3 ToVector()
|
||||
{
|
||||
return new Vector3(X, Y, Z);
|
||||
}
|
||||
#endregion
|
||||
#region SERVER-ONLY
|
||||
public float Length() => (float)Math.Sqrt((X * X) + (Y * Y) + (Z * Z));
|
||||
public static LVector3 Subtract(LVector3 pos1, LVector3 pos2) { return new LVector3(pos1.X - pos2.X, pos1.Y - pos2.Y, pos1.Z - pos2.Z); }
|
||||
public static bool Equals(LVector3 value1, LVector3 value2) => value1.X == value2.X && value1.Y == value2.Y && value1.Z == value2.Z;
|
||||
public static LVector3 operator /(LVector3 value1, float value2)
|
||||
{
|
||||
float num = 1f / value2;
|
||||
return new LVector3(value1.X * num, value1.Y * num, value1.Z * num);
|
||||
}
|
||||
public static LVector3 operator -(LVector3 left, LVector3 right)
|
||||
{
|
||||
return new LVector3(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
|
||||
}
|
||||
public static LVector3 operator -(LVector3 value)
|
||||
{
|
||||
return default(LVector3) - value;
|
||||
}
|
||||
#endregion
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public LVector3(float X, float Y, float Z)
|
||||
{
|
||||
this.X = X;
|
||||
this.Y = Y;
|
||||
this.Z = Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public float X { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public float Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public float Z { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public struct LQuaternion
|
||||
{
|
||||
#region CLIENT-ONLY
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Quaternion ToQuaternion()
|
||||
{
|
||||
return new Quaternion(X, Y, Z, W);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public LQuaternion(float X, float Y, float Z, float W)
|
||||
{
|
||||
this.X = X;
|
||||
this.Y = Y;
|
||||
this.Z = Z;
|
||||
this.W = W;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public float X { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public float Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public float Z { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public float W { get; set; }
|
||||
}
|
||||
*/
|
||||
public enum PacketTypes:byte
|
||||
{
|
||||
Handshake=0,
|
||||
PlayerConnect=1,
|
||||
PlayerDisconnect=2,
|
||||
PlayerInfoUpdate=3,
|
||||
|
||||
ChatMessage=10,
|
||||
NativeCall=11,
|
||||
NativeResponse=12,
|
||||
Mod=13,
|
||||
CleanUpWorld=14,
|
||||
FileTransferTick=15,
|
||||
FileTransferRequest=16,
|
||||
FileTransferComplete=17,
|
||||
ServerClientEvent=18,
|
||||
|
||||
#region Sync
|
||||
|
||||
#region INTERVAL
|
||||
VehicleSync = 20,
|
||||
VehicleStateSync = 21,
|
||||
PedSync = 22,
|
||||
PedStateSync = 23,
|
||||
ProjectileSync=24,
|
||||
#endregion
|
||||
|
||||
#region EVENT
|
||||
|
||||
PedKilled=30,
|
||||
BulletShot=31,
|
||||
EnteringVehicle=32,
|
||||
LeaveVehicle = 33,
|
||||
EnteredVehicle=34,
|
||||
OwnerChanged=35,
|
||||
VehicleBulletShot = 36,
|
||||
NozzleTransform=37,
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
public static class PacketExtensions
|
||||
{
|
||||
public static bool IsSyncEvent(this PacketTypes p)
|
||||
{
|
||||
return (30<=(byte)p)&&((byte)p<=40);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ConnectionChannel
|
||||
{
|
||||
Default = 0,
|
||||
Chat = 5,
|
||||
Native = 6,
|
||||
Mod = 7,
|
||||
File = 8,
|
||||
Event = 9,
|
||||
VehicleSync=20,
|
||||
PedSync=21,
|
||||
ProjectileSync = 22,
|
||||
SyncEvents =30,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum PedDataFlags:ushort
|
||||
{
|
||||
None=0,
|
||||
IsAiming = 1 << 0,
|
||||
IsReloading = 1 << 2,
|
||||
IsJumping = 1 << 3,
|
||||
IsRagdoll = 1 << 4,
|
||||
IsOnFire = 1 << 5,
|
||||
IsInParachuteFreeFall = 1 << 6,
|
||||
IsParachuteOpen = 1 << 7,
|
||||
IsOnLadder = 1 << 8,
|
||||
IsVaulting = 1 << 9,
|
||||
IsInCover=1<< 10,
|
||||
}
|
||||
|
||||
#region ===== VEHICLE DATA =====
|
||||
public enum VehicleDataFlags:ushort
|
||||
{
|
||||
IsEngineRunning = 1 << 0,
|
||||
AreLightsOn = 1 << 1,
|
||||
AreBrakeLightsOn = 1 << 2,
|
||||
AreHighBeamsOn = 1 << 3,
|
||||
IsSirenActive = 1 << 4,
|
||||
IsDead = 1 << 5,
|
||||
IsHornActive = 1 << 6,
|
||||
IsTransformed = 1 << 7,
|
||||
RoofOpened = 1 << 8,
|
||||
OnTurretSeat = 1 << 9,
|
||||
IsAircraft = 1 << 10,
|
||||
IsDeluxoHovering=1 << 11,
|
||||
}
|
||||
|
||||
|
||||
public struct VehicleDamageModel
|
||||
{
|
||||
public byte BrokenDoors { get; set; }
|
||||
public byte OpenedDoors { get; set; }
|
||||
public byte BrokenWindows { get; set; }
|
||||
public short BurstedTires { get; set; }
|
||||
public byte LeftHeadLightBroken { get; set; }
|
||||
public byte RightHeadLightBroken { get; set; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
interface IPacket
|
||||
{
|
||||
void Pack(NetOutgoingMessage message);
|
||||
void Unpack(byte[] array);
|
||||
}
|
||||
|
||||
public abstract class Packet : IPacket
|
||||
{
|
||||
public abstract void Pack(NetOutgoingMessage message);
|
||||
public abstract void Unpack(byte[] array);
|
||||
}
|
||||
|
||||
public partial class Packets
|
||||
{
|
||||
public class Mod : Packet
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public byte CustomPacketID { get; set; }
|
||||
|
||||
public byte[] Bytes { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.Mod);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write Name
|
||||
byte[] nameBytes = Encoding.UTF8.GetBytes(Name);
|
||||
byteArray.AddRange(BitConverter.GetBytes(nameBytes.Length));
|
||||
byteArray.AddRange(nameBytes);
|
||||
|
||||
// Write CustomPacketID
|
||||
byteArray.Add(CustomPacketID);
|
||||
|
||||
// Write Bytes
|
||||
byteArray.AddRange(BitConverter.GetBytes(Bytes.Length));
|
||||
byteArray.AddRange(Bytes);
|
||||
|
||||
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 Name
|
||||
int nameLength = reader.ReadInt();
|
||||
Name = reader.ReadString(nameLength);
|
||||
|
||||
// Read CustomPacketID
|
||||
CustomPacketID = reader.ReadByte();
|
||||
|
||||
// Read Bytes
|
||||
int bytesLength = reader.ReadInt();
|
||||
Bytes = reader.ReadByteArray(bytesLength);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
public class ChatMessage : Packet
|
||||
{
|
||||
public string Username { get; set; }
|
||||
|
||||
public string Message { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.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
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerClientEvent : Packet
|
||||
{
|
||||
public string EventName { get; set; }
|
||||
|
||||
public List<object> Args { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.ServerClientEvent);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
byte[] eventNameBytes = Encoding.UTF8.GetBytes(EventName);
|
||||
|
||||
// Write event name
|
||||
byteArray.AddRange(BitConverter.GetBytes(eventNameBytes.Length));
|
||||
byteArray.AddRange(eventNameBytes);
|
||||
|
||||
// Write args
|
||||
byteArray.AddRange(BitConverter.GetBytes(Args.Count));
|
||||
foreach (object arg in Args)
|
||||
{
|
||||
var test = CoreUtils.GetBytesFromObject(arg);
|
||||
if (test.Item1 == 0x0)
|
||||
{
|
||||
// Logger.Write("Can't get type of an object!", Logger.LogLevel.Server);
|
||||
byteArray.Add(0x0);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteArray.Add(test.Item1);
|
||||
byteArray.AddRange(test.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
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 event name
|
||||
int eventNameBytes = reader.ReadInt();
|
||||
EventName = reader.ReadString(eventNameBytes);
|
||||
|
||||
// Read args
|
||||
Args = new List<object>();
|
||||
int argsCount = reader.ReadInt();
|
||||
for (int i = 0; i < argsCount; i++)
|
||||
{
|
||||
byte argType = reader.ReadByte();
|
||||
switch (argType)
|
||||
{
|
||||
case 0x01:
|
||||
Args.Add(reader.ReadByte());
|
||||
break;
|
||||
case 0x02:
|
||||
Args.Add(reader.ReadShort());
|
||||
break;
|
||||
case 0x03:
|
||||
Args.Add(reader.ReadUShort());
|
||||
break;
|
||||
case 0x04:
|
||||
Args.Add(reader.ReadInt());
|
||||
break;
|
||||
case 0x05:
|
||||
Args.Add(reader.ReadUInt());
|
||||
break;
|
||||
case 0x06:
|
||||
Args.Add(reader.ReadLong());
|
||||
break;
|
||||
case 0x07:
|
||||
Args.Add(reader.ReadULong());
|
||||
break;
|
||||
case 0x08:
|
||||
Args.Add(reader.ReadFloat());
|
||||
break;
|
||||
case 0x09:
|
||||
Args.Add(reader.ReadBool());
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#region ===== NATIVECALL =====
|
||||
public class NativeCall : Packet
|
||||
{
|
||||
public ulong Hash { get; set; }
|
||||
|
||||
public List<object> Args { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.NativeCall);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write Hash
|
||||
byteArray.AddRange(BitConverter.GetBytes(Hash));
|
||||
|
||||
// Write Args
|
||||
byteArray.AddRange(BitConverter.GetBytes(Args.Count));
|
||||
Args.ForEach(x =>
|
||||
{
|
||||
Type type = x.GetType();
|
||||
|
||||
if (type == typeof(int))
|
||||
{
|
||||
byteArray.Add(0x00);
|
||||
byteArray.AddRange(BitConverter.GetBytes((int)x));
|
||||
}
|
||||
else if (type == typeof(bool))
|
||||
{
|
||||
byteArray.Add(0x01);
|
||||
byteArray.AddRange(BitConverter.GetBytes((bool)x));
|
||||
}
|
||||
else if (type == typeof(float))
|
||||
{
|
||||
byteArray.Add(0x02);
|
||||
byteArray.AddRange(BitConverter.GetBytes((float)x));
|
||||
}
|
||||
else if (type == typeof(string))
|
||||
{
|
||||
byteArray.Add(0x03);
|
||||
byte[] stringBytes = Encoding.UTF8.GetBytes((string)x);
|
||||
byteArray.AddRange(BitConverter.GetBytes(stringBytes.Length));
|
||||
byteArray.AddRange(stringBytes);
|
||||
}
|
||||
else if (type == typeof(Vector3))
|
||||
{
|
||||
byteArray.Add(0x04);
|
||||
Vector3 vector = (Vector3)x;
|
||||
byteArray.AddRange(BitConverter.GetBytes(vector.X));
|
||||
byteArray.AddRange(BitConverter.GetBytes(vector.Y));
|
||||
byteArray.AddRange(BitConverter.GetBytes(vector.Z));
|
||||
}
|
||||
});
|
||||
|
||||
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 Hash
|
||||
Hash = reader.ReadULong();
|
||||
|
||||
// Read Args
|
||||
Args = new List<object>();
|
||||
int argsLength = reader.ReadInt();
|
||||
for (int i = 0; i < argsLength; i++)
|
||||
{
|
||||
byte argType = reader.ReadByte();
|
||||
switch (argType)
|
||||
{
|
||||
case 0x00:
|
||||
Args.Add(reader.ReadInt());
|
||||
break;
|
||||
case 0x01:
|
||||
Args.Add(reader.ReadBool());
|
||||
break;
|
||||
case 0x02:
|
||||
Args.Add(reader.ReadFloat());
|
||||
break;
|
||||
case 0x03:
|
||||
int stringLength = reader.ReadInt();
|
||||
Args.Add(reader.ReadString(stringLength));
|
||||
break;
|
||||
case 0x04:
|
||||
Args.Add(new Vector3()
|
||||
{
|
||||
X = reader.ReadFloat(),
|
||||
Y = reader.ReadFloat(),
|
||||
Z = reader.ReadFloat()
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
public class NativeResponse : Packet
|
||||
{
|
||||
public ulong Hash { get; set; }
|
||||
|
||||
public List<object> Args { get; set; }
|
||||
|
||||
public byte? ResultType { get; set; }
|
||||
|
||||
public long ID { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.NativeResponse);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write Hash
|
||||
byteArray.AddRange(BitConverter.GetBytes(Hash));
|
||||
|
||||
Type type;
|
||||
|
||||
// Write Args
|
||||
byteArray.AddRange(BitConverter.GetBytes(Args.Count));
|
||||
Args.ForEach(x =>
|
||||
{
|
||||
type = x.GetType();
|
||||
|
||||
if (type == typeof(int))
|
||||
{
|
||||
byteArray.Add(0x00);
|
||||
byteArray.AddRange(BitConverter.GetBytes((int)x));
|
||||
}
|
||||
else if (type == typeof(bool))
|
||||
{
|
||||
byteArray.Add(0x01);
|
||||
byteArray.AddRange(BitConverter.GetBytes((bool)x));
|
||||
}
|
||||
else if (type == typeof(float))
|
||||
{
|
||||
byteArray.Add(0x02);
|
||||
byteArray.AddRange(BitConverter.GetBytes((float)x));
|
||||
}
|
||||
else if (type == typeof(string))
|
||||
{
|
||||
byteArray.Add(0x03);
|
||||
byte[] stringBytes = Encoding.UTF8.GetBytes((string)x);
|
||||
byteArray.AddRange(BitConverter.GetBytes(stringBytes.Length));
|
||||
byteArray.AddRange(stringBytes);
|
||||
}
|
||||
else if (type == typeof(Vector3))
|
||||
{
|
||||
byteArray.Add(0x04);
|
||||
Vector3 vector = (Vector3)x;
|
||||
byteArray.AddRange(BitConverter.GetBytes(vector.X));
|
||||
byteArray.AddRange(BitConverter.GetBytes(vector.Y));
|
||||
byteArray.AddRange(BitConverter.GetBytes(vector.Z));
|
||||
}
|
||||
});
|
||||
|
||||
byteArray.AddRange(BitConverter.GetBytes(ID));
|
||||
|
||||
// Write type of result
|
||||
if (ResultType.HasValue)
|
||||
{
|
||||
byteArray.Add(ResultType.Value);
|
||||
}
|
||||
|
||||
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 Hash
|
||||
Hash = reader.ReadULong();
|
||||
|
||||
// Read Args
|
||||
Args = new List<object>();
|
||||
int argsLength = reader.ReadInt();
|
||||
for (int i = 0; i < argsLength; i++)
|
||||
{
|
||||
byte argType = reader.ReadByte();
|
||||
switch (argType)
|
||||
{
|
||||
case 0x00:
|
||||
Args.Add(reader.ReadInt());
|
||||
break;
|
||||
case 0x01:
|
||||
Args.Add(reader.ReadBool());
|
||||
break;
|
||||
case 0x02:
|
||||
Args.Add(reader.ReadFloat());
|
||||
break;
|
||||
case 0x03:
|
||||
int stringLength = reader.ReadInt();
|
||||
Args.Add(reader.ReadString(stringLength));
|
||||
break;
|
||||
case 0x04:
|
||||
Args.Add(new Vector3()
|
||||
{
|
||||
X = reader.ReadFloat(),
|
||||
Y = reader.ReadFloat(),
|
||||
Z = reader.ReadFloat()
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ID = reader.ReadLong();
|
||||
|
||||
// Read type of result
|
||||
if (reader.CanRead(1))
|
||||
{
|
||||
ResultType = reader.ReadByte();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
#endregion // ===== NATIVECALL =====
|
||||
}
|
||||
|
||||
public 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,248 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public partial class Packets
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// For non-critical properties, synced every 20 frames.
|
||||
/// </summary>
|
||||
public class PedStateSync : Packet
|
||||
{
|
||||
public int ID { get; set; }
|
||||
|
||||
public int ModelHash { get; set; }
|
||||
|
||||
public Dictionary<byte, short> Clothes { get; set; }
|
||||
|
||||
public int OwnerID { get; set; }
|
||||
|
||||
public Dictionary<uint, bool> WeaponComponents { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.PedStateSync);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write ID
|
||||
byteArray.AddInt(ID);
|
||||
|
||||
// Write model hash
|
||||
byteArray.AddInt(ModelHash);
|
||||
|
||||
// Write player clothes
|
||||
// Write the count of clothes
|
||||
byteArray.AddRange(BitConverter.GetBytes((ushort)Clothes.Count));
|
||||
// Loop the dictionary and add the values
|
||||
foreach (KeyValuePair<byte, short> cloth in Clothes)
|
||||
{
|
||||
byteArray.Add(cloth.Key);
|
||||
byteArray.AddRange(BitConverter.GetBytes(cloth.Value));
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
// Create new Dictionary
|
||||
Clothes = new Dictionary<byte, short>();
|
||||
// Read the count of clothes
|
||||
ushort clothCount = reader.ReadUShort();
|
||||
// For clothCount
|
||||
for (ushort i = 0; i < clothCount; i++)
|
||||
{
|
||||
// Read cloth value
|
||||
Clothes.Add(reader.ReadByte(), reader.ReadShort());
|
||||
}
|
||||
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public 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)PacketTypes.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.HasFlag(PedDataFlags.IsRagdoll))
|
||||
{
|
||||
byteArray.AddVector3(RotationVelocity);
|
||||
}
|
||||
|
||||
// Write ped speed
|
||||
byteArray.Add(Speed);
|
||||
|
||||
// Write ped weapon hash
|
||||
byteArray.AddRange(BitConverter.GetBytes(CurrentWeaponHash));
|
||||
|
||||
if (Flag.HasFlag(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.HasFlag(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.HasFlag(PedDataFlags.IsAiming))
|
||||
{
|
||||
// Read player aim coords
|
||||
AimCoords = reader.ReadVector3();
|
||||
}
|
||||
|
||||
Heading=reader.ReadFloat();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public partial class Packets
|
||||
{
|
||||
public class Handshake : Packet
|
||||
{
|
||||
public int PedID { get; set; }
|
||||
|
||||
public string Username { get; set; }
|
||||
|
||||
public string ModVersion { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.Handshake);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write Player Ped ID
|
||||
byteArray.AddRange(BitConverter.GetBytes(PedID));
|
||||
|
||||
// Write Username
|
||||
byte[] usernameBytes = Encoding.UTF8.GetBytes(Username);
|
||||
byteArray.AddRange(BitConverter.GetBytes(usernameBytes.Length));
|
||||
byteArray.AddRange(usernameBytes);
|
||||
|
||||
// Write ModVersion
|
||||
byte[] modVersionBytes = Encoding.UTF8.GetBytes(ModVersion);
|
||||
byteArray.AddRange(BitConverter.GetBytes(modVersionBytes.Length));
|
||||
byteArray.AddRange(modVersionBytes);
|
||||
|
||||
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
|
||||
PedID = reader.ReadInt();
|
||||
|
||||
// Read Username
|
||||
int usernameLength = reader.ReadInt();
|
||||
Username = reader.ReadString(usernameLength);
|
||||
|
||||
// Read ModVersion
|
||||
int modVersionLength = reader.ReadInt();
|
||||
ModVersion = reader.ReadString(modVersionLength);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
public class PlayerConnect : Packet
|
||||
{
|
||||
public int PedID { get; set; }
|
||||
|
||||
public string Username { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.PlayerConnect);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write NetHandle
|
||||
byteArray.AddRange(BitConverter.GetBytes(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
|
||||
}
|
||||
|
||||
public override void Unpack(byte[] array)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
// Read player netHandle
|
||||
PedID = reader.ReadInt();
|
||||
|
||||
// Read Username
|
||||
int usernameLength = reader.ReadInt();
|
||||
Username = reader.ReadString(usernameLength);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
public class PlayerDisconnect : Packet
|
||||
{
|
||||
public int PedID { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.PlayerDisconnect);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
byteArray.AddRange(BitConverter.GetBytes(PedID));
|
||||
|
||||
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();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
public class PlayerInfoUpdate : Packet
|
||||
{
|
||||
/// <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)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.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));
|
||||
|
||||
// Write Username
|
||||
byteArray.AddRange(usernameBytes);
|
||||
|
||||
// Write Latency
|
||||
byteArray.AddFloat(Latency);
|
||||
|
||||
byte[] result = byteArray.ToArray();
|
||||
|
||||
message.Write(result.Length);
|
||||
message.Write(result);
|
||||
#endregion
|
||||
}
|
||||
|
||||
public override void Unpack(byte[] array)
|
||||
{
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
// Read player ID
|
||||
PedID = reader.ReadInt();
|
||||
|
||||
// Read Username
|
||||
int usernameLength = reader.ReadInt();
|
||||
Username = reader.ReadString(usernameLength);
|
||||
|
||||
Latency=reader.ReadFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public partial class Packets
|
||||
{
|
||||
public class ProjectileSync : Packet
|
||||
{
|
||||
|
||||
public int ID { get; set; }
|
||||
|
||||
public int ShooterID { get; set; }
|
||||
public uint WeaponHash { get; set; }
|
||||
|
||||
public Vector3 Position { get; set; }
|
||||
|
||||
public Vector3 Rotation { get; set; }
|
||||
|
||||
public Vector3 Velocity { get; set; }
|
||||
|
||||
public bool Exploded { get; set; }
|
||||
|
||||
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.ProjectileSync);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write id
|
||||
byteArray.AddInt(ID);
|
||||
|
||||
// Write ShooterID
|
||||
byteArray.AddInt(ShooterID);
|
||||
|
||||
byteArray.AddUint(WeaponHash);
|
||||
|
||||
// Write position
|
||||
byteArray.AddVector3(Position);
|
||||
|
||||
|
||||
// Write rotation
|
||||
byteArray.AddVector3(Rotation);
|
||||
|
||||
// Write velocity
|
||||
byteArray.AddVector3(Velocity);
|
||||
|
||||
if (Exploded) { byteArray.Add(1); }
|
||||
|
||||
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 id
|
||||
ID = reader.ReadInt();
|
||||
|
||||
// Read ShooterID
|
||||
ShooterID= reader.ReadInt();
|
||||
|
||||
WeaponHash= reader.ReadUInt();
|
||||
|
||||
// Read position
|
||||
Position = reader.ReadVector3();
|
||||
|
||||
// Read rotation
|
||||
Rotation = reader.ReadVector3();
|
||||
|
||||
// Read velocity
|
||||
Velocity =reader.ReadVector3();
|
||||
|
||||
if (reader.CanRead(1))
|
||||
{
|
||||
Exploded=true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public partial class Packets
|
||||
{
|
||||
|
||||
public class BulletShot : Packet
|
||||
{
|
||||
public int OwnerID { get; set; }
|
||||
|
||||
public uint WeaponHash { get; set; }
|
||||
|
||||
public Vector3 StartPosition { get; set; }
|
||||
public Vector3 EndPosition { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.BulletShot);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write OwnerID
|
||||
byteArray.AddRange(BitConverter.GetBytes(OwnerID));
|
||||
|
||||
// Write weapon hash
|
||||
byteArray.AddRange(BitConverter.GetBytes(WeaponHash));
|
||||
|
||||
// Write StartPosition
|
||||
byteArray.AddVector3(StartPosition);
|
||||
|
||||
// Write EndPosition
|
||||
byteArray.AddVector3(EndPosition);
|
||||
|
||||
|
||||
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 OwnerID
|
||||
OwnerID=reader.ReadInt();
|
||||
|
||||
// Read WeponHash
|
||||
WeaponHash=reader.ReadUInt();
|
||||
|
||||
// Read StartPosition
|
||||
StartPosition=reader.ReadVector3();
|
||||
|
||||
// Read EndPosition
|
||||
EndPosition=reader.ReadVector3();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public partial class Packets
|
||||
{
|
||||
public 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)PacketTypes.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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public partial class Packets
|
||||
{
|
||||
public 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)PacketTypes.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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public partial class Packets
|
||||
{
|
||||
|
||||
public class LeaveVehicle : Packet
|
||||
{
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public partial class Packets
|
||||
{
|
||||
public class NozzleTransform : Packet
|
||||
{
|
||||
public int VehicleID { get; set; }
|
||||
|
||||
public bool Hover { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.NozzleTransform);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
byteArray.AddInt(VehicleID);
|
||||
if (Hover) { byteArray.Add(1); }
|
||||
|
||||
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);
|
||||
VehicleID=reader.ReadInt();
|
||||
Hover=reader.CanRead(1);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public partial class Packets
|
||||
{
|
||||
|
||||
public class OwnerChanged : Packet
|
||||
{
|
||||
public int ID { get; set; }
|
||||
|
||||
public int NewOwnerID { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.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
|
||||
}
|
||||
|
||||
public override void Unpack(byte[] array)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
ID=reader.ReadInt();
|
||||
NewOwnerID=reader.ReadInt();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public partial class Packets
|
||||
{
|
||||
|
||||
public class PedKilled : Packet
|
||||
{
|
||||
public int VictimID { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.PedKilled);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
byteArray.AddInt(VictimID);
|
||||
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);
|
||||
|
||||
VictimID=reader.ReadInt();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,316 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public partial class Packets
|
||||
{
|
||||
/// <summary>
|
||||
/// Non-critical stuff, such as damage model, landing gear, health, etc..
|
||||
/// </summary>
|
||||
public class VehicleStateSync : Packet
|
||||
{
|
||||
public int ID { get; set; }
|
||||
|
||||
// ID of player responsible for syncing this vehicle
|
||||
public int OwnerID { get; set; }
|
||||
|
||||
public int ModelHash { get; set; }
|
||||
|
||||
public float EngineHealth { get; set; }
|
||||
|
||||
public byte[] Colors { get; set; }
|
||||
|
||||
public Dictionary<int, int> Mods { get; set; }
|
||||
|
||||
public VehicleDamageModel DamageModel { get; set; }
|
||||
|
||||
public byte LandingGear { get; set; }
|
||||
|
||||
public VehicleDataFlags Flag { get; set; }
|
||||
|
||||
|
||||
public VehicleLockStatus LockStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// VehicleSeat,PedID
|
||||
/// </summary>
|
||||
public Dictionary<int, int> Passengers { get; set; }
|
||||
|
||||
public byte RadioStation { get; set; } = 255;
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.VehicleStateSync);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write player netHandle
|
||||
byteArray.AddRange(BitConverter.GetBytes(ID));
|
||||
|
||||
//Write vehicle flag
|
||||
byteArray.AddRange(BitConverter.GetBytes((ushort)Flag));
|
||||
|
||||
// Write vehicle model hash
|
||||
byteArray.AddRange(BitConverter.GetBytes(ModelHash));
|
||||
|
||||
|
||||
// Write vehicle engine health
|
||||
byteArray.AddRange(BitConverter.GetBytes(EngineHealth));
|
||||
|
||||
// Check
|
||||
if (Flag.HasFlag(VehicleDataFlags.IsAircraft))
|
||||
{
|
||||
// Write the vehicle landing gear
|
||||
byteArray.AddRange(BitConverter.GetBytes(LandingGear));
|
||||
}
|
||||
|
||||
// Write vehicle colors
|
||||
byteArray.Add(Colors[0]);
|
||||
byteArray.Add(Colors[1]);
|
||||
|
||||
// Write vehicle mods
|
||||
// Write the count of mods
|
||||
byteArray.AddRange(BitConverter.GetBytes((short)Mods.Count));
|
||||
// Loop the dictionary and add the values
|
||||
foreach (KeyValuePair<int, int> mod in Mods)
|
||||
{
|
||||
// Write the mod value
|
||||
byteArray.AddRange(BitConverter.GetBytes(mod.Key));
|
||||
byteArray.AddRange(BitConverter.GetBytes(mod.Value));
|
||||
}
|
||||
|
||||
if (!DamageModel.Equals(default(VehicleDamageModel)))
|
||||
{
|
||||
// Write boolean = true
|
||||
byteArray.Add(0x01);
|
||||
// Write vehicle damage model
|
||||
byteArray.Add(DamageModel.BrokenDoors);
|
||||
byteArray.Add(DamageModel.OpenedDoors);
|
||||
byteArray.Add(DamageModel.BrokenWindows);
|
||||
byteArray.AddRange(BitConverter.GetBytes(DamageModel.BurstedTires));
|
||||
byteArray.Add(DamageModel.LeftHeadLightBroken);
|
||||
byteArray.Add(DamageModel.RightHeadLightBroken);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write boolean = false
|
||||
byteArray.Add(0x00);
|
||||
}
|
||||
|
||||
// Write OwnerID
|
||||
byteArray.AddRange(BitConverter.GetBytes(OwnerID));
|
||||
|
||||
// Write passengers
|
||||
byteArray.AddRange(BitConverter.GetBytes(Passengers.Count));
|
||||
|
||||
foreach (KeyValuePair<int, int> p in Passengers)
|
||||
{
|
||||
byteArray.AddRange(BitConverter.GetBytes(p.Key));
|
||||
byteArray.AddRange(BitConverter.GetBytes(p.Value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Write LockStatus
|
||||
byteArray.Add((byte)LockStatus);
|
||||
|
||||
// Write RadioStation
|
||||
byteArray.Add(RadioStation);
|
||||
|
||||
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 vehicle id
|
||||
ID = reader.ReadInt();
|
||||
|
||||
// Read vehicle flags
|
||||
Flag = (VehicleDataFlags)reader.ReadUShort();
|
||||
|
||||
// Read vehicle model hash
|
||||
ModelHash = reader.ReadInt();
|
||||
|
||||
// Read vehicle engine health
|
||||
EngineHealth = reader.ReadFloat();
|
||||
|
||||
|
||||
// Check
|
||||
if (Flag.HasFlag(VehicleDataFlags.IsAircraft))
|
||||
{
|
||||
// Read vehicle landing gear
|
||||
LandingGear = (byte)reader.ReadShort();
|
||||
}
|
||||
|
||||
// Read vehicle colors
|
||||
byte vehColor1 = reader.ReadByte();
|
||||
byte vehColor2 = reader.ReadByte();
|
||||
Colors = new byte[] { vehColor1, vehColor2 };
|
||||
|
||||
// Read vehicle mods
|
||||
// Create new Dictionary
|
||||
Mods = new Dictionary<int, int>();
|
||||
// Read count of mods
|
||||
short vehModCount = reader.ReadShort();
|
||||
// Loop
|
||||
for (int i = 0; i < vehModCount; i++)
|
||||
{
|
||||
// Read the mod value
|
||||
Mods.Add(reader.ReadInt(), reader.ReadInt());
|
||||
}
|
||||
|
||||
if (reader.ReadBool())
|
||||
{
|
||||
// Read vehicle damage model
|
||||
DamageModel = new VehicleDamageModel()
|
||||
{
|
||||
BrokenDoors = reader.ReadByte(),
|
||||
OpenedDoors=reader.ReadByte(),
|
||||
BrokenWindows = reader.ReadByte(),
|
||||
BurstedTires = reader.ReadShort(),
|
||||
LeftHeadLightBroken = reader.ReadByte(),
|
||||
RightHeadLightBroken = reader.ReadByte()
|
||||
};
|
||||
}
|
||||
|
||||
// Read OwnerID
|
||||
OwnerID= reader.ReadInt();
|
||||
|
||||
|
||||
// Read Passengers
|
||||
Passengers=new Dictionary<int, int>();
|
||||
int count = reader.ReadInt();
|
||||
for (int i = 0; i<count; i++)
|
||||
{
|
||||
int seat, id;
|
||||
seat = reader.ReadInt();
|
||||
id = reader.ReadInt();
|
||||
Passengers.Add(seat, id);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Read LockStatus
|
||||
LockStatus=(VehicleLockStatus)reader.ReadByte();
|
||||
|
||||
// Read RadioStation
|
||||
RadioStation=reader.ReadByte();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
public class VehicleSync : Packet
|
||||
{
|
||||
public int ID { get; set; }
|
||||
|
||||
public Vector3 Position { get; set; }
|
||||
|
||||
public Quaternion Quaternion { get; set; }
|
||||
// public Vector3 Rotation { get; set; }
|
||||
|
||||
public Vector3 Velocity { get; set; }
|
||||
|
||||
public Vector3 RotationVelocity { get; set; }
|
||||
|
||||
public float ThrottlePower { get; set; }
|
||||
public float BrakePower { get; set; }
|
||||
public float SteeringAngle { get; set; }
|
||||
public float DeluxoWingRatio { get; set; } = -1;
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
message.Write((byte)PacketTypes.VehicleSync);
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write vehicle id
|
||||
byteArray.AddInt(ID);
|
||||
|
||||
// Write position
|
||||
byteArray.AddVector3(Position);
|
||||
|
||||
|
||||
// Write quaternion
|
||||
//byteArray.AddVector3(Rotation);
|
||||
byteArray.AddQuaternion(Quaternion);
|
||||
|
||||
// Write velocity
|
||||
byteArray.AddVector3(Velocity);
|
||||
|
||||
// Write rotation velocity
|
||||
byteArray.AddVector3(RotationVelocity);
|
||||
|
||||
|
||||
byteArray.AddFloat(ThrottlePower);
|
||||
|
||||
byteArray.AddFloat(BrakePower);
|
||||
|
||||
// Write vehicle steering angle
|
||||
byteArray.AddFloat(SteeringAngle);
|
||||
|
||||
if (DeluxoWingRatio!=-1)
|
||||
{
|
||||
byteArray.AddFloat(DeluxoWingRatio);
|
||||
}
|
||||
|
||||
|
||||
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 vehicle id
|
||||
ID = reader.ReadInt();
|
||||
|
||||
// Read position
|
||||
Position = reader.ReadVector3();
|
||||
|
||||
// Read quaternion
|
||||
// Rotation = reader.ReadVector3();
|
||||
Quaternion=reader.ReadQuaternion();
|
||||
|
||||
// Read velocity
|
||||
Velocity =reader.ReadVector3();
|
||||
|
||||
// Read rotation velocity
|
||||
RotationVelocity=reader.ReadVector3();
|
||||
|
||||
// Read throttle power
|
||||
ThrottlePower=reader.ReadFloat();
|
||||
|
||||
// Read brake power
|
||||
BrakePower=reader.ReadFloat();
|
||||
|
||||
// Read steering angle
|
||||
SteeringAngle = reader.ReadFloat();
|
||||
|
||||
|
||||
if (reader.CanRead(4))
|
||||
{
|
||||
DeluxoWingRatio= reader.ReadFloat();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using GTA.Math;
|
||||
|
||||
[assembly: InternalsVisibleTo("RageCoop.Server")]
|
||||
[assembly: InternalsVisibleTo("RageCoop.Client")]
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public class PlayerData
|
||||
{
|
||||
public string Username { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Universal character ID.
|
||||
/// </summary>
|
||||
public int PedID
|
||||
{
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The ID of player's last vehicle.
|
||||
/// </summary>
|
||||
public int VehicleID { get; internal set; }
|
||||
public Vector3 Position { get;internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Player Latency in second.
|
||||
/// </summary>
|
||||
public float Latency { get; internal set; }
|
||||
public int Health { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<AssemblyVersion>0.1</AssemblyVersion>
|
||||
<FileVersion>0.1</FileVersion>
|
||||
<Version>0.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net6.0|AnyCPU'">
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0|AnyCPU'">
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Lidgren.Network">
|
||||
<HintPath>..\Libs\Release\scripts\Lidgren.Network.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\Libs\Release\scripts\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ScriptHookVDotNet3">
|
||||
<HintPath>..\Libs\Release\ScriptHookVDotNet3.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,153 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Linq;
|
||||
|
||||
[assembly: InternalsVisibleTo("RageCoop.Server")]
|
||||
[assembly: InternalsVisibleTo("RageCoop.Client")]
|
||||
namespace RageCoop.Core.Scripting
|
||||
{
|
||||
internal class ScriptingEngine
|
||||
{
|
||||
private Type BaseScriptType;
|
||||
public Logging.Logger Logger { get; set; }
|
||||
public ScriptingEngine(Type baseScriptType, Logging.Logger logger)
|
||||
{
|
||||
BaseScriptType = baseScriptType;
|
||||
Logger = logger;
|
||||
}
|
||||
/// <summary>
|
||||
/// Loads scripts from the specified assembly file.
|
||||
/// </summary>
|
||||
/// <param name="filename">The path to the assembly file to load.</param>
|
||||
/// <returns><see langword="true" /> on success, <see langword="false" /> otherwise</returns>
|
||||
private bool LoadScriptsFromAssembly(string filename)
|
||||
{
|
||||
if (!IsManagedAssembly(filename))
|
||||
return false;
|
||||
|
||||
Logger?.Debug($"Loading assembly {Path.GetFileName(filename)} ...");
|
||||
|
||||
Assembly assembly;
|
||||
|
||||
try
|
||||
{
|
||||
assembly = Assembly.LoadFrom(filename);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error( "Unable to load "+Path.GetFileName(filename));
|
||||
Logger?.Error(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return LoadScriptsFromAssembly(assembly, filename);
|
||||
}
|
||||
/// <summary>
|
||||
/// Loads scripts from the specified assembly object.
|
||||
/// </summary>
|
||||
/// <param name="filename">The path to the file associated with this assembly.</param>
|
||||
/// <param name="assembly">The assembly to load.</param>
|
||||
/// <returns><see langword="true" /> on success, <see langword="false" /> otherwise</returns>
|
||||
private bool LoadScriptsFromAssembly(Assembly assembly, string filename)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
try
|
||||
{
|
||||
// Find all script types in the assembly
|
||||
foreach (var type in assembly.GetTypes().Where(x => IsSubclassOf(x,nameof(BaseScriptType))))
|
||||
{
|
||||
ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
|
||||
if (constructor != null && constructor.IsPublic)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Invoke script constructor
|
||||
constructor.Invoke(null);
|
||||
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 {Path.GetFileName(filename)}: ");
|
||||
Logger?.Error(ex);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger?.Info($"Loaded {count.ToString()} script(s) in {Path.GetFileName(filename)}");
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 106 KiB |
Binary file not shown.
@@ -1,2 +0,0 @@
|
||||
ReloadKey=None
|
||||
ConsoleKey=F4
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -1,78 +1,76 @@
|
||||
|
||||
|
||||
# 🌐 RAGECOOP
|
||||
|
||||
[![Downloads][downloads-shield]][downloads-url]
|
||||
[![Contributors][contributors-shield]][contributors-url]
|
||||
[![Forks][forks-shield]][forks-url]
|
||||
[![Stargazers][stars-shield]][stars-url]
|
||||
[![Issues][issues-shield]][issues-url]
|
||||
|
||||
|
||||
# Disclaimer
|
||||
The original author of this project is @EntenKoeniq.
|
||||
The project has been reworked and is currently maintained by @Sardelka9515.
|
||||
|
||||
# 🧠 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 properly.
|
||||
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)
|
||||
|
||||
### Client
|
||||
|
||||
Download latest release, remove old version of the mod. Extract the zip and put `RageCoop` in `Grand Theft Auto V/Scripts`.
|
||||
|
||||
### Server
|
||||
|
||||
Download latest release for your OS, then extract and run.
|
||||
|
||||
# Downloads
|
||||
# 🧨 Downloads
|
||||
|
||||
Download latest release [here](https://github.com/RAGECOOP/RAGECOOP-V/releases/latest)
|
||||
|
||||
You can also download nightly builds [here](https://github.com/RAGECOOP/RAGECOOP-V/releases/nightly), which includes latest features and bug-fixes, but has not been thoroughly tested.
|
||||
|
||||
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)
|
||||
@@ -81,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
|
||||
@@ -92,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
|
||||
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31919.166
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Server", "Server\RageCoop.Server.csproj", "{84AB99D9-5E00-4CA2-B1DD-56B8419AAD24}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Server", "RageCoop.Server\RageCoop.Server.csproj", "{84AB99D9-5E00-4CA2-B1DD-56B8419AAD24}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RageCoop.Client", "Client\RageCoop.Client.csproj", "{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Core", "RageCoop.Core\RageCoop.Core.csproj", "{CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Core", "Core\RageCoop.Core.csproj", "{CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}"
|
||||
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
|
||||
@@ -25,14 +27,6 @@ Global
|
||||
{84AB99D9-5E00-4CA2-B1DD-56B8419AAD24}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{84AB99D9-5E00-4CA2-B1DD-56B8419AAD24}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{84AB99D9-5E00-4CA2-B1DD-56B8419AAD24}.Release|x64.Build.0 = Release|Any CPU
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{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
|
||||
{CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -41,6 +35,22 @@ Global
|
||||
{CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}.Release|x64.Build.0 = Release|Any CPU
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{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
|
||||
@@ -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>
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace RageCoop.Client.Installer
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
)]
|
||||
@@ -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>
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
+73
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
After Width: | Height: | Size: 2.5 MiB |
@@ -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.Show(Debug.TimeStamps.Dump());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
public 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,
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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,44 +19,57 @@ namespace RageCoop.Client
|
||||
/// </summary>
|
||||
internal class Main : Script
|
||||
{
|
||||
|
||||
private bool _gameLoaded = false;
|
||||
private bool _lastDead = false;
|
||||
public static readonly string CurrentVersion = "V0_4_1";
|
||||
internal static Version Version = typeof(Main).Assembly.GetName().Version;
|
||||
|
||||
public static int LocalPlayerID=0;
|
||||
internal static int LocalPlayerID = 0;
|
||||
|
||||
internal static RelationshipGroup SyncedPedsGroup;
|
||||
|
||||
public static new Settings Settings = null;
|
||||
internal static new Settings Settings = null;
|
||||
internal static Scripting.BaseScript BaseScript = new Scripting.BaseScript();
|
||||
|
||||
#if !NON_INTERACTIVE
|
||||
#endif
|
||||
public static Chat MainChat = null;
|
||||
public static Stopwatch Counter = new Stopwatch();
|
||||
public static Core.Logging.Logger Logger = null;
|
||||
internal static Chat MainChat = null;
|
||||
internal static Stopwatch Counter = new Stopwatch();
|
||||
internal static Logger Logger = null;
|
||||
|
||||
public static ulong Ticked = 0;
|
||||
private static List<Func<bool>> QueuedActions = new List<Func<bool>>();
|
||||
internal static ulong Ticked = 0;
|
||||
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();
|
||||
Logger=new Core.Logging.Logger()
|
||||
Worker = new Worker("RageCoop.Client.Main.Worker", Logger);
|
||||
try
|
||||
{
|
||||
LogPath="Scripts\\RageCoop\\RageCoop.Client.log",
|
||||
UseConsole=false,
|
||||
Settings = Util.ReadSettings();
|
||||
}
|
||||
catch
|
||||
{
|
||||
GTA.UI.Notification.Show("Malformed configuration, overwriting with default values...");
|
||||
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
|
||||
LogLevel=Settings.LogLevel,
|
||||
#endif
|
||||
};
|
||||
// Required for some synchronization!
|
||||
/*if (Game.Version < GameVersion.v1_0_1290_1_Steam)
|
||||
Resources = new Scripting.Resources();
|
||||
if (Game.Version < GameVersion.v1_0_1290_1_Steam)
|
||||
{
|
||||
Tick += (object sender, EventArgs e) =>
|
||||
{
|
||||
@@ -64,7 +77,6 @@ namespace RageCoop.Client
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_gameLoaded)
|
||||
{
|
||||
GTA.UI.Notification.Show("~r~Please update your GTA5 to v1.0.1290 or newer!", true);
|
||||
@@ -72,29 +84,32 @@ namespace RageCoop.Client
|
||||
}
|
||||
};
|
||||
return;
|
||||
}*/
|
||||
SyncedPedsGroup=World.AddRelationshipGroup("SYNCPED");
|
||||
}
|
||||
BaseScript.OnStart();
|
||||
SyncedPedsGroup = World.AddRelationshipGroup("SYNCPED");
|
||||
Game.Player.Character.RelationshipGroup.SetRelationshipBetweenGroups(SyncedPedsGroup, Relationship.Neutral, true);
|
||||
Networking.Start();
|
||||
#if !NON_INTERACTIVE
|
||||
#endif
|
||||
MainChat = new Chat();
|
||||
|
||||
Tick += OnTick;
|
||||
Tick += (s, e) => { Scripting.API.Events.InvokeTick(); };
|
||||
KeyDown += OnKeyDown;
|
||||
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
|
||||
private ulong _lastDebugData;
|
||||
private int _debugBytesSend;
|
||||
private int _debugBytesReceived;
|
||||
#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;
|
||||
@@ -102,93 +117,76 @@ 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.Show(GTA.UI.NotificationIcon.AllPlayersConf, "RAGECOOP", "Welcome!", $"Press ~g~{Main.Settings.MenuKey}~s~ to open the menu.");
|
||||
#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
|
||||
{
|
||||
Networking.Tick();
|
||||
EntityPool.DoSync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.Logger.Error(ex);
|
||||
}
|
||||
|
||||
if (!DownloadManager.DownloadComplete)
|
||||
{
|
||||
DownloadManager.RenderProgress();
|
||||
}
|
||||
|
||||
MapLoader.LoadAll();
|
||||
|
||||
#if DEBUG
|
||||
Main.Logger.Error(ex);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Networking.ShowNetworkInfo)
|
||||
{
|
||||
ulong time = Util.GetTickCount64();
|
||||
if (time - _lastDebugData > 1000)
|
||||
{
|
||||
_lastDebugData = time;
|
||||
|
||||
_debugBytesReceived = Networking.BytesReceived;
|
||||
Networking.BytesReceived = 0;
|
||||
_debugBytesSend = Networking.BytesSend;
|
||||
Networking.BytesSend = 0;
|
||||
}
|
||||
|
||||
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(_debugBytesReceived)}/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(_debugBytesSend)}/s", 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();
|
||||
if (Settings.DisableAutoRespawn)
|
||||
if (!Scripting.API.Config.EnableAutoRespawn)
|
||||
{
|
||||
Function.Call(Hash.PAUSE_DEATH_ARREST_RESTART, true);
|
||||
Function.Call(Hash.IGNORE_NEXT_RESTART, true);
|
||||
Function.Call(Hash.FORCE_GAME_STATE_PLAYING);
|
||||
var P = Game.Player.Character;
|
||||
Function.Call(Hash.TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME, "respawn_controller");
|
||||
if (P.IsDead)
|
||||
{
|
||||
Function.Call(Hash.TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME, "respawn_controller");
|
||||
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);
|
||||
}
|
||||
_lastDead=P.IsDead;
|
||||
|
||||
}
|
||||
else if (P.IsDead && !_lastDead)
|
||||
{
|
||||
Scripting.API.Events.InvokePlayerDied(KillMessage());
|
||||
}
|
||||
|
||||
_lastDead = P.IsDead;
|
||||
Ticked++;
|
||||
}
|
||||
|
||||
private void OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (MainChat.Focused)
|
||||
@@ -198,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;
|
||||
@@ -217,8 +229,8 @@ namespace RageCoop.Client
|
||||
{
|
||||
if (x.Visible)
|
||||
{
|
||||
CoopMenu.LastMenu=x;
|
||||
x.Visible=false;
|
||||
CoopMenu.LastMenu = x;
|
||||
x.Visible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -227,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)
|
||||
@@ -242,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))
|
||||
@@ -254,95 +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;
|
||||
|
||||
}
|
||||
|
||||
public 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
|
||||
};
|
||||
public static Dictionary<int, byte> ServerItems = new Dictionary<int, byte>();
|
||||
public 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.Show("~g~Connected!");
|
||||
});
|
||||
|
||||
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.Show("~r~Disconnected: " + reason);
|
||||
LocalPlayerID = default;
|
||||
});
|
||||
Memory.RestorePatches();
|
||||
DownloadManager.Cleanup();
|
||||
Voice.ClearAll();
|
||||
Resources.Unload();
|
||||
}
|
||||
|
||||
private static void DoQueuedActions()
|
||||
{
|
||||
lock (QueuedActions)
|
||||
@@ -356,9 +348,11 @@ namespace RageCoop.Client
|
||||
QueuedActions.Remove(action);
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
GTA.UI.Screen.ShowSubtitle(ex.ToString());
|
||||
#if DEBUG
|
||||
Logger.Error(ex);
|
||||
#endif
|
||||
QueuedActions.Remove(action);
|
||||
}
|
||||
}
|
||||
@@ -366,57 +360,49 @@ 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>
|
||||
public static void QueueAction(Func<bool> a)
|
||||
/// <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)
|
||||
{
|
||||
QueuedActions.Add(a);
|
||||
}
|
||||
}
|
||||
public static void QueueAction(Action a)
|
||||
internal static void QueueAction(Action a)
|
||||
{
|
||||
lock (QueuedActions)
|
||||
{
|
||||
QueuedActions.Add(() => { a(); return true; }) ;
|
||||
QueuedActions.Add(() => { a(); return true; });
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears all queued actions
|
||||
/// </summary>
|
||||
public static void ClearQueuedActions()
|
||||
internal static void ClearQueuedActions()
|
||||
{
|
||||
lock (QueuedActions) { QueuedActions.Clear(); }
|
||||
}
|
||||
|
||||
public static string DumpCharacters()
|
||||
public static void Delay(Action a, int time)
|
||||
{
|
||||
string s = "Characters:";
|
||||
lock (EntityPool.PedsLock)
|
||||
Task.Run(() =>
|
||||
{
|
||||
foreach (int id in EntityPool.GetPedIDs())
|
||||
{
|
||||
var c = EntityPool.GetPedByID(id);
|
||||
s+=$"\r\nID:{c.ID} Owner:{c.OwnerID} LastUpdated:{c.LastUpdated} LastSynced:{c.LastSynced} LastStateSynced:{c.LastStateSynced}";
|
||||
// s+=$"\r\n{c.IsAiming} {c.IsJumping} {c.IsOnFire} {c.IsOnLadder} {c.IsRagdoll} {c.IsReloading} {c.IsShooting} {c.Speed}";
|
||||
}
|
||||
}
|
||||
Main.Logger.Trace(s);
|
||||
return s;
|
||||
}
|
||||
public static string DumpPlayers()
|
||||
{
|
||||
string s = "Players:";
|
||||
foreach (PlayerData p in PlayerList.Players)
|
||||
{
|
||||
|
||||
s+=$"\r\nID:{p.PedID} Username:{p.Username}";
|
||||
}
|
||||
Main.Logger.Trace(s);
|
||||
return s;
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +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
|
||||
{
|
||||
@@ -18,16 +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()
|
||||
{
|
||||
Title = "",
|
||||
Prompt = "",
|
||||
Subtitle = "",
|
||||
Error = "",
|
||||
ShowBackground = true,
|
||||
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) };
|
||||
|
||||
public static readonly NativeItem ServerIpItem = new NativeItem("Server IP") { AltTitle = Main.Settings.LastServerAddress };
|
||||
private static readonly NativeItem _serverConnectItem = new NativeItem("Connect");
|
||||
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
|
||||
|
||||
@@ -36,10 +48,12 @@ namespace RageCoop.Client.Menus
|
||||
/// </summary>
|
||||
static CoopMenu()
|
||||
{
|
||||
|
||||
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;
|
||||
ServerIpItem.Activated += ServerIpActivated;
|
||||
_serverConnectItem.Activated += (sender, item) => { Networking.ToggleConnection(Main.Settings.LastServerAddress); };
|
||||
|
||||
@@ -47,24 +61,68 @@ namespace RageCoop.Client.Menus
|
||||
Menu.AddSubMenu(ServersMenu.Menu);
|
||||
|
||||
Menu.Add(_usernameItem);
|
||||
Menu.Add(_passwordItem);
|
||||
Menu.Add(ServerIpItem);
|
||||
Menu.Add(_serverConnectItem);
|
||||
|
||||
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);
|
||||
|
||||
Menu.Add(_aboutItem);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
Script.Yield();
|
||||
while (true)
|
||||
{
|
||||
Game.DisableAllControlsThisFrame();
|
||||
MenuPool.Process();
|
||||
|
||||
var scaleform = new Scaleform("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;
|
||||
return true;
|
||||
}
|
||||
else if (Game.IsControlJustPressed(Control.FrontendCancel))
|
||||
{
|
||||
PopUp.Visible = false;
|
||||
return false;
|
||||
}
|
||||
Script.Yield();
|
||||
Game.DisableAllControlsThisFrame();
|
||||
|
||||
}
|
||||
}
|
||||
public static void UsernameActivated(object a, System.EventArgs b)
|
||||
{
|
||||
string newUsername = Game.GetUserInput(WindowTitle.EnterMessage20, _usernameItem.AltTitle, 20);
|
||||
@@ -77,6 +135,13 @@ namespace RageCoop.Client.Menus
|
||||
}
|
||||
}
|
||||
|
||||
private static void _passwordActivated(object sender, System.EventArgs e)
|
||||
{
|
||||
string newPass = Game.GetUserInput(WindowTitle.EnterMessage20, "", 20);
|
||||
Main.Settings.Password = newPass;
|
||||
Util.SaveSettings();
|
||||
_passwordItem.AltTitle = new string('*', newPass.Length);
|
||||
}
|
||||
public static void ServerIpActivated(object a, System.EventArgs b)
|
||||
{
|
||||
string newServerIp = Game.GetUserInput(WindowTitle.EnterMessage60, ServerIpItem.AltTitle, 60);
|
||||
@@ -0,0 +1,60 @@
|
||||
#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")
|
||||
{
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
public static NativeMenu DiagnosticMenu = new NativeMenu("RAGECOOP", "Diagnostic", "Performence and Diagnostic")
|
||||
{
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
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.BannerText.Color = Color.FromArgb(255, 165, 0);
|
||||
|
||||
|
||||
DiagnosticMenu.Opening += (sender, e) =>
|
||||
{
|
||||
DiagnosticMenu.Clear();
|
||||
DiagnosticMenu.Add(new NativeItem("EntityPool", EntityPool.DumpDebug()));
|
||||
foreach (var pair in Debug.TimeStamps)
|
||||
{
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
var realUrl = Main.Settings.MasterServer=="[AUTO]" ? DownloadString("https://ragecoop.online/stuff/masterserver") : Main.Settings.MasterServer;
|
||||
serverList = JsonConvert.DeserializeObject<List<ServerListClass>>(DownloadString(realUrl));
|
||||
|
||||
List<ServerInfo> serverList = null;
|
||||
var realUrl = Main.Settings.MasterServer;
|
||||
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.Show($"~y~Joining ZeroTier network... {server.ztID}");
|
||||
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.Show($"~r~{ex.Message}");
|
||||
if (server.useZT)
|
||||
{
|
||||
Notification.Show($"Make sure ZeroTier is correctly installed, download it from https://www.zerotier.com/");
|
||||
}
|
||||
}
|
||||
};
|
||||
Menu.Add(tmpItem);
|
||||
@@ -0,0 +1,156 @@
|
||||
using GTA;
|
||||
using LemonUI.Menus;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace RageCoop.Client.Menus
|
||||
{
|
||||
internal static class SettingsMenu
|
||||
{
|
||||
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "Settings", "Go to the settings")
|
||||
{
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
|
||||
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.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 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());
|
||||
|
||||
static SettingsMenu()
|
||||
{
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
|
||||
|
||||
_disableTrafficItem.CheckboxChanged += DisableTrafficCheckboxChanged;
|
||||
_disablePauseAlt.CheckboxChanged += DisablePauseAltCheckboxChanged;
|
||||
_disableVoice.CheckboxChanged += DisableVoiceCheckboxChanged;
|
||||
_flipMenuItem.CheckboxChanged += FlipMenuCheckboxChanged;
|
||||
_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(_disableVoice);
|
||||
Menu.Add(_menuKey);
|
||||
Menu.Add(_passengerKey);
|
||||
Menu.Add(_vehicleSoftLimit);
|
||||
Menu.Add(_pedSoftLimit);
|
||||
Menu.Add(_showBlip);
|
||||
Menu.Add(_showNametag);
|
||||
}
|
||||
|
||||
private static void DisableVoiceCheckboxChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (_disableVoice.Checked)
|
||||
{
|
||||
if (Networking.IsOnServer && !Voice.WasInitialized())
|
||||
{
|
||||
Voice.Init();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Voice.ClearAll();
|
||||
}
|
||||
|
||||
Main.Settings.Voice = _disableVoice.Checked;
|
||||
Util.SaveSettings();
|
||||
}
|
||||
|
||||
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(
|
||||
Game.GetUserInput(WindowTitle.EnterMessage20,
|
||||
Main.Settings.WorldVehicleSoftLimit.ToString(), 20));
|
||||
_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 { }
|
||||
}
|
||||
private static void ChaneMenuKey(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.Settings.MenuKey = (Keys)Enum.Parse(
|
||||
typeof(Keys),
|
||||
Game.GetUserInput(WindowTitle.EnterMessage20,
|
||||
Main.Settings.MenuKey.ToString(), 20));
|
||||
_menuKey.AltTitle = Main.Settings.MenuKey.ToString();
|
||||
Util.SaveSettings();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static void ChangePassengerKey(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.Settings.PassengerKey = (Keys)Enum.Parse(
|
||||
typeof(Keys),
|
||||
Game.GetUserInput(WindowTitle.EnterMessage20,
|
||||
Main.Settings.PassengerKey.ToString(), 20));
|
||||
_passengerKey.AltTitle = Main.Settings.PassengerKey.ToString();
|
||||
Util.SaveSettings();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public static void DisableTrafficCheckboxChanged(object a, System.EventArgs b)
|
||||
{
|
||||
WorldThread.Traffic(!_disableTrafficItem.Checked);
|
||||
Main.Settings.DisableTraffic = _disableTrafficItem.Checked;
|
||||
Util.SaveSettings();
|
||||
}
|
||||
|
||||
public static void FlipMenuCheckboxChanged(object a, System.EventArgs b)
|
||||
{
|
||||
CoopMenu.Menu.Alignment = _flipMenuItem.Checked ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left;
|
||||
|
||||
Menu.Alignment = _flipMenuItem.Checked ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left;
|
||||
Main.Settings.FlipMenu = _flipMenuItem.Checked;
|
||||
Util.SaveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -36,7 +35,7 @@ namespace RageCoop.Client
|
||||
private bool CurrentHidden { get; set; }
|
||||
private bool Hidden
|
||||
{
|
||||
get { return CurrentHidden; }
|
||||
get => CurrentHidden;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
@@ -106,7 +105,7 @@ namespace RageCoop.Client
|
||||
CurrentInput = "";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (key == Keys.PageUp)
|
||||
{
|
||||
MainScaleForm.CallFunction("PAGE_UP");
|
||||
@@ -0,0 +1,185 @@
|
||||
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.Deserialize(data);
|
||||
if (fr.Name.EndsWith(".res"))
|
||||
{
|
||||
_resources.Add(fr.Name);
|
||||
}
|
||||
return new Packets.FileTransferResponse()
|
||||
{
|
||||
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.Deserialize(data);
|
||||
|
||||
Main.Logger.Debug($"Finalizing download:{packet.ID}");
|
||||
Complete(packet.ID);
|
||||
|
||||
// Inform the server that the download is completed
|
||||
return new Packets.FileTransferResponse()
|
||||
{
|
||||
ID = packet.ID,
|
||||
Response = FileResponse.Completed
|
||||
};
|
||||
});
|
||||
Networking.RequestHandlers.Add(PacketType.AllResourcesSent, (data) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.Resources.Load(ResourceFolder, _resources.ToArray());
|
||||
return new Packets.FileTransferResponse() { ID = 0, Response = FileResponse.Loaded };
|
||||
}
|
||||
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 };
|
||||
}
|
||||
});
|
||||
}
|
||||
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 HashSet<string> _resources = new HashSet<string>();
|
||||
public static bool AddFile(int id, string name, long length)
|
||||
{
|
||||
var path = $"{ResourceFolder}\\{name}";
|
||||
Main.Logger.Debug($"Downloading file to {path} , id:{id}");
|
||||
if (!Directory.Exists(Directory.GetParent(path).FullName))
|
||||
{
|
||||
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()
|
||||
{
|
||||
FileID = id,
|
||||
FileName = name,
|
||||
FileLength = length,
|
||||
Stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.ReadWrite)
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the file already exists and if the size correct otherwise delete this file
|
||||
/// </summary>
|
||||
/// <param name="folder"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
private static bool FileAlreadyExists(string folder, string name, long length)
|
||||
{
|
||||
string filePath = $"{folder}\\{name}";
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
if (new FileInfo(filePath).Length == length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Delete the file because the length is wrong (maybe the file was updated)
|
||||
File.Delete(filePath);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Write(int id, byte[] chunk)
|
||||
{
|
||||
lock (InProgressDownloads)
|
||||
{
|
||||
if (InProgressDownloads.TryGetValue(id, out DownloadFile file))
|
||||
{
|
||||
|
||||
file.Stream.Write(chunk, 0, chunk.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
Main.Logger.Trace($"Received unhandled file chunk:{id}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Complete(int id)
|
||||
{
|
||||
|
||||
if (InProgressDownloads.TryGetValue(id, out DownloadFile f))
|
||||
{
|
||||
InProgressDownloads.Remove(id);
|
||||
f.Dispose();
|
||||
Main.Logger.Info($"Download finished:{f.FileName}");
|
||||
DownloadCompleted?.Invoke(null, Path.Combine(ResourceFolder, f.FileName));
|
||||
}
|
||||
else
|
||||
{
|
||||
Main.Logger.Error($"Download not found! {id}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Cleanup()
|
||||
{
|
||||
lock (InProgressDownloads)
|
||||
{
|
||||
foreach (var file in InProgressDownloads.Values)
|
||||
{
|
||||
file.Dispose();
|
||||
}
|
||||
InProgressDownloads.Clear();
|
||||
}
|
||||
_resources.Clear();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
internal class DownloadFile : IDisposable
|
||||
{
|
||||
public int FileID { get; set; } = 0;
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
public long FileLength { get; set; } = 0;
|
||||
public long FileWritten { get; set; } = 0;
|
||||
public FileStream Stream { get; set; }
|
||||
public void Dispose()
|
||||
{
|
||||
if (Stream != null)
|
||||
{
|
||||
Stream.Flush();
|
||||
Stream.Close();
|
||||
Stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
using GTA.UI;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static partial class Networking
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public static void ToggleConnection(string address, string username = null, string password = null, PublicKey publicKey = null)
|
||||
{
|
||||
Menus.CoopMenu.Menu.Visible = false;
|
||||
if (IsConnecting)
|
||||
{
|
||||
_publicKeyReceived.Set();
|
||||
IsConnecting = false;
|
||||
Main.QueueAction(() => Notification.Show("Connection has been canceled"));
|
||||
Peer?.Shutdown("Bye");
|
||||
}
|
||||
else if (IsOnServer)
|
||||
{
|
||||
Peer?.Shutdown("Bye");
|
||||
}
|
||||
else
|
||||
{
|
||||
Peer?.Dispose();
|
||||
|
||||
IsConnecting = true;
|
||||
password = password ?? Main.Settings.Password;
|
||||
username = username ?? Main.Settings.Username;
|
||||
|
||||
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
|
||||
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
|
||||
{
|
||||
AutoFlushSendQueue = false,
|
||||
AcceptIncomingConnections = true,
|
||||
MaximumConnections = 32,
|
||||
PingInterval = 5
|
||||
};
|
||||
#if DEBUG
|
||||
config.SimulatedMinimumLatency = SimulatedLatency;
|
||||
config.SimulatedRandomLatency = 0;
|
||||
#endif
|
||||
config.EnableMessageType(NetIncomingMessageType.UnconnectedData);
|
||||
config.EnableMessageType(NetIncomingMessageType.NatIntroductionSuccess);
|
||||
|
||||
string[] ip = new string[2];
|
||||
|
||||
int idx = address.LastIndexOf(':');
|
||||
if (idx != -1)
|
||||
{
|
||||
ip[0] = address.Substring(0, idx);
|
||||
ip[1] = address.Substring(idx + 1);
|
||||
}
|
||||
|
||||
if (ip.Length != 2)
|
||||
{
|
||||
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();
|
||||
Peer = new CoopPeer(config);
|
||||
Peer.OnMessageReceived += (s, m) =>
|
||||
{
|
||||
try { ProcessMessage(m); }
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Main.Logger.Error(ex);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
Main.QueueAction(() => { Notification.Show($"~y~Trying to connect..."); });
|
||||
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");
|
||||
}
|
||||
}
|
||||
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.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);
|
||||
ServerConnection = Peer.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.Logger.Error("Cannot connect to server: ", ex);
|
||||
Main.QueueAction(() => Notification.Show("Cannot connect to server: " + ex.Message));
|
||||
}
|
||||
IsConnecting = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
public static bool IsOnServer { get => ServerConnection?.Status == NetConnectionStatus.Connected; }
|
||||
|
||||
#region -- PLAYER --
|
||||
private static void PlayerConnect(Packets.PlayerConnect packet)
|
||||
{
|
||||
var p = new Player
|
||||
{
|
||||
ID = packet.PedID,
|
||||
Username = packet.Username,
|
||||
};
|
||||
PlayerList.SetPlayer(packet.PedID, packet.Username);
|
||||
|
||||
Main.Logger.Debug($"player connected:{p.Username}");
|
||||
Main.QueueAction(() =>
|
||||
GTA.UI.Notification.Show($"~h~{p.Username}~h~ connected."));
|
||||
}
|
||||
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
|
||||
{
|
||||
var player = PlayerList.GetPlayer(packet.PedID);
|
||||
if (player == null) { return; }
|
||||
PlayerList.RemovePlayer(packet.PedID);
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
EntityPool.RemoveAllFromPlayer(packet.PedID);
|
||||
GTA.UI.Notification.Show($"~h~{player.Username}~h~ left.");
|
||||
});
|
||||
}
|
||||
|
||||
#endregion // -- PLAYER --
|
||||
#region -- GET --
|
||||
private static bool GetServerPublicKey(string host, int port, int timeout = 10000)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,420 @@
|
||||
using GTA;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Client.Menus;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static partial class Networking
|
||||
{
|
||||
|
||||
/// <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.ReadInt32()].MainProp?.Handle;
|
||||
case 51:
|
||||
return EntityPool.GetPedByID(reader.ReadInt32())?.MainPed?.Handle;
|
||||
case 52:
|
||||
return EntityPool.GetVehicleByID(reader.ReadInt32())?.MainVehicle?.Handle;
|
||||
case 60:
|
||||
return EntityPool.ServerBlips[reader.ReadInt32()].Handle;
|
||||
default:
|
||||
throw new ArgumentException("Cannot resolve server side argument: " + t);
|
||||
}
|
||||
};
|
||||
private static readonly AutoResetEvent _publicKeyReceived = new AutoResetEvent(false);
|
||||
private static bool _recycle;
|
||||
public static void ProcessMessage(NetIncomingMessage message)
|
||||
{
|
||||
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 (message.SenderConnection == ServerConnection)
|
||||
{
|
||||
CoopMenu.InitiateConnectionMenuSetting();
|
||||
}
|
||||
break;
|
||||
case NetConnectionStatus.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; }
|
||||
|
||||
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:
|
||||
if (message.SenderConnection == ServerConnection)
|
||||
{
|
||||
Main.Disconnected(reason);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NetIncomingMessageType.Data:
|
||||
{
|
||||
if (message.LengthBytes == 0) { break; }
|
||||
var packetType = PacketType.Unknown;
|
||||
try
|
||||
{
|
||||
// Get packet type
|
||||
packetType = (PacketType)message.ReadByte();
|
||||
switch (packetType)
|
||||
{
|
||||
case PacketType.Response:
|
||||
{
|
||||
int id = message.ReadInt32();
|
||||
if (PendingResponses.TryGetValue(id, out var callback))
|
||||
{
|
||||
callback((PacketType)message.ReadByte(), message);
|
||||
PendingResponses.Remove(id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PacketType.Request:
|
||||
{
|
||||
int id = message.ReadInt32();
|
||||
var realType = (PacketType)message.ReadByte();
|
||||
if (RequestHandlers.TryGetValue(realType, out var handler))
|
||||
{
|
||||
var response = Peer.CreateMessage();
|
||||
response.Write((byte)PacketType.Response);
|
||||
response.Write(id);
|
||||
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:
|
||||
{
|
||||
|
||||
HandlePacket(packetType, message, message.SenderConnection, ref _recycle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#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);
|
||||
Peer.Shutdown($"Packet Error [{packetType}]");
|
||||
#endif
|
||||
_recycle = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NetIncomingMessageType.UnconnectedData:
|
||||
{
|
||||
var packetType = (PacketType)message.ReadByte();
|
||||
switch (packetType)
|
||||
{
|
||||
|
||||
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;
|
||||
}
|
||||
if (_recycle)
|
||||
{
|
||||
Peer.Recycle(message);
|
||||
}
|
||||
}
|
||||
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:
|
||||
PlayerConnect(msg.GetPacket<Packets.PlayerConnect>());
|
||||
break;
|
||||
|
||||
case PacketType.PlayerDisconnect:
|
||||
PlayerDisconnect(msg.GetPacket<Packets.PlayerDisconnect>());
|
||||
break;
|
||||
|
||||
case PacketType.PlayerInfoUpdate:
|
||||
PlayerList.UpdatePlayer(msg.GetPacket<Packets.PlayerInfoUpdate>());
|
||||
break;
|
||||
|
||||
case PacketType.VehicleSync:
|
||||
ReceivedPackets.VehicelPacket.Deserialize(msg);
|
||||
VehicleSync(ReceivedPackets.VehicelPacket);
|
||||
break;
|
||||
|
||||
case PacketType.PedSync:
|
||||
ReceivedPackets.PedPacket.Deserialize(msg);
|
||||
PedSync(ReceivedPackets.PedPacket);
|
||||
break;
|
||||
case PacketType.ProjectileSync:
|
||||
ReceivedPackets.ProjectilePacket.Deserialize(msg);
|
||||
ProjectileSync(ReceivedPackets.ProjectilePacket);
|
||||
break;
|
||||
|
||||
case PacketType.ChatMessage:
|
||||
{
|
||||
|
||||
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.Deserialize(msg);
|
||||
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
||||
}
|
||||
break;
|
||||
|
||||
case PacketType.CustomEventQueued:
|
||||
{
|
||||
recycle = false;
|
||||
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
packet.Deserialize(msg);
|
||||
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
||||
Peer.Recycle(msg);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case PacketType.FileTransferChunk:
|
||||
{
|
||||
Packets.FileTransferChunk packet = new Packets.FileTransferChunk();
|
||||
packet.Deserialize(msg);
|
||||
DownloadManager.Write(packet.ID, packet.FileChunk);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (packetType.IsSyncEvent())
|
||||
{
|
||||
recycle = false;
|
||||
// Dispatch to script thread
|
||||
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, msg); return true; });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void PedSync(Packets.PedSync packet)
|
||||
{
|
||||
SyncedPed c = EntityPool.GetPedByID(packet.ID);
|
||||
if (c == null)
|
||||
{
|
||||
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) || packet.ID == packet.OwnerID)
|
||||
{
|
||||
// Main.Logger.Debug($"Creating character for incoming sync:{packet.ID}");
|
||||
EntityPool.ThreadSafe.Add(c = new SyncedPed(packet.ID));
|
||||
}
|
||||
else return;
|
||||
}
|
||||
c.ID = packet.ID;
|
||||
c.OwnerID = packet.OwnerID;
|
||||
c.Health = packet.Health;
|
||||
c.Rotation = packet.Rotation;
|
||||
c.Velocity = packet.Velocity;
|
||||
c.Speed = packet.Speed;
|
||||
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 (packet.Flags.HasPedFlag(PedDataFlags.IsFullSync))
|
||||
{
|
||||
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 VehicleSync(Packets.VehicleSync packet)
|
||||
{
|
||||
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
|
||||
if (v == null)
|
||||
{
|
||||
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.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))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
private static void ProjectileSync(Packets.ProjectileSync packet)
|
||||
{
|
||||
var p = EntityPool.GetProjectileByID(packet.ID);
|
||||
if (p == null)
|
||||
{
|
||||
if (packet.Flags.HasProjDataFlag(ProjectileDataFlags.Exploded)) { return; }
|
||||
// Main.Logger.Debug($"Creating new projectile: {(WeaponHash)packet.WeaponHash}");
|
||||
EntityPool.ThreadSafe.Add(p = new SyncedProjectile(packet.ID));
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Reduce GC pressure by reusing frequently used packets
|
||||
/// </summary>
|
||||
private static class SendPackets
|
||||
{
|
||||
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 sp, bool full)
|
||||
{
|
||||
if (sp.LastSentStopWatch.ElapsedMilliseconds < SyncInterval)
|
||||
{
|
||||
return;
|
||||
}
|
||||
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))
|
||||
{
|
||||
p.AimCoords = ped.GetAimCoord();
|
||||
}
|
||||
if (p.Flags.HasPedFlag(PedDataFlags.IsRagdoll))
|
||||
{
|
||||
p.HeadPosition = ped.Bones[Bone.SkelHead].Position;
|
||||
p.RightFootPosition = ped.Bones[Bone.SkelRightFoot].Position;
|
||||
p.LeftFootPosition = ped.Bones[Bone.SkelLeftFoot].Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Seat sync
|
||||
if (p.Speed >= 4)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
SendSync(p, ConnectionChannel.PedSync);
|
||||
}
|
||||
public static void SendVehicle(SyncedVehicle v, bool full)
|
||||
{
|
||||
if (v.LastSentStopWatch.ElapsedMilliseconds < SyncInterval)
|
||||
{
|
||||
return;
|
||||
}
|
||||
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.RotationVelocity;
|
||||
packet.ThrottlePower = veh.ThrottlePower;
|
||||
packet.BrakePower = veh.BrakePower;
|
||||
v.LastSentStopWatch.Restart();
|
||||
if (packet.Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering)) { packet.DeluxoWingRatio = v.MainVehicle.GetDeluxoWingRatio(); }
|
||||
if (full)
|
||||
{
|
||||
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;
|
||||
}
|
||||
SendSync(packet, ConnectionChannel.VehicleSync);
|
||||
}
|
||||
public static void SendProjectile(SyncedProjectile sp)
|
||||
{
|
||||
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 SendBullet(Vector3 start, Vector3 end, uint weapon, int ownerID)
|
||||
{
|
||||
SendSync(new Packets.BulletShot()
|
||||
{
|
||||
StartPosition = start,
|
||||
EndPosition = end,
|
||||
OwnerID = ownerID,
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class Statistics
|
||||
{
|
||||
public static int BytesDownPerSecond { get; private set; }
|
||||
public static int BytesUpPerSecond { get; private set; }
|
||||
static Statistics()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var bu = Networking.Peer.Statistics.SentBytes;
|
||||
var bd = Networking.Peer.Statistics.ReceivedBytes;
|
||||
Thread.Sleep(1000);
|
||||
BytesUpPerSecond = Networking.Peer.Statistics.SentBytes - bu;
|
||||
BytesDownPerSecond = Networking.Peer.Statistics.ReceivedBytes - bd;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class PlayerList
|
||||
{
|
||||
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 ulong _lastUpdate = Util.GetTickCount64();
|
||||
public static ulong Pressed { get; set; }
|
||||
|
||||
public static bool LeftAlign = true;
|
||||
public static Dictionary<int, Player> Players = new Dictionary<int, Player> { };
|
||||
public static void Tick()
|
||||
{
|
||||
if (!Networking.IsOnServer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((Util.GetTickCount64() - _lastUpdate) >= 1000)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
|
||||
if ((Util.GetTickCount64() - Pressed) < 5000 && !Main.MainChat.Focused
|
||||
#if !NON_INTERACTIVE
|
||||
&& !Menus.CoopMenu.MenuPool.AreAnyVisible
|
||||
#endif
|
||||
)
|
||||
{
|
||||
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()
|
||||
{
|
||||
_lastUpdate = Util.GetTickCount64();
|
||||
|
||||
_mainScaleform.CallFunction("SET_DATA_SLOT_EMPTY", 0);
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var player in Players.Values)
|
||||
{
|
||||
_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} players");
|
||||
_mainScaleform.CallFunction("DISPLAY_VIEW");
|
||||
}
|
||||
public static void SetPlayer(int id, string username, float latency = 0)
|
||||
{
|
||||
Main.Logger.Debug($"{id},{username},{latency}");
|
||||
if (Players.TryGetValue(id, out Player p))
|
||||
{
|
||||
p.Username = username;
|
||||
p.ID = id;
|
||||
p._latencyToServer = latency;
|
||||
}
|
||||
else
|
||||
{
|
||||
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 != null)
|
||||
{
|
||||
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 Player GetPlayer(int id)
|
||||
{
|
||||
Players.TryGetValue(id, out Player p);
|
||||
return p;
|
||||
}
|
||||
public static Player GetPlayer(SyncedPed p)
|
||||
{
|
||||
var player = GetPlayer(p.ID);
|
||||
if (player != null)
|
||||
{
|
||||
player.Character = p;
|
||||
}
|
||||
return player;
|
||||
}
|
||||
public static void RemovePlayer(int id)
|
||||
{
|
||||
if (Players.TryGetValue(id, out var player))
|
||||
{
|
||||
Players.Remove(id);
|
||||
Main.QueueAction(() => player.FakeBlip?.Delete());
|
||||
}
|
||||
}
|
||||
public static void Cleanup()
|
||||
{
|
||||
foreach (var p in Players.Values.ToArray())
|
||||
{
|
||||
p.FakeBlip?.Delete();
|
||||
}
|
||||
Players = new Dictionary<int, Player> { };
|
||||
}
|
||||
}
|
||||
|
||||
public class Player
|
||||
{
|
||||
public byte HolePunchStatus { get; internal set; } = 1;
|
||||
public bool IsHost { get; internal set; }
|
||||
public string Username { get; internal set; }
|
||||
/// <summary>
|
||||
/// Universal ped ID.
|
||||
/// </summary>
|
||||
public int ID
|
||||
{
|
||||
get; internal 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 round-trip time in seconds, will be the rtt to server if not using P2P connection.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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" )]
|
||||
|
||||
@@ -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;
|
||||
#>
|
||||
@@ -0,0 +1,310 @@
|
||||
<?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>
|
||||
<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>
|
||||
<ItemGroup>
|
||||
<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">
|
||||
<Project>{cc2e8102-e568-4524-aa1f-f8e0f1cfe58a}</Project>
|
||||
<Name>RageCoop.Core</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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, Version=2012.1.7.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\libs\Lidgren.Network.dll</HintPath>
|
||||
</Reference>
|
||||
<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">
|
||||
<HintPath>..\libs\ScriptHookVDotNet.dll</HintPath>
|
||||
</Reference>
|
||||
<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>
|
||||
<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>
|
||||
@@ -0,0 +1,339 @@
|
||||
#undef DEBUG
|
||||
using GTA;
|
||||
using Newtonsoft.Json;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace RageCoop.Client.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class CustomEventReceivedArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The event hash
|
||||
/// </summary>
|
||||
public int Hash { get; set; }
|
||||
/// <summary>
|
||||
/// Supported types: byte, short, ushort, int, uint, long, ulong, float, bool, string, Vector3, Quaternion
|
||||
/// </summary>
|
||||
public object[] Args { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Provides vital functionality to interact with RAGECOOP
|
||||
/// </summary>
|
||||
public class API
|
||||
{
|
||||
#region INTERNAL
|
||||
internal static Dictionary<int, List<Action<CustomEventReceivedArgs>>> CustomEventHandlers = new Dictionary<int, List<Action<CustomEventReceivedArgs>>>();
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Client configuration, this will conflict with server-side config.
|
||||
/// </summary>
|
||||
public static class Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Get or set local player's username, set won't be effective if already connected to a server.
|
||||
/// </summary>
|
||||
public static string Username
|
||||
{
|
||||
get => Main.Settings.Username;
|
||||
set
|
||||
{
|
||||
if (Networking.IsOnServer || string.IsNullOrEmpty(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Main.Settings.Username = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Enable automatic respawn for this player.
|
||||
/// </summary>
|
||||
public static bool EnableAutoRespawn { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Get or set player's blip color
|
||||
/// </summary>
|
||||
public static BlipColor BlipColor { get; set; } = BlipColor.White;
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
public static float BlipScale { get; set; } = 1;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Base events for RageCoop
|
||||
/// </summary>
|
||||
public static class Events
|
||||
{
|
||||
#region DELEGATES
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public delegate void EmptyEvent();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="hash"></param>
|
||||
/// <param name="args"></param>
|
||||
public delegate void CustomEvent(int hash, List<object> args);
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// The local player is dead
|
||||
/// </summary>
|
||||
public static event EventHandler<string> OnPlayerDied;
|
||||
|
||||
/// <summary>
|
||||
/// A local vehicle is spawned
|
||||
/// </summary>
|
||||
public static event EventHandler<SyncedVehicle> OnVehicleSpawned;
|
||||
|
||||
/// <summary>
|
||||
/// A local vehicle is deleted
|
||||
/// </summary>
|
||||
public static event EventHandler<SyncedVehicle> OnVehicleDeleted;
|
||||
|
||||
/// <summary>
|
||||
/// A local ped is spawned
|
||||
/// </summary>
|
||||
public static event EventHandler<SyncedPed> OnPedSpawned;
|
||||
|
||||
/// <summary>
|
||||
/// A local ped is deleted
|
||||
/// </summary>
|
||||
public static event EventHandler<SyncedPed> OnPedDeleted;
|
||||
|
||||
/// <summary>
|
||||
/// This is equivalent of <see cref="GTA.Script.Tick"/>.
|
||||
/// </summary>
|
||||
public static event EmptyEvent OnTick;
|
||||
|
||||
/// <summary>
|
||||
/// This is equivalent of <see cref="Script.KeyDown"/>
|
||||
/// </summary>
|
||||
public static KeyEventHandler OnKeyDown;
|
||||
|
||||
/// <summary>
|
||||
/// This is equivalent of <see cref="Script.KeyUp"/>
|
||||
/// </summary>
|
||||
public static KeyEventHandler OnKeyUp;
|
||||
|
||||
#region INVOKE
|
||||
internal static void InvokeVehicleSpawned(SyncedVehicle v) { OnVehicleSpawned?.Invoke(null, v); }
|
||||
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(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 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 };
|
||||
|
||||
// Main.Logger.Debug($"CustomEvent:\n"+args.Args.DumpWithType());
|
||||
|
||||
if (CustomEventHandlers.TryGetValue(p.Hash, out List<Action<CustomEventReceivedArgs>> handlers))
|
||||
{
|
||||
handlers.ForEach((x) => { x.Invoke(args); });
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region PROPERTIES
|
||||
|
||||
/// <summary>
|
||||
/// Get the local player's ID
|
||||
/// </summary>
|
||||
/// <returns>PlayerID</returns>
|
||||
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 => Menus.CoopMenu.MenuPool.AreAnyVisible;
|
||||
|
||||
/// <summary>
|
||||
/// Check if the RAGECOOP chat is visible
|
||||
/// </summary>
|
||||
public static bool IsChatFocused => Main.MainChat.Focused;
|
||||
|
||||
/// <summary>
|
||||
/// Check if the RAGECOOP list of players is visible
|
||||
/// </summary>
|
||||
public static bool IsPlayerListVisible => Util.GetTickCount64() - PlayerList.Pressed < 5000;
|
||||
|
||||
/// <summary>
|
||||
/// Get the version of RAGECOOP
|
||||
/// </summary>
|
||||
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 => 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>
|
||||
/// <param name="from">Name of the sender</param>
|
||||
/// <param name="message">The player's message</param>
|
||||
public static void LocalChatMessage(string from, string message)
|
||||
{
|
||||
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>
|
||||
/// <param name="a"></param>
|
||||
public static void QueueAction(Action a)
|
||||
{
|
||||
Main.QueueAction(a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
|
||||
/// </summary>
|
||||
/// <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)
|
||||
{
|
||||
Main.QueueAction(a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send an event and data to the server.
|
||||
/// </summary>
|
||||
/// <param name="eventHash">An unique identifier of the event</param>
|
||||
/// <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)
|
||||
{
|
||||
|
||||
Networking.Peer.SendTo(new Packets.CustomEvent()
|
||||
{
|
||||
Args = args,
|
||||
Hash = eventHash
|
||||
}, Networking.ServerConnection, ConnectionChannel.Event, Lidgren.Network.NetDeliveryMethod.ReliableOrdered);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register an handler to the specifed event hash, one event can have multiple handlers. This will be invoked from backgound thread, use <see cref="QueueAction(Action)"/> in the handler to dispatch code to script thread.
|
||||
/// </summary>
|
||||
/// <param name="hash">An unique identifier of the event, you can hash your event name with <see cref="Core.Scripting.CustomEvents.Hash(string)"/></param>
|
||||
/// <param name="handler">An handler to be invoked when the event is received from the server. </param>
|
||||
public static void RegisterCustomEventHandler(int hash, Action<CustomEventReceivedArgs> handler)
|
||||
{
|
||||
lock (CustomEventHandlers)
|
||||
{
|
||||
if (!CustomEventHandlers.TryGetValue(hash, out List<Action<CustomEventReceivedArgs>> handlers))
|
||||
{
|
||||
CustomEventHandlers.Add(hash, handlers = new List<Action<CustomEventReceivedArgs>>());
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using RageCoop.Core.Scripting;
|
||||
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;
|
||||
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.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.ServerPropSync, ServerObjectSync);
|
||||
API.RegisterCustomEventHandler(CustomEvents.DeleteServerProp, DeleteServerProp);
|
||||
API.RegisterCustomEventHandler(CustomEvents.DeleteEntity, DeleteEntity);
|
||||
API.RegisterCustomEventHandler(CustomEvents.SetDisplayNameTag, SetNameTag);
|
||||
API.RegisterCustomEventHandler(CustomEvents.ServerBlipSync, ServerBlipSync);
|
||||
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.WeatherTimeSync, WeatherTimeSync);
|
||||
API.RegisterCustomEventHandler(CustomEvents.OnPlayerDied, (e) => { GTA.UI.Notification.Show((string)e.Args[0]); });
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_isHost)
|
||||
{
|
||||
API.QueueAction(() =>
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var time = World.CurrentTimeOfDay;
|
||||
int weather1 = default(int);
|
||||
int weather2 = default(int);
|
||||
float percent2 = default(float);
|
||||
Function.Call(Hash.GET_CURR_WEATHER_STATE, &weather1, &weather2, &percent2);
|
||||
API.SendCustomEvent(CustomEvents.WeatherTimeSync, time.Hours, time.Minutes, time.Seconds, weather1, weather2, percent2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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_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]; }
|
||||
}
|
||||
|
||||
private void UpdatePedBlip(CustomEventReceivedArgs e)
|
||||
{
|
||||
var p = Entity.FromHandle((int)e.Args[0]);
|
||||
if (p == null) { return; }
|
||||
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];
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateVehicle(CustomEventReceivedArgs e)
|
||||
{
|
||||
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)
|
||||
{
|
||||
veh = World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3]);
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
veh.CanPretendOccupants = false;
|
||||
var v = new SyncedVehicle()
|
||||
{
|
||||
ID = (int)e.Args[0],
|
||||
MainVehicle = veh,
|
||||
OwnerID = Main.LocalPlayerID,
|
||||
};
|
||||
EntityPool.Add(v);
|
||||
}
|
||||
|
||||
private void DeleteServerBlip(CustomEventReceivedArgs e)
|
||||
{
|
||||
if (EntityPool.ServerBlips.TryGetValue((int)e.Args[0], out var blip))
|
||||
{
|
||||
EntityPool.ServerBlips.Remove((int)e.Args[0]);
|
||||
blip?.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
private void ServerBlipSync(CustomEventReceivedArgs obj)
|
||||
{
|
||||
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];
|
||||
if (!EntityPool.ServerBlips.TryGetValue(id, out Blip blip))
|
||||
{
|
||||
EntityPool.ServerBlips.Add(id, blip = World.CreateBlip(pos));
|
||||
}
|
||||
blip.Sprite = sprite;
|
||||
blip.Color = color;
|
||||
blip.Scale = scale;
|
||||
blip.Position = pos;
|
||||
blip.Rotation = rot;
|
||||
blip.Name = name;
|
||||
}
|
||||
|
||||
|
||||
private void DeleteEntity(CustomEventReceivedArgs e)
|
||||
{
|
||||
Entity.FromHandle((int)e.Args[0])?.Delete();
|
||||
}
|
||||
|
||||
public override void OnStop()
|
||||
{
|
||||
}
|
||||
private void SetNameTag(CustomEventReceivedArgs e)
|
||||
{
|
||||
var p = PlayerList.GetPlayer((int)e.Args[0]);
|
||||
if (p != null)
|
||||
{
|
||||
p.DisplayNameTag = (bool)e.Args[1];
|
||||
}
|
||||
}
|
||||
private void SetAutoRespawn(CustomEventReceivedArgs args)
|
||||
{
|
||||
API.Config.EnableAutoRespawn = (bool)args.Args[0];
|
||||
}
|
||||
private void DeleteServerProp(CustomEventReceivedArgs e)
|
||||
{
|
||||
var id = (int)e.Args[0];
|
||||
if (EntityPool.ServerProps.TryGetValue(id, out var prop))
|
||||
{
|
||||
EntityPool.ServerProps.Remove(id);
|
||||
prop?.MainProp?.Delete();
|
||||
}
|
||||
|
||||
}
|
||||
private void ServerObjectSync(CustomEventReceivedArgs e)
|
||||
{
|
||||
SyncedProp prop;
|
||||
var id = (int)e.Args[0];
|
||||
lock (EntityPool.PropsLock)
|
||||
{
|
||||
if (!EntityPool.ServerProps.TryGetValue(id, out prop))
|
||||
{
|
||||
EntityPool.ServerProps.Add(id, prop = new SyncedProp(id));
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
List<InputArgument> arguments = new List<InputArgument>();
|
||||
int i;
|
||||
var ty = (byte)e.Args[0];
|
||||
TypeCode returnType = (TypeCode)ty;
|
||||
i = returnType == TypeCode.Empty ? 1 : 2;
|
||||
var hash = (Hash)e.Args[i++];
|
||||
for (; i < e.Args.Length; i++)
|
||||
{
|
||||
arguments.Add(GetInputArgument(e.Args[i]));
|
||||
}
|
||||
|
||||
if (returnType == TypeCode.Empty)
|
||||
{
|
||||
Function.Call(hash, arguments.ToArray());
|
||||
return;
|
||||
}
|
||||
var t = returnType;
|
||||
int id = (int)e.Args[1];
|
||||
|
||||
|
||||
switch (returnType)
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<bool>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Byte:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<byte>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Char:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<char>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Single:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<float>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Double:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<double>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Int16:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<short>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Int32:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<int>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Int64:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<long>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.String:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<string>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.UInt16:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<ushort>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.UInt32:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<uint>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.UInt64:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<ulong>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
private InputArgument GetInputArgument(object obj)
|
||||
{
|
||||
// Implicit conversion
|
||||
switch (obj)
|
||||
{
|
||||
case byte _:
|
||||
return (byte)obj;
|
||||
case short _:
|
||||
return (short)obj;
|
||||
case ushort _:
|
||||
return (ushort)obj;
|
||||
case int _:
|
||||
return (int)obj;
|
||||
case uint _:
|
||||
return (uint)obj;
|
||||
case long _:
|
||||
return (long)obj;
|
||||
case ulong _:
|
||||
return (ulong)obj;
|
||||
case float _:
|
||||
return (float)obj;
|
||||
case bool _:
|
||||
return (bool)obj;
|
||||
case string _:
|
||||
return (obj as string);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using RageCoop.Core.Scripting;
|
||||
|
||||
namespace RageCoop.Client.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Inherit from this class, constructor will be called automatically, but other scripts might have yet been loaded, you should use <see cref="OnStart"/>. to initiate your script.
|
||||
/// </summary>
|
||||
public abstract class ClientScript
|
||||
{
|
||||
/// <summary>
|
||||
/// This method would be called from background thread, call <see cref="API.QueueAction(System.Action)"/> to dispatch it to main thread.
|
||||
/// </summary>
|
||||
public abstract void OnStart();
|
||||
|
||||
/// <summary>
|
||||
/// This method would be called from background thread when the client disconnected from the server, you MUST terminate all background jobs/threads in this method.
|
||||
/// </summary>
|
||||
public abstract void OnStop();
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="ResourceFile"/> instance where this script is loaded from.
|
||||
/// </summary>
|
||||
public ResourceFile CurrentFile { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="ClientResource"/> that this script belongs to.
|
||||
/// </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;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using RageCoop.Core;
|
||||
using RageCoop.Core.Scripting;
|
||||
using System;
|
||||
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>();
|
||||
|
||||
/// <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.CurrentResource = d;
|
||||
s.OnStart();
|
||||
}
|
||||
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 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") && !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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using RageCoop.Core;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class Security
|
||||
{
|
||||
public RSA ServerRSA { get; set; }
|
||||
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)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
public byte[] Encrypt(byte[] data)
|
||||
{
|
||||
return new CryptoStream(new MemoryStream(data), ClientAes.CreateEncryptor(), CryptoStreamMode.Read).ReadToEnd();
|
||||
}
|
||||
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);
|
||||
}
|
||||
public void Regen()
|
||||
{
|
||||
ClientAes = Aes.Create();
|
||||
ClientAes.GenerateKey();
|
||||
ClientAes.GenerateIV();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,23 +12,31 @@ namespace RageCoop.Client
|
||||
/// </summary>
|
||||
public string Username { get; set; } = "Player";
|
||||
/// <summary>
|
||||
/// The password used to authenticate when connecting to a server.
|
||||
/// </summary>
|
||||
public string Password { get; set; } = "";
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public string LastServerAddress { get; set; } = "127.0.0.1:4499";
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public string MasterServer { get; set; } = "[AUTO]";
|
||||
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
|
||||
@@ -38,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.
|
||||
@@ -53,11 +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>
|
||||
/// Disable automatic respawn.
|
||||
/// The game won't spawn more NPC traffic if the limit is exceeded. -1 for unlimited (not recommended).
|
||||
/// </summary>
|
||||
public bool DisableAutoRespawn { get; set; } = false;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user