Compare commits
129 Commits
Author | SHA1 | Date | |
---|---|---|---|
3b901d8e6c | |||
9764484f4a | |||
5f781f6f48 | |||
fcd7e18d9b | |||
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 |
48
.github/workflows/build-test.yaml
vendored
Normal file
48
.github/workflows/build-test.yaml
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
name: Build test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*' # matches every branch that doesn't contain a '/'
|
||||
- '*/*' # matches every branch containing a single '/'
|
||||
- '**' # matches every branch
|
||||
- '!main' # excludes main
|
||||
- '!dev-nightly' # excludes nightly
|
||||
|
||||
pull_request:
|
||||
branches: [ "main", "dev-nightly" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
dotnet-version: ['6.0.x']
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v2
|
||||
with:
|
||||
dotnet-version: ${{ matrix.dotnet-version }}
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Restore nuget packages
|
||||
run: nuget restore
|
||||
- name: Build client and installer
|
||||
run: dotnet build RageCoop.Client.Installer/RageCoop.Client.Installer.csproj --configuration Release -o bin/Release/Client/RageCoop
|
||||
- name: Build server win-x64
|
||||
run: dotnet build RageCoop.Server/RageCoop.Server.csproj -o bin/Release/Server
|
||||
- name: Upload server
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: RageCoop.Server
|
||||
path: bin/Release/Server
|
||||
- name: Upload Client
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: RageCoop.Client
|
||||
path: bin/Release/Client
|
||||
- uses: actions/checkout@v2
|
||||
|
32
.github/workflows/docker-build.yaml
vendored
Normal file
32
.github/workflows/docker-build.yaml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: Build and Push Docker Image to GHCR
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set repo owner to lowercase
|
||||
run: echo "REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker image to GHCR
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ghcr.io/${{ env.REPO_OWNER }}/ragecoop-v:latest
|
||||
dockerfile: Dockerfile
|
80
.github/workflows/nightly-build.yaml
vendored
80
.github/workflows/nightly-build.yaml
vendored
@ -1,15 +1,11 @@
|
||||
name: Nightly-build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: windows-latest
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
dotnet-version: ['6.0.x']
|
||||
@ -23,16 +19,16 @@ jobs:
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Restore nuget packages
|
||||
run: nuget restore
|
||||
- name: Build client
|
||||
run: dotnet build RageCoop.Client/RageCoop.Client.csproj --configuration Release -o bin/Release/Client/RageCoop
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y nuget
|
||||
nuget restore
|
||||
- name: Build client and installer
|
||||
run: dotnet build RageCoop.Client.Installer/RageCoop.Client.Installer.csproj --configuration Release -o bin/Release/Client/RageCoop
|
||||
- name: Build server win-x64
|
||||
run: dotnet publish RageCoop.Server/RageCoop.Server.csproj --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=false -r win-x64 -o RageCoop.Server/bin/win-x64 -c Release
|
||||
run: dotnet publish RageCoop.Server/RageCoop.Server.csproj --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=false -r win-x64 -o bin/Release/Server/win-x64 -c Release
|
||||
- name: Build server linux-x64
|
||||
run: dotnet publish RageCoop.Server/RageCoop.Server.csproj --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=false -r linux-x64 -o RageCoop.Server/bin/linux-x64 -c Release
|
||||
- name: Build server linux-arm
|
||||
run: dotnet publish RageCoop.Server/RageCoop.Server.csproj --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=false -r linux-arm -o RageCoop.Server/bin/linux-arm -c Release
|
||||
|
||||
run: dotnet publish RageCoop.Server/RageCoop.Server.csproj --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=false -r linux-x64 -o bin/Release/Server/linux-x64 -c Release
|
||||
- uses: vimtor/action-zip@v1
|
||||
with:
|
||||
files: bin/Release/Client
|
||||
@ -40,62 +36,10 @@ jobs:
|
||||
|
||||
- uses: vimtor/action-zip@v1
|
||||
with:
|
||||
files: RageCoop.Server/bin/win-x64
|
||||
files: bin/Release/Server/win-x64
|
||||
dest: RageCoop.Server-win-x64.zip
|
||||
|
||||
- uses: vimtor/action-zip@v1
|
||||
with:
|
||||
files: RageCoop.Server/bin/linux-x64
|
||||
files: bin/Release/Server/linux-x64
|
||||
dest: RageCoop.Server-linux-x64.zip
|
||||
|
||||
- uses: vimtor/action-zip@v1
|
||||
with:
|
||||
files: RageCoop.Server/bin/linux-arm
|
||||
dest: RageCoop.Server-linux-arm.zip
|
||||
|
||||
- uses: WebFreak001/deploy-nightly@v1.1.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # automatically provided by github actions
|
||||
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
|
||||
|
||||
|
||||
- uses: WebFreak001/deploy-nightly@v1.1.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # automatically provided by github actions
|
||||
with:
|
||||
upload_url: https://uploads.github.com/repos/RAGECOOP/RAGECOOP-V/releases/70603992/assets{?name,label}
|
||||
release_id: 70603992
|
||||
asset_path: RageCoop.Server-linux-arm.zip
|
||||
asset_name: RageCoop.Server-linux-arm.zip
|
||||
asset_content_type: application/zip
|
||||
max_releases: 7
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
||||
**/packages
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/.idea
|
28
Dockerfile
Normal file
28
Dockerfile
Normal file
@ -0,0 +1,28 @@
|
||||
# Use the official image as a parent image
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
|
||||
# Use the SDK image to build the app
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
|
||||
WORKDIR /src
|
||||
|
||||
# Copy csproj and restore as distinct layers
|
||||
COPY RageCoop.Server/*.csproj ./RageCoop.Server/
|
||||
COPY libs/*.dll ./libs/
|
||||
|
||||
# Assuming RageCoop.Core is a dependency, if not, you can comment out the next line
|
||||
COPY RageCoop.Core/*.csproj ./RageCoop.Core/
|
||||
|
||||
RUN dotnet restore RageCoop.Server/RageCoop.Server.csproj
|
||||
|
||||
# Copy everything else and build
|
||||
COPY . .
|
||||
WORKDIR /src/RageCoop.Server
|
||||
RUN dotnet publish -c Release -o /app
|
||||
|
||||
# Build runtime image
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=build-env /app .
|
||||
ENTRYPOINT ["dotnet", "RageCoop.Server.dll"]
|
45
README.md
45
README.md
@ -1,6 +1,7 @@
|
||||
|
||||
|
||||
# 🌐 RAGECOOP
|
||||
|
||||
[![Downloads][downloads-shield]][downloads-url]
|
||||
[![Contributors][contributors-shield]][contributors-url]
|
||||
[![Forks][forks-shield]][forks-url]
|
||||
@ -9,24 +10,37 @@
|
||||
|
||||
|
||||
# 🧠 That's it
|
||||
|
||||
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
|
||||
@ -35,17 +49,17 @@ RAGECOOP brings multiplayer experience to the story mode, you can complete missi
|
||||
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.online).
|
||||
8. Powerful scripting API and resource system, easily [add multiplayer functionality to your mod](HTTPS://docs.ragecoop.com).
|
||||
|
||||
# Known issues
|
||||
# ⚠ Known issues
|
||||
|
||||
See [Bugs](https://github.com/RAGECOOP/RAGECOOP-V/issues/33)
|
||||
|
||||
|
||||
## Installation
|
||||
# 🔫 Installation
|
||||
Refer to the [wiki](https://github.com/RAGECOOP/RAGECOOP-V/wiki)
|
||||
|
||||
# Downloads
|
||||
# 🧨 Downloads
|
||||
|
||||
Download latest release [here](https://github.com/RAGECOOP/RAGECOOP-V/releases/latest)
|
||||
|
||||
@ -56,6 +70,7 @@ Please note that this is incompatible with all previous versions of ragecoop, re
|
||||
|
||||
|
||||
# 🦆 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)
|
||||
@ -64,6 +79,7 @@ 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
|
||||
@ -77,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
|
||||
|
||||
|
||||
|
@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Core", "RageCoop.C
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RageCoop.Client", "RageCoop.Client\RageCoop.Client.csproj", "{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Client.Installer", "RageCoop.Client.Installer\RageCoop.Client.Installer.csproj", "{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -41,6 +43,14 @@ Global
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|x64.Build.0 = Release|Any CPU
|
||||
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
9
RageCoop.Client.Installer/App.xaml
Normal file
9
RageCoop.Client.Installer/App.xaml
Normal file
@ -0,0 +1,9 @@
|
||||
<Application x:Class="RageCoop.Client.Installer.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:RageCoop.Client.Installer"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
11
RageCoop.Client.Installer/App.xaml.cs
Normal file
11
RageCoop.Client.Installer/App.xaml.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace RageCoop.Client.Installer
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
10
RageCoop.Client.Installer/AssemblyInfo.cs
Normal file
10
RageCoop.Client.Installer/AssemblyInfo.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
15
RageCoop.Client.Installer/MainWindow.xaml
Normal file
15
RageCoop.Client.Installer/MainWindow.xaml
Normal file
@ -0,0 +1,15 @@
|
||||
<Window x:Class="RageCoop.Client.Installer.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:RageCoop.Client.Installer"
|
||||
mc:Ignorable="d"
|
||||
Title="MainWindow" Height="376" Width="617" Background="#FFBABABA">
|
||||
<Grid>
|
||||
<Grid.Background>
|
||||
<ImageBrush ImageSource="/bg.png" Opacity="0.2"/>
|
||||
</Grid.Background>
|
||||
<Label x:Name="Status" FontSize="20" Foreground="#FF232323" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</Window>
|
213
RageCoop.Client.Installer/MainWindow.xaml.cs
Normal file
213
RageCoop.Client.Installer/MainWindow.xaml.cs
Normal file
@ -0,0 +1,213 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Input;
|
||||
using MessageBox = System.Windows.MessageBox;
|
||||
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
|
||||
using Path = System.IO.Path;
|
||||
using RageCoop.Core;
|
||||
|
||||
namespace RageCoop.Client.Installer
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
Choose();
|
||||
}
|
||||
|
||||
private void Choose()
|
||||
{
|
||||
var od = new OpenFileDialog()
|
||||
{
|
||||
Filter = "GTA 5 executable |GTA5.exe;PlayGTAV.exe",
|
||||
Title = "Select you GTAV executable"
|
||||
};
|
||||
if (od.ShowDialog() ?? false == true)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Install(Directory.GetParent(od.FileName).FullName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("Installation failed: " + ex.ToString());
|
||||
Environment.Exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void Install(string root)
|
||||
{
|
||||
UpdateStatus("Checking requirements");
|
||||
var shvPath = Path.Combine(root, "ScriptHookV.dll");
|
||||
var shvdnPath = Path.Combine(root, "ScriptHookVDotNet3.dll");
|
||||
var scriptsPath = Path.Combine(root, "Scripts");
|
||||
var lemonPath = Path.Combine(scriptsPath, "LemonUI.SHVDN3.dll");
|
||||
var installPath = Path.Combine(scriptsPath, "RageCoop");
|
||||
if (Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName == installPath)
|
||||
{
|
||||
throw new InvalidOperationException("The installer is not meant to be run in the game folder, please extract the zip to somewhere else and run again.");
|
||||
}
|
||||
Directory.CreateDirectory(installPath);
|
||||
if (!File.Exists(shvPath))
|
||||
{
|
||||
MessageBox.Show("Please install ScriptHookV first!");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
if (!File.Exists(shvdnPath))
|
||||
{
|
||||
MessageBox.Show("Please install ScriptHookVDotNet first!");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
var shvdnVer = GetVer(shvdnPath);
|
||||
if (shvdnVer < new Version(3, 6, 0))
|
||||
{
|
||||
MessageBox.Show("Please update ScriptHookVDotNet to latest version!" +
|
||||
$"\nCurrent version is {shvdnVer}, 3.6.0 or higher is required");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
if (File.Exists(lemonPath))
|
||||
{
|
||||
var lemonVer = GetVer(lemonPath);
|
||||
if (lemonVer < new Version(1, 7))
|
||||
{
|
||||
UpdateStatus("Updating LemonUI");
|
||||
File.WriteAllBytes(lemonPath, getLemon());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UpdateStatus("Removing old versions");
|
||||
|
||||
foreach (var f in Directory.GetFiles(scriptsPath, "RageCoop.*", SearchOption.AllDirectories))
|
||||
{
|
||||
if (f.EndsWith("RageCoop.Client.Settings.xml")) { continue; }
|
||||
File.Delete(f);
|
||||
}
|
||||
foreach (var f in Directory.GetFiles(installPath, "*.dll", SearchOption.AllDirectories))
|
||||
{
|
||||
File.Delete(f);
|
||||
}
|
||||
|
||||
if (File.Exists("RageCoop.Core.dll") && File.Exists("RageCoop.Client.dll"))
|
||||
{
|
||||
UpdateStatus("Installing...");
|
||||
CoreUtils.CopyFilesRecursively(new DirectoryInfo(Directory.GetCurrentDirectory()), new DirectoryInfo(installPath));
|
||||
Finish();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Required files are missing, please re-download the zip from official website");
|
||||
}
|
||||
|
||||
void Finish()
|
||||
{
|
||||
|
||||
checkKeys:
|
||||
UpdateStatus("Checking conflicts");
|
||||
var menyooConfig = Path.Combine(root, @"menyooStuff\menyooConfig.ini");
|
||||
var settingsPath = Path.Combine(installPath, @"Data\RageCoop.Client.Settings.xml");
|
||||
Settings settings = null;
|
||||
try
|
||||
{
|
||||
settings = Util.ReadSettings(settingsPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
settings = new Settings();
|
||||
}
|
||||
if (File.Exists(menyooConfig))
|
||||
{
|
||||
var lines = File.ReadAllLines(menyooConfig).Where(x => !x.StartsWith(";") && x.EndsWith(" = " + (int)settings.MenuKey));
|
||||
if (lines.Any())
|
||||
{
|
||||
if (MessageBox.Show("Following menyoo config value will conflict with RAGECOOP menu key\n" +
|
||||
string.Join("\n", lines)
|
||||
+ "\nDo you wish to change the Menu Key?", "Warning!", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
{
|
||||
var ae = new AutoResetEvent(false);
|
||||
UpdateStatus("Press the key you wish to change to");
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
KeyDown += (s, e) =>
|
||||
{
|
||||
settings.MenuKey = (Keys)KeyInterop.VirtualKeyFromKey(e.Key);
|
||||
ae.Set();
|
||||
}));
|
||||
ae.WaitOne();
|
||||
if (!Util.SaveSettings(settingsPath, settings))
|
||||
{
|
||||
MessageBox.Show("Error occurred when saving settings");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
MessageBox.Show("Menu key changed to " + settings.MenuKey);
|
||||
goto checkKeys;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateStatus("Checking ZeroTier");
|
||||
try
|
||||
{
|
||||
ZeroTierHelper.Check();
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (MessageBox.Show("You can't join ZeroTier server unless ZeroTier is installed, do you want to download and install it?", "Install ZeroTier", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
{
|
||||
var url = "https://download.zerotier.com/dist/ZeroTier%20One.msi";
|
||||
UpdateStatus("Downloading ZeroTier from " + url);
|
||||
try
|
||||
{
|
||||
HttpHelper.DownloadFile(url, "ZeroTier.msi", (p) => UpdateStatus("Downloading ZeroTier " + p + "%"));
|
||||
UpdateStatus("Installing ZeroTier");
|
||||
Process.Start("ZeroTier.msi").WaitForExit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show("Failed to download ZeroTier, please download it from officail website");
|
||||
Process.Start(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateStatus("Completed!");
|
||||
MessageBox.Show("Installation sucessful!");
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateStatus(string status)
|
||||
{
|
||||
Dispatcher.BeginInvoke(new Action(() => Status.Content = status));
|
||||
}
|
||||
|
||||
private Version GetVer(string location)
|
||||
{
|
||||
return Version.Parse(FileVersionInfo.GetVersionInfo(location).FileVersion);
|
||||
}
|
||||
|
||||
private byte[] getLemon()
|
||||
{
|
||||
return (byte[])Resource.ResourceManager.GetObject("LemonUI_SHVDN3");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
36
RageCoop.Client.Installer/RageCoop.Client.Installer.csproj
Normal file
36
RageCoop.Client.Installer/RageCoop.Client.Installer.csproj
Normal file
@ -0,0 +1,36 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="bg.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RageCoop.Client\RageCoop.Client.csproj" />
|
||||
<ProjectReference Include="..\RageCoop.Core\RageCoop.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="bg.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Resource.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resource.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Resource.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -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
RageCoop.Client.Installer/Resource.Designer.cs
generated
Normal file
73
RageCoop.Client.Installer/Resource.Designer.cs
generated
Normal file
@ -0,0 +1,73 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RageCoop.Client.Installer {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resource {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resource() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RageCoop.Client.Installer.Resource", typeof(Resource).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
internal static byte[] LemonUI_SHVDN3 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("LemonUI_SHVDN3", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
124
RageCoop.Client.Installer/Resource.resx
Normal file
124
RageCoop.Client.Installer/Resource.resx
Normal file
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="LemonUI_SHVDN3" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>Resources\LemonUI.SHVDN3.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
</root>
|
BIN
RageCoop.Client.Installer/Resources/LemonUI.SHVDN3.dll
Normal file
BIN
RageCoop.Client.Installer/Resources/LemonUI.SHVDN3.dll
Normal file
Binary file not shown.
BIN
RageCoop.Client.Installer/bg.png
Normal file
BIN
RageCoop.Client.Installer/bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 MiB |
@ -6,12 +6,11 @@ using RageCoop.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -39,7 +38,7 @@ namespace RageCoop.Client
|
||||
internal static ulong Ticked = 0;
|
||||
internal static Vector3 PlayerPosition;
|
||||
internal static Scripting.Resources Resources = null;
|
||||
private static List<Func<bool>> QueuedActions = new List<Func<bool>>();
|
||||
private static readonly List<Func<bool>> QueuedActions = new List<Func<bool>>();
|
||||
public static Worker Worker;
|
||||
|
||||
/// <summary>
|
||||
@ -47,9 +46,6 @@ namespace RageCoop.Client
|
||||
/// </summary>
|
||||
public Main()
|
||||
{
|
||||
#if DEBUG_HIGH_PING
|
||||
Networking.SimulatedLatency=0.3f;
|
||||
#endif
|
||||
Worker = new Worker("RageCoop.Client.Main.Worker", Logger);
|
||||
try
|
||||
{
|
||||
@ -100,7 +96,7 @@ namespace RageCoop.Client
|
||||
KeyDown += OnKeyDown;
|
||||
KeyDown += (s, e) => { Scripting.API.Events.InvokeKeyDown(s, e); };
|
||||
KeyUp += (s, e) => { Scripting.API.Events.InvokeKeyUp(s, e); };
|
||||
Aborted += (object sender, EventArgs e) => CleanUp();
|
||||
Aborted += (object sender, EventArgs e) => Disconnected("Abort");
|
||||
|
||||
Util.NativeMemory();
|
||||
Counter.Restart();
|
||||
@ -111,25 +107,9 @@ namespace RageCoop.Client
|
||||
private bool _lastDead;
|
||||
private void OnTick(object sender, EventArgs e)
|
||||
{
|
||||
/*
|
||||
unsafe
|
||||
{
|
||||
var stationName = Function.Call<string>(Hash.GET_RADIO_STATION_NAME, Game.RadioStation);
|
||||
|
||||
//_GET_CURRENT_RADIO_TRACK_NAME
|
||||
var currentTrack = Function.Call<int>((Hash)0x34D66BC058019CE0, stationName);
|
||||
Function.Call(Hash.SET_RADIO_TRACK, "RADIO_03_HIPHOP_NEW", "ARM1_RADIO_STARTS");
|
||||
return currentTrack;
|
||||
|
||||
var h1 = Function.Call<int>(Hash._GET_CURRENT_RADIO_STATION_HASH);
|
||||
return $"{h1},{h2},{s},{s1}";
|
||||
}
|
||||
*/
|
||||
P = Game.Player.Character;
|
||||
PlayerPosition = P.ReadPosition();
|
||||
FPS = Game.FPS;
|
||||
// World.DrawMarker(MarkerType.DebugSphere, PedExtensions.RaycastEverything(default), default, default, new Vector3(0.2f, 0.2f, 0.2f), Color.AliceBlue);
|
||||
|
||||
if (Game.IsLoading)
|
||||
{
|
||||
return;
|
||||
@ -161,7 +141,9 @@ namespace RageCoop.Client
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Main.Logger.Error(ex);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Networking.ShowNetworkInfo)
|
||||
@ -188,7 +170,7 @@ namespace RageCoop.Client
|
||||
P.Health = 1;
|
||||
Game.Player.WantedLevel = 0;
|
||||
Main.Logger.Debug("Player died.");
|
||||
Scripting.API.Events.InvokePlayerDied();
|
||||
Scripting.API.Events.InvokePlayerDied(KillMessage());
|
||||
}
|
||||
GTA.UI.Screen.StopEffects();
|
||||
}
|
||||
@ -199,7 +181,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
else if (P.IsDead && !_lastDead)
|
||||
{
|
||||
Scripting.API.Events.InvokePlayerDied();
|
||||
Scripting.API.Events.InvokePlayerDied(KillMessage());
|
||||
}
|
||||
|
||||
_lastDead = P.IsDead;
|
||||
@ -273,25 +255,6 @@ namespace RageCoop.Client
|
||||
PlayerList.Pressed = (currentTimestamp - PlayerList.Pressed) < 5000 ? (currentTimestamp - 6000) : currentTimestamp;
|
||||
}
|
||||
}
|
||||
else if (Game.IsControlJustPressed(GTA.Control.VehicleExit))
|
||||
{
|
||||
if (P.IsInVehicle())
|
||||
{
|
||||
P.Task.LeaveVehicle();
|
||||
}
|
||||
else if (P.IsTaskActive(TaskType.CTaskMoveGoToVehicleDoor))
|
||||
{
|
||||
P.Task.ClearAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
var v = World.GetClosestVehicle(P.Position, 10);
|
||||
if (v!=null)
|
||||
{
|
||||
P.Task.EnterVehicle(v, VehicleSeat.Driver, -1, 5, EnterVehicleFlags.AllowJacking);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.KeyCode == Settings.PassengerKey)
|
||||
{
|
||||
var P = Game.Player.Character;
|
||||
@ -309,20 +272,68 @@ namespace RageCoop.Client
|
||||
if (V != null)
|
||||
{
|
||||
var seat = P.GetNearestSeat(V);
|
||||
P.Task.EnterVehicle(V, seat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void CleanUp()
|
||||
var p = V.GetPedOnSeat(seat);
|
||||
if (p != null && !p.IsDead)
|
||||
{
|
||||
MainChat.Clear();
|
||||
Voice.ClearAll();
|
||||
EntityPool.Cleanup();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
internal static void Connected()
|
||||
{
|
||||
Memory.ApplyPatches();
|
||||
if (Settings.Voice && !Voice.WasInitialized())
|
||||
{
|
||||
Voice.Init();
|
||||
}
|
||||
QueueAction(() =>
|
||||
{
|
||||
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)
|
||||
{
|
||||
MainChat.Focused = false;
|
||||
}
|
||||
PlayerList.Cleanup();
|
||||
LocalPlayerID=default;
|
||||
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()
|
||||
{
|
||||
@ -339,7 +350,9 @@ namespace RageCoop.Client
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Logger.Error(ex);
|
||||
#endif
|
||||
QueuedActions.Remove(action);
|
||||
}
|
||||
}
|
||||
@ -380,5 +393,16 @@ namespace RageCoop.Client
|
||||
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,4 +1,5 @@
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using LemonUI;
|
||||
using LemonUI.Menus;
|
||||
using LemonUI.Scaleform;
|
||||
@ -49,7 +50,7 @@ namespace RageCoop.Client.Menus
|
||||
{
|
||||
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
Menu.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
|
||||
|
||||
_usernameItem.Activated += UsernameActivated;
|
||||
_passwordItem.Activated += _passwordActivated;
|
||||
@ -66,17 +67,18 @@ namespace RageCoop.Client.Menus
|
||||
|
||||
Menu.AddSubMenu(SettingsMenu.Menu);
|
||||
Menu.AddSubMenu(DevToolMenu.Menu);
|
||||
#if DEBUG
|
||||
Menu.AddSubMenu(DebugMenu.Menu);
|
||||
Menu.AddSubMenu(UpdateMenu.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(UpdateMenu.Menu);
|
||||
MenuPool.Add(PopUp);
|
||||
|
||||
Menu.Add(_aboutItem);
|
||||
@ -96,6 +98,16 @@ namespace RageCoop.Client.Menus
|
||||
{
|
||||
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;
|
||||
@ -107,6 +119,8 @@ namespace RageCoop.Client.Menus
|
||||
return false;
|
||||
}
|
||||
Script.Yield();
|
||||
Game.DisableAllControlsThisFrame();
|
||||
|
||||
}
|
||||
}
|
||||
public static void UsernameActivated(object a, System.EventArgs b)
|
||||
|
@ -1,7 +1,8 @@
|
||||
using GTA;
|
||||
#if DEBUG
|
||||
using GTA;
|
||||
using LemonUI.Menus;
|
||||
using System.Drawing;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -18,12 +19,13 @@ namespace RageCoop.Client
|
||||
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.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
|
||||
|
||||
|
||||
DiagnosticMenu.Opening += (sender, e) =>
|
||||
@ -44,8 +46,10 @@ namespace RageCoop.Client
|
||||
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);
|
||||
|
||||
}
|
||||
@ -53,3 +57,4 @@ namespace RageCoop.Client
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -12,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");
|
||||
@ -22,7 +22,7 @@ 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;
|
||||
|
@ -1,12 +1,12 @@
|
||||
using LemonUI.Menus;
|
||||
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;
|
||||
using RageCoop.Core;
|
||||
using GTA.UI;
|
||||
|
||||
namespace RageCoop.Client.Menus
|
||||
{
|
||||
@ -30,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) =>
|
||||
{
|
||||
@ -76,7 +76,7 @@ namespace RageCoop.Client.Menus
|
||||
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}]" };
|
||||
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
|
||||
@ -85,7 +85,7 @@ namespace RageCoop.Client.Menus
|
||||
if (server.useZT)
|
||||
{
|
||||
address = $"{server.ztAddress}:{server.port}";
|
||||
Main.QueueAction(() => { Notification.Show($"~y~Joining ZeroTier network... {server.ztID}"); });
|
||||
Notification.Show($"~y~Joining ZeroTier network... {server.ztID}");
|
||||
if (ZeroTierHelper.Join(server.ztID) == null)
|
||||
{
|
||||
throw new Exception("Failed to obtain ZeroTier network IP");
|
||||
|
@ -16,17 +16,20 @@ namespace RageCoop.Client.Menus
|
||||
|
||||
private static readonly NativeCheckboxItem _disableTrafficItem = new NativeCheckboxItem("Disable Traffic (NPCs/Vehicles)", "Local traffic only", Main.Settings.DisableTraffic);
|
||||
private static readonly NativeCheckboxItem _flipMenuItem = new NativeCheckboxItem("Flip menu", Main.Settings.FlipMenu);
|
||||
private static readonly NativeCheckboxItem _disablePauseAlt = new NativeCheckboxItem("Disable Alternate Pause", "Don't freeze game time when Esc pressed", Main.Settings.DisableTraffic);
|
||||
private static readonly NativeCheckboxItem _disablePauseAlt = new NativeCheckboxItem("Disable Alternate Pause", "Don't freeze game time when Esc pressed", Main.Settings.DisableAlternatePause);
|
||||
private static readonly NativeCheckboxItem _showBlip = new NativeCheckboxItem("Show player blip", "Show other player's blip on map", Main.Settings.ShowPlayerBlip);
|
||||
private static readonly NativeCheckboxItem _showNametag = new NativeCheckboxItem("Show player nametag", "Show other player's nametag on your screen", Main.Settings.ShowPlayerNameTag);
|
||||
private static readonly NativeCheckboxItem _disableVoice = new NativeCheckboxItem("Enable voice", "Check your GTA:V settings to find the right key on your keyboard for PushToTalk and talk to your friends", Main.Settings.Voice);
|
||||
|
||||
private static NativeItem _menuKey = new NativeItem("Menu Key", "The key to open menu", Main.Settings.MenuKey.ToString());
|
||||
private static NativeItem _passengerKey = new NativeItem("Passenger Key", "The key to enter a vehicle as passenger", Main.Settings.PassengerKey.ToString());
|
||||
private static NativeItem _vehicleSoftLimit = new NativeItem("Vehicle limit (soft)", "The game won't spawn more NPC traffic if the limit is exceeded. \n-1 for unlimited (not recommended).", Main.Settings.WorldVehicleSoftLimit.ToString());
|
||||
private static readonly NativeItem _menuKey = new NativeItem("Menu Key", "The key to open menu", Main.Settings.MenuKey.ToString());
|
||||
private static readonly NativeItem _passengerKey = new NativeItem("Passenger Key", "The key to enter a vehicle as passenger", Main.Settings.PassengerKey.ToString());
|
||||
private static readonly NativeItem _vehicleSoftLimit = new NativeItem("Vehicle limit (soft)", "The game won't spawn more NPC traffic if the limit is exceeded. \n-1 for unlimited (not recommended).", Main.Settings.WorldVehicleSoftLimit.ToString());
|
||||
private static readonly NativeItem _pedSoftLimit = new NativeItem("Ped limit (soft)", "The game won't spawn more NPCs if the limit is exceeded. \n-1 for unlimited (not recommended).", Main.Settings.WorldPedSoftLimit.ToString());
|
||||
|
||||
static SettingsMenu()
|
||||
{
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
Menu.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
|
||||
|
||||
_disableTrafficItem.CheckboxChanged += DisableTrafficCheckboxChanged;
|
||||
_disablePauseAlt.CheckboxChanged += DisablePauseAltCheckboxChanged;
|
||||
@ -35,6 +38,17 @@ namespace RageCoop.Client.Menus
|
||||
_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);
|
||||
@ -43,6 +57,9 @@ namespace RageCoop.Client.Menus
|
||||
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)
|
||||
@ -53,7 +70,9 @@ namespace RageCoop.Client.Menus
|
||||
{
|
||||
Voice.Init();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Voice.ClearAll();
|
||||
}
|
||||
|
||||
@ -73,7 +92,19 @@ namespace RageCoop.Client.Menus
|
||||
Main.Settings.WorldVehicleSoftLimit = int.Parse(
|
||||
Game.GetUserInput(WindowTitle.EnterMessage20,
|
||||
Main.Settings.WorldVehicleSoftLimit.ToString(), 20));
|
||||
_menuKey.AltTitle=Main.Settings.WorldVehicleSoftLimit.ToString();
|
||||
_vehicleSoftLimit.AltTitle = Main.Settings.WorldVehicleSoftLimit.ToString();
|
||||
Util.SaveSettings();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
private static void PedSoftLimitActivated(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.Settings.WorldPedSoftLimit = int.Parse(
|
||||
Game.GetUserInput(WindowTitle.EnterMessage20,
|
||||
Main.Settings.WorldPedSoftLimit.ToString(), 20));
|
||||
_pedSoftLimit.AltTitle = Main.Settings.WorldPedSoftLimit.ToString();
|
||||
Util.SaveSettings();
|
||||
}
|
||||
catch { }
|
||||
@ -108,6 +139,7 @@ namespace RageCoop.Client.Menus
|
||||
|
||||
public static void DisableTrafficCheckboxChanged(object a, System.EventArgs b)
|
||||
{
|
||||
WorldThread.Traffic(!_disableTrafficItem.Checked);
|
||||
Main.Settings.DisableTraffic = _disableTrafficItem.Checked;
|
||||
Util.SaveSettings();
|
||||
}
|
||||
|
@ -1,103 +0,0 @@
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using LemonUI.Menus;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RageCoop.Client.Menus
|
||||
{
|
||||
internal class UpdateMenu
|
||||
{
|
||||
public static bool IsUpdating { get; private set; } = false;
|
||||
private static NativeItem _updatingItem = new NativeItem("Updating...");
|
||||
private static NativeItem _downloadItem = new NativeItem("Download", "Download and update to latest nightly");
|
||||
|
||||
private static string _downloadPath = Path.Combine(Main.Settings.DataDirectory, "RageCoop.Client.zip");
|
||||
public static NativeMenu Menu = new NativeMenu("Update", "Update", "Download and install latest nightly build from GitHub")
|
||||
{
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
static UpdateMenu()
|
||||
{
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
Menu.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
Menu.Opening+=Opening;
|
||||
_downloadItem.Activated+=StartUpdate;
|
||||
}
|
||||
|
||||
private static void StartUpdate(object sender, EventArgs e)
|
||||
{
|
||||
IsUpdating=true;
|
||||
Menu.Clear();
|
||||
Menu.Add(_updatingItem);
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(_downloadPath)) { File.Delete(_downloadPath); }
|
||||
WebClient client = new WebClient();
|
||||
|
||||
// TLS only
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
|
||||
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||
|
||||
client.DownloadProgressChanged += (s, e1) => { Main.QueueAction(() => { _updatingItem.AltTitle=$"{e1.ProgressPercentage}%"; }); };
|
||||
client.DownloadFileCompleted +=(s, e2) => { Install(); };
|
||||
client.DownloadFileAsync(new Uri("https://github.com/RAGECOOP/RAGECOOP-V/releases/download/nightly/RageCoop.Client.zip"), _downloadPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.Logger.Error(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void Install()
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
_updatingItem.AltTitle="Installing...";
|
||||
});
|
||||
Directory.CreateDirectory(@"Scripts\RageCoop");
|
||||
foreach(var f in Directory.GetFiles(@"Scripts\RageCoop", "*.dll", SearchOption.AllDirectories))
|
||||
{
|
||||
try { File.Delete(f); }
|
||||
catch { }
|
||||
}
|
||||
new FastZip().ExtractZip(_downloadPath, "Scripts", FastZip.Overwrite.Always, null, null, null, true);
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
Util.Reload();
|
||||
IsUpdating=false;
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.Logger.Error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Opening(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
Menu.Clear();
|
||||
if (Networking.IsOnServer)
|
||||
{
|
||||
Menu.Add(new NativeItem("Disconnect from the server first"));
|
||||
}
|
||||
else if (IsUpdating)
|
||||
{
|
||||
Menu.Add(_updatingItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu.Add(_downloadItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ namespace RageCoop.Client
|
||||
private bool CurrentFocused { get; set; }
|
||||
public bool Focused
|
||||
{
|
||||
get { return CurrentFocused; }
|
||||
get => CurrentFocused;
|
||||
set
|
||||
{
|
||||
if (value && Hidden)
|
||||
@ -35,7 +35,7 @@ namespace RageCoop.Client
|
||||
private bool CurrentHidden { get; set; }
|
||||
private bool Hidden
|
||||
{
|
||||
get { return CurrentHidden; }
|
||||
get => CurrentHidden;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
|
@ -122,8 +122,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
lock (InProgressDownloads)
|
||||
{
|
||||
DownloadFile file;
|
||||
if (InProgressDownloads.TryGetValue(id, out file))
|
||||
if (InProgressDownloads.TryGetValue(id, out DownloadFile file))
|
||||
{
|
||||
|
||||
file.Stream.Write(chunk, 0, chunk.Length);
|
||||
@ -137,9 +136,8 @@ namespace RageCoop.Client
|
||||
|
||||
public static void Complete(int id)
|
||||
{
|
||||
DownloadFile f;
|
||||
|
||||
if (InProgressDownloads.TryGetValue(id, out f))
|
||||
if (InProgressDownloads.TryGetValue(id, out DownloadFile f))
|
||||
{
|
||||
InProgressDownloads.Remove(id);
|
||||
f.Dispose();
|
||||
|
@ -1,12 +1,10 @@
|
||||
using System;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using RageCoop.Core;
|
||||
using Lidgren.Network;
|
||||
using System.Net;
|
||||
using System.Timers;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -29,7 +27,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
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.PedID}");
|
||||
Main.Logger.Trace($"Sending HolePunch message to {p.InternalEndPoint},{p.ExternalEndPoint}. {p.Username}:{p.ID}");
|
||||
var msg = Networking.Peer.CreateMessage();
|
||||
new Packets.HolePunch
|
||||
{
|
||||
@ -69,7 +67,7 @@ namespace RageCoop.Client
|
||||
puncher.HolePunchStatus = (byte)(p.Status + 1);
|
||||
if (p.Status >= 3)
|
||||
{
|
||||
Main.Logger.Debug("HolePunch sucess: "+from+", "+puncher.PedID);
|
||||
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);
|
||||
|
@ -1,12 +1,12 @@
|
||||
using Lidgren.Network;
|
||||
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;
|
||||
using GTA.UI;
|
||||
using System.Net;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -17,8 +17,8 @@ namespace RageCoop.Client
|
||||
public static bool ShowNetworkInfo = false;
|
||||
public static Security Security;
|
||||
public static NetConnection ServerConnection;
|
||||
private static readonly Dictionary<int, Action<PacketType, byte[]>> PendingResponses = new Dictionary<int, Action<PacketType, byte[]>>();
|
||||
internal static readonly Dictionary<PacketType, Func<byte[], Packet>> RequestHandlers = new Dictionary<PacketType, Func<byte[], Packet>>();
|
||||
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;
|
||||
@ -30,15 +30,16 @@ namespace RageCoop.Client
|
||||
public static void ToggleConnection(string address, string username = null, string password = null, PublicKey publicKey = null)
|
||||
{
|
||||
Menus.CoopMenu.Menu.Visible = false;
|
||||
Peer?.Shutdown("Bye");
|
||||
if (IsOnServer)
|
||||
if (IsConnecting)
|
||||
{
|
||||
// ?
|
||||
}
|
||||
else if (IsConnecting) {
|
||||
_publicKeyReceived.Set();
|
||||
IsConnecting = false;
|
||||
Notification.Show("Connection has been canceled");
|
||||
Main.QueueAction(() => Notification.Show("Connection has been canceled"));
|
||||
Peer?.Shutdown("Bye");
|
||||
}
|
||||
else if (IsOnServer)
|
||||
{
|
||||
Peer?.Shutdown("Bye");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -52,13 +53,14 @@ namespace RageCoop.Client
|
||||
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
|
||||
{
|
||||
AutoFlushSendQueue = false,
|
||||
SimulatedMinimumLatency =SimulatedLatency,
|
||||
SimulatedRandomLatency=0,
|
||||
AcceptIncomingConnections = true,
|
||||
MaximumConnections = 32,
|
||||
PingInterval = 5
|
||||
};
|
||||
|
||||
#if DEBUG
|
||||
config.SimulatedMinimumLatency = SimulatedLatency;
|
||||
config.SimulatedRandomLatency = 0;
|
||||
#endif
|
||||
config.EnableMessageType(NetIncomingMessageType.UnconnectedData);
|
||||
config.EnableMessageType(NetIncomingMessageType.NatIntroductionSuccess);
|
||||
|
||||
@ -88,24 +90,33 @@ namespace RageCoop.Client
|
||||
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) { Main.Logger.Error(ex); }
|
||||
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 (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{
|
||||
else
|
||||
{
|
||||
Security.SetServerPublicKey(publicKey.Modulus, publicKey.Exponent);
|
||||
}
|
||||
|
||||
@ -141,7 +152,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
var p = new Player
|
||||
{
|
||||
PedID = packet.PedID,
|
||||
ID = packet.PedID,
|
||||
Username = packet.Username,
|
||||
};
|
||||
PlayerList.SetPlayer(packet.PedID, packet.Username);
|
||||
@ -155,7 +166,8 @@ namespace RageCoop.Client
|
||||
var player = PlayerList.GetPlayer(packet.PedID);
|
||||
if (player == null) { return; }
|
||||
PlayerList.RemovePlayer(packet.PedID);
|
||||
Main.QueueAction(() => {
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
EntityPool.RemoveAllFromPlayer(packet.PedID);
|
||||
GTA.UI.Notification.Show($"~h~{player.Username}~h~ left.");
|
||||
});
|
||||
|
@ -3,7 +3,7 @@ using Lidgren.Network;
|
||||
using RageCoop.Client.Menus;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Client
|
||||
@ -14,7 +14,7 @@ namespace RageCoop.Client
|
||||
/// <summary>
|
||||
/// Reduce GC pressure by reusing frequently used packets
|
||||
/// </summary>
|
||||
static class ReceivedPackets
|
||||
private static class ReceivedPackets
|
||||
{
|
||||
public static Packets.PedSync PedPacket = new Packets.PedSync();
|
||||
public static Packets.VehicleSync VehicelPacket = new Packets.VehicleSync();
|
||||
@ -24,7 +24,7 @@ namespace RageCoop.Client
|
||||
/// <summary>
|
||||
/// Used to reslove entity handle in a <see cref="Packets.CustomEvent"/>
|
||||
/// </summary>
|
||||
private static readonly Func<byte, BitReader, object> _resolveHandle = (t, reader) =>
|
||||
private static readonly Func<byte, NetIncomingMessage, object> _resolveHandle = (t, reader) =>
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
@ -41,10 +41,11 @@ namespace RageCoop.Client
|
||||
}
|
||||
};
|
||||
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:
|
||||
@ -61,30 +62,18 @@ namespace RageCoop.Client
|
||||
case NetConnectionStatus.Connected:
|
||||
if (message.SenderConnection == ServerConnection)
|
||||
{
|
||||
Memory.ApplyPatches();
|
||||
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.ReadBytes(response.ReadInt32()));
|
||||
p.Deserialize(response);
|
||||
foreach (var player in p.Players)
|
||||
{
|
||||
PlayerList.SetPlayer(player.ID, player.Username);
|
||||
}
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
CoopMenu.ConnectedMenuSetting();
|
||||
Main.MainChat.Init();
|
||||
if (Main.Settings.Voice && !Voice.WasInitialized())
|
||||
{
|
||||
Voice.Init();
|
||||
}
|
||||
GTA.UI.Notification.Show("~g~Connected!");
|
||||
});
|
||||
|
||||
Main.Logger.Info(">> Connected <<");
|
||||
Main.Connected();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -107,19 +96,7 @@ namespace RageCoop.Client
|
||||
case NetConnectionStatus.Disconnected:
|
||||
if (message.SenderConnection == ServerConnection)
|
||||
{
|
||||
Memory.RestorePatches();
|
||||
DownloadManager.Cleanup();
|
||||
|
||||
if (Main.MainChat.Focused)
|
||||
{
|
||||
Main.MainChat.Focused = false;
|
||||
}
|
||||
|
||||
Main.QueueAction(() => Main.CleanUp());
|
||||
CoopMenu.DisconnectedMenuSetting();
|
||||
Main.Logger.Info($">> Disconnected << reason: {reason}");
|
||||
Main.QueueAction(() => GTA.UI.Notification.Show("~r~Disconnected: " + reason));
|
||||
Main.Resources.Unload();
|
||||
Main.Disconnected(reason);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -139,7 +116,7 @@ namespace RageCoop.Client
|
||||
int id = message.ReadInt32();
|
||||
if (PendingResponses.TryGetValue(id, out var callback))
|
||||
{
|
||||
callback((PacketType)message.ReadByte(), message.ReadBytes(message.ReadInt32()));
|
||||
callback((PacketType)message.ReadByte(), message);
|
||||
PendingResponses.Remove(id);
|
||||
}
|
||||
break;
|
||||
@ -148,57 +125,60 @@ namespace RageCoop.Client
|
||||
{
|
||||
int id = message.ReadInt32();
|
||||
var realType = (PacketType)message.ReadByte();
|
||||
int len = message.ReadInt32();
|
||||
if (RequestHandlers.TryGetValue(realType, out var handler))
|
||||
{
|
||||
var response = Peer.CreateMessage();
|
||||
response.Write((byte)PacketType.Response);
|
||||
response.Write(id);
|
||||
handler(message.ReadBytes(len)).Pack(response);
|
||||
handler(message).Pack(response);
|
||||
Peer.SendMessage(response, ServerConnection, NetDeliveryMethod.ReliableOrdered, message.SequenceChannel);
|
||||
Peer.FlushSendQueue();
|
||||
}
|
||||
else
|
||||
{
|
||||
Main.Logger.Debug("Did not find a request handler of type: " + realType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
byte[] data = message.ReadBytes(message.ReadInt32());
|
||||
|
||||
HandlePacket(packetType, data,message.SenderConnection);
|
||||
HandlePacket(packetType, message, message.SenderConnection, ref _recycle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
GTA.UI.Notification.Show("~r~~h~Packet Error");
|
||||
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();
|
||||
int len = message.ReadInt32();
|
||||
byte[] data = message.ReadBytes(len);
|
||||
switch (packetType)
|
||||
{
|
||||
|
||||
case PacketType.HolePunch:
|
||||
{
|
||||
HolePunch.Punched(data.GetPacket<Packets.HolePunch>(), message.SenderEndPoint);
|
||||
HolePunch.Punched(message.GetPacket<Packets.HolePunch>(), message.SenderEndPoint);
|
||||
break;
|
||||
}
|
||||
case PacketType.PublicKeyResponse:
|
||||
{
|
||||
if (message.SenderEndPoint.ToString() != _targetServerEP.ToString() || !IsConnecting) { break; }
|
||||
var packet = data.GetPacket<Packets.PublicKeyResponse>();
|
||||
var packet = message.GetPacket<Packets.PublicKeyResponse>();
|
||||
Security.SetServerPublicKey(packet.Modulus, packet.Exponent);
|
||||
_publicKeyReceived.Set();
|
||||
break;
|
||||
@ -215,41 +195,42 @@ namespace RageCoop.Client
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (_recycle)
|
||||
{
|
||||
Peer.Recycle(message);
|
||||
}
|
||||
private static void HandlePacket(PacketType packetType, byte[] data, NetConnection senderConnection)
|
||||
}
|
||||
private static void HandlePacket(PacketType packetType, NetIncomingMessage msg, NetConnection senderConnection, ref bool recycle)
|
||||
{
|
||||
|
||||
switch (packetType)
|
||||
{
|
||||
case PacketType.HolePunchInit:
|
||||
HolePunch.Add(data.GetPacket<Packets.HolePunchInit>());
|
||||
HolePunch.Add(msg.GetPacket<Packets.HolePunchInit>());
|
||||
break;
|
||||
|
||||
case PacketType.PlayerConnect:
|
||||
PlayerConnect(data.GetPacket<Packets.PlayerConnect>());
|
||||
PlayerConnect(msg.GetPacket<Packets.PlayerConnect>());
|
||||
break;
|
||||
|
||||
case PacketType.PlayerDisconnect:
|
||||
PlayerDisconnect(data.GetPacket<Packets.PlayerDisconnect>());
|
||||
PlayerDisconnect(msg.GetPacket<Packets.PlayerDisconnect>());
|
||||
break;
|
||||
|
||||
case PacketType.PlayerInfoUpdate:
|
||||
PlayerList.UpdatePlayer(data.GetPacket<Packets.PlayerInfoUpdate>());
|
||||
PlayerList.UpdatePlayer(msg.GetPacket<Packets.PlayerInfoUpdate>());
|
||||
break;
|
||||
|
||||
case PacketType.VehicleSync:
|
||||
ReceivedPackets.VehicelPacket.Deserialize(data);
|
||||
ReceivedPackets.VehicelPacket.Deserialize(msg);
|
||||
VehicleSync(ReceivedPackets.VehicelPacket);
|
||||
break;
|
||||
|
||||
case PacketType.PedSync:
|
||||
ReceivedPackets.PedPacket.Deserialize(data);
|
||||
ReceivedPackets.PedPacket.Deserialize(msg);
|
||||
PedSync(ReceivedPackets.PedPacket);
|
||||
break;
|
||||
case PacketType.ProjectileSync:
|
||||
ReceivedPackets.ProjectilePacket.Deserialize(data);
|
||||
ReceivedPackets.ProjectilePacket.Deserialize(msg);
|
||||
ProjectileSync(ReceivedPackets.ProjectilePacket);
|
||||
break;
|
||||
|
||||
@ -257,7 +238,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
|
||||
Packets.ChatMessage packet = new Packets.ChatMessage((b) => Security.Decrypt(b));
|
||||
packet.Deserialize(data);
|
||||
packet.Deserialize(msg);
|
||||
|
||||
Main.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message); return true; });
|
||||
}
|
||||
@ -268,7 +249,7 @@ namespace RageCoop.Client
|
||||
if (Main.Settings.Voice)
|
||||
{
|
||||
Packets.Voice packet = new Packets.Voice();
|
||||
packet.Deserialize(data);
|
||||
packet.Deserialize(msg);
|
||||
|
||||
|
||||
SyncedPed player = EntityPool.GetPedByID(packet.ID);
|
||||
@ -283,18 +264,20 @@ namespace RageCoop.Client
|
||||
case PacketType.CustomEvent:
|
||||
{
|
||||
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
||||
packet.Deserialize(data);
|
||||
packet.Deserialize(msg);
|
||||
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
||||
}
|
||||
break;
|
||||
|
||||
case PacketType.CustomEventQueued:
|
||||
{
|
||||
recycle = false;
|
||||
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
packet.Deserialize(data);
|
||||
packet.Deserialize(msg);
|
||||
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
||||
Peer.Recycle(msg);
|
||||
});
|
||||
}
|
||||
break;
|
||||
@ -302,7 +285,7 @@ namespace RageCoop.Client
|
||||
case PacketType.FileTransferChunk:
|
||||
{
|
||||
Packets.FileTransferChunk packet = new Packets.FileTransferChunk();
|
||||
packet.Deserialize(data);
|
||||
packet.Deserialize(msg);
|
||||
DownloadManager.Write(packet.ID, packet.FileChunk);
|
||||
}
|
||||
break;
|
||||
@ -310,8 +293,9 @@ namespace RageCoop.Client
|
||||
default:
|
||||
if (packetType.IsSyncEvent())
|
||||
{
|
||||
recycle = false;
|
||||
// Dispatch to script thread
|
||||
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, data); return true; });
|
||||
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, msg); return true; });
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -321,11 +305,15 @@ namespace RageCoop.Client
|
||||
{
|
||||
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));
|
||||
}
|
||||
PedDataFlags flags = packet.Flags;
|
||||
else return;
|
||||
}
|
||||
c.ID = packet.ID;
|
||||
c.OwnerID = packet.OwnerID;
|
||||
c.Health = packet.Health;
|
||||
@ -335,6 +323,7 @@ namespace RageCoop.Client
|
||||
c.Flags = packet.Flags;
|
||||
c.Heading = packet.Heading;
|
||||
c.Position = packet.Position;
|
||||
c.LastSyncedStopWatch.Restart();
|
||||
if (c.IsRagdoll)
|
||||
{
|
||||
c.HeadPosition = packet.HeadPosition;
|
||||
@ -370,8 +359,14 @@ namespace RageCoop.Client
|
||||
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;
|
||||
@ -404,7 +399,6 @@ namespace RageCoop.Client
|
||||
}
|
||||
private static void ProjectileSync(Packets.ProjectileSync packet)
|
||||
{
|
||||
|
||||
var p = EntityPool.GetProjectileByID(packet.ID);
|
||||
if (p == null)
|
||||
{
|
||||
@ -420,6 +414,7 @@ namespace RageCoop.Client
|
||||
p.Shooter = packet.Flags.HasProjDataFlag(ProjectileDataFlags.IsShotByVehicle) ?
|
||||
(SyncedEntity)EntityPool.GetVehicleByID(packet.ShooterID) : EntityPool.GetPedByID(packet.ShooterID);
|
||||
p.LastSynced = Main.Ticked;
|
||||
p.LastSyncedStopWatch.Restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace RageCoop.Client
|
||||
/// <summary>
|
||||
/// Reduce GC pressure by reusing frequently used packets
|
||||
/// </summary>
|
||||
static class SendPackets
|
||||
private static class SendPackets
|
||||
{
|
||||
public static Packets.PedSync PedPacket = new Packets.PedSync();
|
||||
public static Packets.VehicleSync VehicelPacket = new Packets.VehicleSync();
|
||||
|
@ -1,11 +1,11 @@
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using System.Collections.Generic;
|
||||
using Lidgren.Network;
|
||||
using System.Net;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -54,7 +54,7 @@ namespace RageCoop.Client
|
||||
|
||||
foreach (var player in Players.Values)
|
||||
{
|
||||
_mainScaleform.CallFunction("SET_DATA_SLOT", i++, $"{player.Ping * 1000:N0}ms", player.Username, 116, 0, i - 1, "", "", 2, "", "", ' ');
|
||||
_mainScaleform.CallFunction("SET_DATA_SLOT", i++, $"{player.Ping * 1000:N0}ms", player.Username + (player.IsHost ? " (Host)" : ""), 116, 0, i - 1, "", "", 2, "", "", ' ');
|
||||
}
|
||||
|
||||
_mainScaleform.CallFunction("SET_TITLE", "Player list", $"{Players.Count} players");
|
||||
@ -63,16 +63,15 @@ namespace RageCoop.Client
|
||||
public static void SetPlayer(int id, string username, float latency = 0)
|
||||
{
|
||||
Main.Logger.Debug($"{id},{username},{latency}");
|
||||
Player p;
|
||||
if (Players.TryGetValue(id, out p))
|
||||
if (Players.TryGetValue(id, out Player p))
|
||||
{
|
||||
p.Username = username;
|
||||
p.PedID=id;
|
||||
p.ID = id;
|
||||
p._latencyToServer = latency;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = new Player { PedID=id, Username=username, _latencyToServer=latency };
|
||||
p = new Player { ID = id, Username = username, _latencyToServer = latency };
|
||||
Players.Add(id, p);
|
||||
}
|
||||
}
|
||||
@ -83,14 +82,18 @@ namespace RageCoop.Client
|
||||
{
|
||||
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 (p.Position.DistanceTo(Main.PlayerPosition)>500)
|
||||
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;
|
||||
@ -98,18 +101,13 @@ namespace RageCoop.Client
|
||||
p.FakeBlip.DisplayType = BlipDisplayType.Default;
|
||||
p.FakeBlip.Position = p.Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
p.FakeBlip.DisplayType=BlipDisplayType.NoDisplay;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
public static Player GetPlayer(int id)
|
||||
{
|
||||
Player p;
|
||||
Players.TryGetValue(id, out p);
|
||||
Players.TryGetValue(id, out Player p);
|
||||
return p;
|
||||
}
|
||||
public static Player GetPlayer(SyncedPed p)
|
||||
@ -139,31 +137,32 @@ namespace RageCoop.Client
|
||||
}
|
||||
}
|
||||
|
||||
internal class Player
|
||||
public class Player
|
||||
{
|
||||
public byte HolePunchStatus { get; set; } = 1;
|
||||
public byte HolePunchStatus { get; internal set; } = 1;
|
||||
public bool IsHost { get; internal set; }
|
||||
public string Username { get; internal set; }
|
||||
/// <summary>
|
||||
/// Universal character ID.
|
||||
/// Universal ped ID.
|
||||
/// </summary>
|
||||
public int PedID
|
||||
public int ID
|
||||
{
|
||||
get; internal set;
|
||||
}
|
||||
public IPEndPoint InternalEndPoint { get; set; }
|
||||
public IPEndPoint ExternalEndPoint { get; set; }
|
||||
public bool ConnectWhenPunched { get; set; }
|
||||
public Blip FakeBlip { get; set; }
|
||||
public Vector3 Position { get; set; }
|
||||
public SyncedPed Character { get; set; }
|
||||
public IPEndPoint InternalEndPoint { get; internal set; }
|
||||
public IPEndPoint ExternalEndPoint { get; internal set; }
|
||||
internal bool ConnectWhenPunched { get; set; }
|
||||
public Blip FakeBlip { get; internal set; }
|
||||
public Vector3 Position { get; internal set; }
|
||||
public SyncedPed Character { get; internal set; }
|
||||
/// <summary>
|
||||
/// Player round-trip time in seconds, will be the latency to server if not using P2P connection.
|
||||
/// Player round-trip time in seconds, will be the rtt to server if not using P2P connection.
|
||||
/// </summary>
|
||||
public float Ping => Main.LocalPlayerID==PedID ? Networking.Latency*2 : (HasDirectConnection ? Connection.AverageRoundtripTime : _latencyToServer*2);
|
||||
public float Ping => Main.LocalPlayerID == ID ? Networking.Latency * 2 : (HasDirectConnection ? Connection.AverageRoundtripTime : _latencyToServer * 2);
|
||||
public float PacketTravelTime => HasDirectConnection ? Connection.AverageRoundtripTime / 2 : Networking.Latency + _latencyToServer;
|
||||
public float _latencyToServer = 0;
|
||||
internal float _latencyToServer = 0;
|
||||
public bool DisplayNameTag { get; set; } = true;
|
||||
public NetConnection Connection { get; set; }
|
||||
public NetConnection Connection { get; internal set; }
|
||||
public bool HasDirectConnection => Connection?.Status == NetConnectionStatus.Connected;
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,8 @@ using System.Resources;
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
|
||||
// Version informationr(
|
||||
[assembly: AssemblyVersion("1.5.1.13")]
|
||||
[assembly: AssemblyFileVersion("1.5.1.13")]
|
||||
// Version information
|
||||
[assembly: AssemblyVersion("1.5.4.7")]
|
||||
[assembly: AssemblyFileVersion("1.5.4.7")]
|
||||
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
<OutPutPath>..\bin\Debug\Client</OutPutPath>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DefineConstants>DEBUG</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
<OutPutPath>..\bin\Release\Client</OutPutPath>
|
||||
@ -35,7 +36,6 @@
|
||||
<Compile Include="Menus\Sub\DevToolMenu.cs" />
|
||||
<Compile Include="Menus\Sub\ServersMenu.cs" />
|
||||
<Compile Include="Menus\Sub\SettingsMenu.cs" />
|
||||
<Compile Include="Menus\Sub\UpdateMenu.cs" />
|
||||
<Compile Include="Networking\Chat.cs" />
|
||||
<Compile Include="Networking\DownloadManager.cs" />
|
||||
<Compile Include="Networking\HolePunch.cs" />
|
||||
@ -55,16 +55,18 @@
|
||||
<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\SyncedVehicle.cs" />
|
||||
<Compile Include="Sync\Entities\SyncedVehicle.Members.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" />
|
||||
@ -88,7 +90,7 @@
|
||||
<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.7.0.0, Culture=neutral, processorArchitecture=AMD64">
|
||||
<Reference Include="LemonUI.SHVDN3, Version=1.10.0.0, Culture=neutral, processorArchitecture=AMD64">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\libs\LemonUI.SHVDN3.dll</HintPath>
|
||||
</Reference>
|
||||
|
@ -1,5 +1,6 @@
|
||||
#undef DEBUG
|
||||
using GTA;
|
||||
using Newtonsoft.Json;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -39,7 +40,7 @@ namespace RageCoop.Client.Scripting
|
||||
/// </summary>
|
||||
public static string Username
|
||||
{
|
||||
get { return Main.Settings.Username; }
|
||||
get => Main.Settings.Username;
|
||||
set
|
||||
{
|
||||
if (Networking.IsOnServer || string.IsNullOrEmpty(value))
|
||||
@ -90,7 +91,7 @@ namespace RageCoop.Client.Scripting
|
||||
/// <summary>
|
||||
/// The local player is dead
|
||||
/// </summary>
|
||||
public static event EmptyEvent OnPlayerDied;
|
||||
public static event EventHandler<string> OnPlayerDied;
|
||||
|
||||
/// <summary>
|
||||
/// A local vehicle is spawned
|
||||
@ -132,7 +133,7 @@ namespace RageCoop.Client.Scripting
|
||||
internal static void InvokeVehicleDeleted(SyncedVehicle v) { OnVehicleDeleted?.Invoke(null, v); }
|
||||
internal static void InvokePedSpawned(SyncedPed p) { OnPedSpawned?.Invoke(null, p); }
|
||||
internal static void InvokePedDeleted(SyncedPed p) { OnPedDeleted?.Invoke(null, p); }
|
||||
internal static void InvokePlayerDied() { OnPlayerDied?.Invoke(); }
|
||||
internal static void InvokePlayerDied(string m) { OnPlayerDied?.Invoke(null, m); }
|
||||
internal static void InvokeTick() { OnTick?.Invoke(); }
|
||||
|
||||
internal static void InvokeKeyDown(object s, KeyEventArgs e) { OnKeyDown?.Invoke(s, e); }
|
||||
@ -145,8 +146,7 @@ namespace RageCoop.Client.Scripting
|
||||
|
||||
// Main.Logger.Debug($"CustomEvent:\n"+args.Args.DumpWithType());
|
||||
|
||||
List<Action<CustomEventReceivedArgs>> handlers;
|
||||
if (CustomEventHandlers.TryGetValue(p.Hash, out handlers))
|
||||
if (CustomEventHandlers.TryGetValue(p.Hash, out List<Action<CustomEventReceivedArgs>> handlers))
|
||||
{
|
||||
handlers.ForEach((x) => { x.Invoke(args); });
|
||||
}
|
||||
@ -160,65 +160,48 @@ namespace RageCoop.Client.Scripting
|
||||
/// Get the local player's ID
|
||||
/// </summary>
|
||||
/// <returns>PlayerID</returns>
|
||||
public static int LocalPlayerID
|
||||
{
|
||||
get { return Main.LocalPlayerID; }
|
||||
}
|
||||
public static int LocalPlayerID => Main.LocalPlayerID;
|
||||
|
||||
/// <summary>
|
||||
/// Check if player is connected to a server
|
||||
/// </summary>
|
||||
public static bool IsOnServer { get { return Networking.IsOnServer; } }
|
||||
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 { get { return Networking.IsOnServer ? Networking.ServerConnection?.RemoteEndPoint : null; } }
|
||||
public static System.Net.IPEndPoint ServerEndPoint => Networking.IsOnServer ? Networking.ServerConnection?.RemoteEndPoint : null;
|
||||
|
||||
/// <summary>
|
||||
/// Check if a RAGECOOP menu is visible
|
||||
/// </summary>
|
||||
public static bool IsMenuVisible
|
||||
{
|
||||
get { return Menus.CoopMenu.MenuPool.AreAnyVisible; }
|
||||
}
|
||||
public static bool IsMenuVisible => Menus.CoopMenu.MenuPool.AreAnyVisible;
|
||||
|
||||
/// <summary>
|
||||
/// Check if the RAGECOOP chat is visible
|
||||
/// </summary>
|
||||
public static bool IsChatFocused
|
||||
{
|
||||
get { return Main.MainChat.Focused; }
|
||||
}
|
||||
public static bool IsChatFocused => Main.MainChat.Focused;
|
||||
|
||||
/// <summary>
|
||||
/// Check if the RAGECOOP list of players is visible
|
||||
/// </summary>
|
||||
public static bool IsPlayerListVisible
|
||||
{
|
||||
get { return Util.GetTickCount64() - PlayerList.Pressed < 5000; }
|
||||
}
|
||||
public static bool IsPlayerListVisible => Util.GetTickCount64() - PlayerList.Pressed < 5000;
|
||||
|
||||
/// <summary>
|
||||
/// Get the version of RAGECOOP
|
||||
/// </summary>
|
||||
public static Version CurrentVersion
|
||||
{
|
||||
get { return Main.Version; }
|
||||
}
|
||||
|
||||
public static Version CurrentVersion => Main.Version;
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="Core.Logger"/> that RAGECOOP is currently using.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Logger Logger
|
||||
{
|
||||
get
|
||||
{
|
||||
return Main.Logger;
|
||||
}
|
||||
}
|
||||
public static Logger Logger => Main.Logger;
|
||||
/// <summary>
|
||||
/// Get all players indexed by their ID
|
||||
/// </summary>
|
||||
public static Dictionary<int, Player> Players => new Dictionary<int, Player>(PlayerList.Players);
|
||||
|
||||
#endregion
|
||||
|
||||
#region FUNCTIONS
|
||||
@ -245,6 +228,16 @@ namespace RageCoop.Client.Scripting
|
||||
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>
|
||||
@ -255,6 +248,15 @@ namespace RageCoop.Client.Scripting
|
||||
Main.MainChat.AddMessage(from, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a chat message or command to server/other players
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public static void SendChatMessage(string message)
|
||||
{
|
||||
Networking.SendChatMessage(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue an action to be executed on next tick.
|
||||
/// </summary>
|
||||
|
@ -16,7 +16,7 @@ namespace RageCoop.Client.Scripting
|
||||
{
|
||||
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+=() => { API.SendCustomEvent(CustomEvents.OnPlayerDied); };
|
||||
API.Events.OnPlayerDied += (s, m) => { API.SendCustomEvent(CustomEvents.OnPlayerDied, m); };
|
||||
|
||||
API.RegisterCustomEventHandler(CustomEvents.SetAutoRespawn, SetAutoRespawn);
|
||||
API.RegisterCustomEventHandler(CustomEvents.SetDisplayNameTag, SetDisplayNameTag);
|
||||
@ -31,7 +31,7 @@ namespace RageCoop.Client.Scripting
|
||||
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($"~h~{e.Args[0]}~h~ died."); });
|
||||
API.RegisterCustomEventHandler(CustomEvents.OnPlayerDied, (e) => { GTA.UI.Notification.Show((string)e.Args[0]); });
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (true)
|
||||
@ -46,7 +46,7 @@ namespace RageCoop.Client.Scripting
|
||||
int weather1 = default(int);
|
||||
int weather2 = default(int);
|
||||
float percent2 = default(float);
|
||||
Function.Call(Hash._GET_WEATHER_TYPE_TRANSITION, &weather1, &weather2, &percent2);
|
||||
Function.Call(Hash.GET_CURR_WEATHER_STATE, &weather1, &weather2, &percent2);
|
||||
API.SendCustomEvent(CustomEvents.WeatherTimeSync, time.Hours, time.Minutes, time.Seconds, weather1, weather2, percent2);
|
||||
}
|
||||
});
|
||||
@ -60,7 +60,7 @@ namespace RageCoop.Client.Scripting
|
||||
private void WeatherTimeSync(CustomEventReceivedArgs e)
|
||||
{
|
||||
World.CurrentTimeOfDay = new TimeSpan((int)e.Args[0], (int)e.Args[1], (int)e.Args[2]);
|
||||
Function.Call(Hash._SET_WEATHER_TYPE_TRANSITION, (int)e.Args[3], (int)e.Args[4], (float)e.Args[5]);
|
||||
Function.Call(Hash.SET_CURR_WEATHER_STATE, (int)e.Args[3], (int)e.Args[4], (float)e.Args[5]);
|
||||
}
|
||||
|
||||
private void SetDisplayNameTag(CustomEventReceivedArgs e)
|
||||
@ -127,8 +127,7 @@ namespace RageCoop.Client.Scripting
|
||||
var pos = (Vector3)obj.Args[4];
|
||||
int rot = (int)obj.Args[5];
|
||||
var name = (string)obj.Args[6];
|
||||
Blip blip;
|
||||
if (!EntityPool.ServerBlips.TryGetValue(id, out blip))
|
||||
if (!EntityPool.ServerBlips.TryGetValue(id, out Blip blip))
|
||||
{
|
||||
EntityPool.ServerBlips.Add(id, blip = World.CreateBlip(pos));
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ namespace RageCoop.Client.Scripting
|
||||
/// <summary>
|
||||
/// Eqivalent of <see cref="ClientResource.Logger"/> in <see cref="CurrentResource"/>
|
||||
/// </summary>
|
||||
public Core.Logger Logger { get { return CurrentResource.Logger; } }
|
||||
public Core.Logger Logger => CurrentResource.Logger;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -38,9 +38,11 @@ namespace RageCoop.Client.Scripting
|
||||
}
|
||||
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()
|
||||
{
|
||||
BaseScriptType = "RageCoop.Client.Scripting.ClientScript";
|
||||
Logger = Main.Logger;
|
||||
}
|
||||
private void StartAll()
|
||||
@ -106,16 +108,6 @@ namespace RageCoop.Client.Scripting
|
||||
}
|
||||
LoadedResources.Clear();
|
||||
}
|
||||
private List<string> ToIgnore = new List<string>
|
||||
{
|
||||
"RageCoop.Client.dll",
|
||||
"RageCoop.Core.dll",
|
||||
"RageCoop.Server.dll",
|
||||
"ScriptHookVDotNet3.dll"
|
||||
};
|
||||
private List<ClientResource> LoadedResources = new List<ClientResource>();
|
||||
private string BaseScriptType;
|
||||
public Logger Logger { get; set; }
|
||||
|
||||
private void LoadResource(ZipFile file, string dataFolderRoot)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
public RSA ServerRSA { get; set; }
|
||||
public Aes ClientAes { get; set; } = Aes.Create();
|
||||
private Logger Logger;
|
||||
private readonly Logger Logger;
|
||||
public Security(Logger logger)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -22,7 +22,7 @@ namespace RageCoop.Client
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public string MasterServer { get; set; } = "https://masterserver.ragecoop.online/";
|
||||
public string MasterServer { get; set; } = "https://masterserver.ragecoop.com/";
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
@ -36,7 +36,7 @@ namespace RageCoop.Client
|
||||
/// 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
|
||||
@ -51,7 +51,7 @@ namespace RageCoop.Client
|
||||
/// <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.
|
||||
@ -67,9 +67,25 @@ namespace RageCoop.Client
|
||||
/// The game won't spawn more NPC traffic if the limit is exceeded. -1 for unlimited (not recommended).
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -116,10 +116,10 @@ namespace RageCoop.Client
|
||||
|
||||
case unchecked((uint)-1357824103):
|
||||
case unchecked((uint)-1074790547):
|
||||
case unchecked((uint)2132975508):
|
||||
case unchecked(2132975508):
|
||||
case unchecked((uint)-2084633992):
|
||||
case unchecked((uint)-952879014):
|
||||
case unchecked((uint)100416529):
|
||||
case unchecked(100416529):
|
||||
case unchecked((uint)WeaponHash.Gusenberg):
|
||||
case unchecked((uint)WeaponHash.MG):
|
||||
case unchecked((uint)WeaponHash.CombatMG):
|
||||
|
81
RageCoop.Client/Sync/Entities/Ped/SyncedPed.Members.cs
Normal file
81
RageCoop.Client/Sync/Entities/Ped/SyncedPed.Members.cs
Normal file
@ -0,0 +1,81 @@
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using RageCoop.Core;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
public partial class SyncedPed : SyncedEntity
|
||||
{
|
||||
internal Blip PedBlip = null;
|
||||
internal BlipColor BlipColor = (BlipColor)255;
|
||||
internal BlipSprite BlipSprite = 0;
|
||||
internal float BlipScale = 1;
|
||||
internal int VehicleID
|
||||
{
|
||||
get => CurrentVehicle?.ID ?? 0;
|
||||
set
|
||||
{
|
||||
if (CurrentVehicle == null || value != CurrentVehicle?.ID)
|
||||
{
|
||||
CurrentVehicle = EntityPool.GetVehicleByID(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
internal SyncedVehicle CurrentVehicle { get; private set; }
|
||||
internal VehicleSeat Seat;
|
||||
public bool IsPlayer { get => OwnerID == ID && ID != 0; }
|
||||
public Ped MainPed { get; internal set; }
|
||||
internal int Health { get; set; }
|
||||
|
||||
internal Vector3 HeadPosition { get; set; }
|
||||
internal Vector3 RightFootPosition { get; set; }
|
||||
internal Vector3 LeftFootPosition { get; set; }
|
||||
|
||||
internal byte WeaponTint { get; set; }
|
||||
private bool _lastRagdoll = false;
|
||||
private ulong _lastRagdollTime = 0;
|
||||
private bool _lastInCover = false;
|
||||
private byte[] _lastClothes = null;
|
||||
internal byte[] Clothes { get; set; }
|
||||
|
||||
internal float Heading { get; set; }
|
||||
|
||||
internal ulong LastSpeakingTime { get; set; } = 0;
|
||||
internal bool IsSpeaking { get; set; } = false;
|
||||
public byte Speed { get; set; }
|
||||
private bool _lastIsJumping = false;
|
||||
internal PedDataFlags Flags;
|
||||
|
||||
internal bool IsAiming => Flags.HasPedFlag(PedDataFlags.IsAiming);
|
||||
internal bool _lastDriveBy;
|
||||
internal bool IsReloading => Flags.HasPedFlag(PedDataFlags.IsReloading);
|
||||
internal bool IsJumping => Flags.HasPedFlag(PedDataFlags.IsJumping);
|
||||
internal bool IsRagdoll => Flags.HasPedFlag(PedDataFlags.IsRagdoll);
|
||||
internal bool IsOnFire => Flags.HasPedFlag(PedDataFlags.IsOnFire);
|
||||
internal bool IsInParachuteFreeFall => Flags.HasPedFlag(PedDataFlags.IsInParachuteFreeFall);
|
||||
internal bool IsParachuteOpen => Flags.HasPedFlag(PedDataFlags.IsParachuteOpen);
|
||||
internal bool IsOnLadder => Flags.HasPedFlag(PedDataFlags.IsOnLadder);
|
||||
internal bool IsVaulting => Flags.HasPedFlag(PedDataFlags.IsVaulting);
|
||||
internal bool IsInCover => Flags.HasPedFlag(PedDataFlags.IsInCover);
|
||||
internal bool IsInLowCover => Flags.HasPedFlag(PedDataFlags.IsInLowCover);
|
||||
internal bool IsInCoverFacingLeft => Flags.HasPedFlag(PedDataFlags.IsInCoverFacingLeft);
|
||||
internal bool IsBlindFiring => Flags.HasPedFlag(PedDataFlags.IsBlindFiring);
|
||||
internal bool IsInStealthMode => Flags.HasPedFlag(PedDataFlags.IsInStealthMode);
|
||||
internal Prop ParachuteProp { get; set; } = null;
|
||||
internal uint CurrentWeaponHash { get; set; }
|
||||
private Dictionary<uint, bool> _lastWeaponComponents = null;
|
||||
internal Dictionary<uint, bool> WeaponComponents { get; set; } = null;
|
||||
private Entity _weaponObj;
|
||||
internal Vector3 AimCoords { get; set; }
|
||||
|
||||
|
||||
private readonly string[] _currentAnimation = new string[2] { "", "" };
|
||||
|
||||
private bool LastMoving;
|
||||
|
||||
}
|
||||
}
|
@ -15,7 +15,6 @@ namespace RageCoop.Client
|
||||
/// </summary>
|
||||
public partial class SyncedPed : SyncedEntity
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
/// <summary>
|
||||
/// Create a local entity (outgoing sync)
|
||||
@ -29,7 +28,7 @@ namespace RageCoop.Client
|
||||
MainPed = p;
|
||||
OwnerID = Main.LocalPlayerID;
|
||||
|
||||
Function.Call(Hash._SET_PED_CAN_PLAY_INJURED_ANIMS, false);
|
||||
//Function.Call(Hash.SET_PED_IS_IGNORED_BY_AUTO_OPEN_DOORS, false);
|
||||
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
|
||||
// MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableMelee, true);
|
||||
|
||||
@ -43,79 +42,10 @@ namespace RageCoop.Client
|
||||
ID = id;
|
||||
LastSynced = Main.Ticked;
|
||||
}
|
||||
#endregion
|
||||
internal Blip PedBlip = null;
|
||||
internal BlipColor BlipColor = (BlipColor)255;
|
||||
internal BlipSprite BlipSprite = 0;
|
||||
internal float BlipScale = 1;
|
||||
internal int VehicleID
|
||||
{
|
||||
get => CurrentVehicle?.ID ?? 0;
|
||||
set
|
||||
{
|
||||
if (CurrentVehicle == null || value != CurrentVehicle?.ID)
|
||||
{
|
||||
CurrentVehicle=EntityPool.GetVehicleByID(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
internal SyncedVehicle CurrentVehicle { get; private set; }
|
||||
internal VehicleSeat Seat;
|
||||
public bool IsPlayer { get => OwnerID == ID && ID != 0; }
|
||||
public Ped MainPed { get; internal set; }
|
||||
internal int Health { get; set; }
|
||||
|
||||
internal Vector3 HeadPosition { get; set; }
|
||||
internal Vector3 RightFootPosition { get; set; }
|
||||
internal Vector3 LeftFootPosition { get; set; }
|
||||
|
||||
internal byte WeaponTint { get; set; }
|
||||
internal Vehicle _lastVehicle { get; set; }
|
||||
internal int _lastVehicleID { get; set; }
|
||||
private bool _lastRagdoll = false;
|
||||
private ulong _lastRagdollTime = 0;
|
||||
private bool _lastInCover = false;
|
||||
private byte[] _lastClothes = null;
|
||||
internal byte[] Clothes { get; set; }
|
||||
|
||||
internal float Heading { get; set; }
|
||||
|
||||
internal ulong LastSpeakingTime { get; set; } = 0;
|
||||
internal bool IsSpeaking { get; set; } = false;
|
||||
|
||||
#region -- VARIABLES --
|
||||
public byte Speed { get; set; }
|
||||
private bool _lastIsJumping = false;
|
||||
internal PedDataFlags Flags;
|
||||
|
||||
internal bool IsAiming => Flags.HasPedFlag(PedDataFlags.IsAiming);
|
||||
internal bool _lastDriveBy;
|
||||
internal bool IsReloading => Flags.HasPedFlag(PedDataFlags.IsReloading);
|
||||
internal bool IsJumping => Flags.HasPedFlag(PedDataFlags.IsJumping);
|
||||
internal bool IsRagdoll => Flags.HasPedFlag(PedDataFlags.IsRagdoll);
|
||||
internal bool IsOnFire => Flags.HasPedFlag(PedDataFlags.IsOnFire);
|
||||
internal bool IsInParachuteFreeFall => Flags.HasPedFlag(PedDataFlags.IsInParachuteFreeFall);
|
||||
internal bool IsParachuteOpen => Flags.HasPedFlag(PedDataFlags.IsParachuteOpen);
|
||||
internal bool IsOnLadder => Flags.HasPedFlag(PedDataFlags.IsOnLadder);
|
||||
internal bool IsVaulting => Flags.HasPedFlag(PedDataFlags.IsVaulting);
|
||||
internal bool IsInCover => Flags.HasPedFlag(PedDataFlags.IsInCover);
|
||||
internal bool IsInLowCover => Flags.HasPedFlag(PedDataFlags.IsInLowCover);
|
||||
internal bool IsInCoverFacingLeft => Flags.HasPedFlag(PedDataFlags.IsInCoverFacingLeft);
|
||||
internal bool IsBlindFiring => Flags.HasPedFlag(PedDataFlags.IsBlindFiring);
|
||||
internal bool IsInStealthMode => Flags.HasPedFlag(PedDataFlags.IsInStealthMode);
|
||||
internal Prop ParachuteProp { get; set; } = null;
|
||||
internal uint CurrentWeaponHash { get; set; }
|
||||
private Dictionary<uint, bool> _lastWeaponComponents = null;
|
||||
internal Dictionary<uint, bool> WeaponComponents { get; set; } = null;
|
||||
private int _lastWeaponObj = 0;
|
||||
#endregion
|
||||
internal Vector3 AimCoords { get; set; }
|
||||
|
||||
private WeaponAsset WeaponAsset { get; set; }
|
||||
|
||||
internal override void Update()
|
||||
{
|
||||
if (Owner==null) { return; }
|
||||
if (Owner == null) { OwnerID = OwnerID; return; }
|
||||
if (IsPlayer)
|
||||
{
|
||||
RenderNameTag();
|
||||
@ -146,20 +76,17 @@ namespace RageCoop.Client
|
||||
}
|
||||
}
|
||||
|
||||
if (((byte)BlipColor==255) && (PedBlip!=null))
|
||||
if (!Main.Settings.ShowPlayerBlip && (byte)BlipColor != 255) BlipColor = (BlipColor)255;
|
||||
if ((byte)BlipColor == 255 && PedBlip != null)
|
||||
{
|
||||
PedBlip.Delete();
|
||||
PedBlip = null;
|
||||
}
|
||||
else if (((byte)BlipColor != 255) && PedBlip==null)
|
||||
else if ((byte)BlipColor != 255 && PedBlip == null)
|
||||
{
|
||||
PedBlip = MainPed.AddBlip();
|
||||
|
||||
if (IsPlayer)
|
||||
{
|
||||
// Main.Logger.Debug("blip:"+Player.Username);
|
||||
Main.QueueAction(() => { PedBlip.Name=Owner.Username; });
|
||||
}
|
||||
|
||||
PedBlip.Color = BlipColor;
|
||||
PedBlip.Sprite = BlipSprite;
|
||||
PedBlip.Scale = BlipScale;
|
||||
@ -174,12 +101,18 @@ namespace RageCoop.Client
|
||||
{
|
||||
PedBlip.Sprite = BlipSprite;
|
||||
}
|
||||
if (IsPlayer)
|
||||
{
|
||||
PedBlip.Name = Owner.Username;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Clothes.SequenceEqual(_lastClothes))
|
||||
{
|
||||
SetClothes();
|
||||
}
|
||||
|
||||
CheckCurrentWeapon();
|
||||
}
|
||||
|
||||
if (MainPed.IsDead)
|
||||
@ -207,13 +140,20 @@ namespace RageCoop.Client
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsPlayer && Health <= 0 && !MainPed.IsDead)
|
||||
{
|
||||
MainPed.Kill();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Speed >= 4)
|
||||
{
|
||||
DisplayInVehicle();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MainPed.IsInVehicle()) { MainPed.Task.LeaveVehicle(LeaveVehicleFlags.WarpOut); }
|
||||
if (MainPed.IsInVehicle()) { MainPed.Task.LeaveVehicle(LeaveVehicleFlags.WarpOut); return; }
|
||||
DisplayOnFoot();
|
||||
}
|
||||
|
||||
@ -237,7 +177,7 @@ namespace RageCoop.Client
|
||||
|
||||
private void RenderNameTag()
|
||||
{
|
||||
if (!Owner.DisplayNameTag || (MainPed==null) || !MainPed.IsVisible || !MainPed.IsInRange(Main.PlayerPosition, 40f))
|
||||
if (!Owner.DisplayNameTag || !Main.Settings.ShowPlayerNameTag || MainPed == null || !MainPed.IsVisible || !MainPed.IsInRange(Main.PlayerPosition, 40f))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -271,7 +211,7 @@ namespace RageCoop.Client
|
||||
MainPed = null;
|
||||
}
|
||||
|
||||
if (PedBlip != null && PedBlip.Exists())
|
||||
if (PedBlip != null)
|
||||
{
|
||||
PedBlip.Delete();
|
||||
PedBlip = null;
|
||||
@ -302,7 +242,7 @@ namespace RageCoop.Client
|
||||
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED_BY_PLAYER, MainPed.Handle, Game.Player, true);
|
||||
Function.Call(Hash.SET_PED_GET_OUT_UPSIDE_DOWN_VEHICLE, MainPed.Handle, false);
|
||||
Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, MainPed.Handle, true, true);
|
||||
Function.Call(Hash._SET_PED_CAN_PLAY_INJURED_ANIMS, false);
|
||||
Function.Call(Hash.SET_PED_IS_IGNORED_BY_AUTO_OPEN_DOORS, false);
|
||||
Function.Call(Hash.SET_PED_CAN_EVASIVE_DIVE, MainPed.Handle, false);
|
||||
|
||||
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DrownsInWater, false);
|
||||
@ -340,13 +280,9 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
|
||||
#region ONFOOT
|
||||
private string[] _currentAnimation = new string[2] { "", "" };
|
||||
|
||||
private void DisplayOnFoot()
|
||||
{
|
||||
|
||||
CheckCurrentWeapon();
|
||||
if (IsInParachuteFreeFall)
|
||||
{
|
||||
MainPed.PositionNoOffset = Vector3.Lerp(MainPed.ReadPosition(), Position + Velocity, 0.5f);
|
||||
@ -490,7 +426,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
_lastIsJumping = false;
|
||||
|
||||
if (IsRagdoll || Health==0)
|
||||
if (IsRagdoll || (IsPlayer && Health == 0))
|
||||
{
|
||||
if (!MainPed.IsRagdoll)
|
||||
{
|
||||
@ -504,8 +440,6 @@ namespace RageCoop.Client
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MainPed.IsRagdoll)
|
||||
{
|
||||
if (Speed == 0)
|
||||
@ -516,10 +450,8 @@ namespace RageCoop.Client
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_lastRagdoll = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsReloading)
|
||||
@ -579,17 +511,15 @@ namespace RageCoop.Client
|
||||
}
|
||||
}
|
||||
|
||||
#region WEAPON
|
||||
private void CheckCurrentWeapon()
|
||||
{
|
||||
if (!WeaponAsset.IsLoaded) { WeaponAsset.Request(); }
|
||||
if (MainPed.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || !WeaponComponents.Compare(_lastWeaponComponents))
|
||||
if (MainPed.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || !WeaponComponents.Compare(_lastWeaponComponents) || (Speed <= 3 && _weaponObj?.IsVisible != true))
|
||||
{
|
||||
if (WeaponAsset!=null) { WeaponAsset.MarkAsNoLongerNeeded(); }
|
||||
WeaponAsset=new WeaponAsset(CurrentWeaponHash);
|
||||
MainPed.Weapons.RemoveAll();
|
||||
_lastWeaponObj = Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0);
|
||||
new WeaponAsset(CurrentWeaponHash).Request();
|
||||
|
||||
MainPed.Weapons.RemoveAll();
|
||||
_weaponObj = Entity.FromHandle(Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0));
|
||||
if (_weaponObj == null) { return; }
|
||||
if (CurrentWeaponHash != (uint)WeaponHash.Unarmed)
|
||||
{
|
||||
if (WeaponComponents != null && WeaponComponents.Count != 0)
|
||||
@ -598,11 +528,11 @@ namespace RageCoop.Client
|
||||
{
|
||||
if (comp.Value)
|
||||
{
|
||||
Function.Call(Hash.GIVE_WEAPON_COMPONENT_TO_WEAPON_OBJECT, _lastWeaponObj, comp.Key);
|
||||
Function.Call(Hash.GIVE_WEAPON_COMPONENT_TO_WEAPON_OBJECT, _weaponObj, comp.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
Function.Call(Hash.GIVE_WEAPON_OBJECT_TO_PED, _lastWeaponObj, MainPed.Handle);
|
||||
Function.Call(Hash.GIVE_WEAPON_OBJECT_TO_PED, _weaponObj, MainPed.Handle);
|
||||
}
|
||||
_lastWeaponComponents = WeaponComponents;
|
||||
}
|
||||
@ -627,14 +557,12 @@ namespace RageCoop.Client
|
||||
}
|
||||
SmoothTransition();
|
||||
}
|
||||
#endregion
|
||||
|
||||
private bool LastMoving;
|
||||
private void WalkTo()
|
||||
{
|
||||
MainPed.Task.ClearAll();
|
||||
Function.Call(Hash.SET_PED_STEALTH_MOVEMENT, MainPed, IsInStealthMode, 0);
|
||||
Vector3 predictPosition = Position + (Position - MainPed.ReadPosition()) + Velocity * 0.5f;
|
||||
Vector3 predictPosition = Predict(Position) + Velocity;
|
||||
float range = predictPosition.DistanceToSquared(MainPed.ReadPosition());
|
||||
|
||||
switch (Speed)
|
||||
@ -676,6 +604,8 @@ namespace RageCoop.Client
|
||||
MainPed.Task.StandStill(2000);
|
||||
LastMoving = false;
|
||||
}
|
||||
|
||||
if (MainPed.IsTaskActive(TaskType.CTaskDiveToGround)) MainPed.Task.ClearAll();
|
||||
break;
|
||||
}
|
||||
SmoothTransition();
|
||||
@ -684,19 +614,25 @@ namespace RageCoop.Client
|
||||
private void SmoothTransition()
|
||||
{
|
||||
var localRagdoll = MainPed.IsRagdoll;
|
||||
var dist = Position.DistanceTo(MainPed.ReadPosition());
|
||||
if (dist>3)
|
||||
var predicted = Predict(Position);
|
||||
var dist = predicted.DistanceTo(MainPed.ReadPosition());
|
||||
if (IsOff(dist))
|
||||
{
|
||||
MainPed.PositionNoOffset=Position;
|
||||
MainPed.PositionNoOffset = predicted;
|
||||
return;
|
||||
}
|
||||
if (!(localRagdoll || MainPed.IsDead))
|
||||
{
|
||||
if (!IsAiming && !MainPed.IsGettingUp)
|
||||
{
|
||||
MainPed.Heading=Heading;
|
||||
var cur = MainPed.Heading;
|
||||
var diff = Heading - cur;
|
||||
if (diff > 180) { diff -= 360; }
|
||||
else if (diff < -180) { diff += 360; }
|
||||
|
||||
MainPed.Heading = cur + diff / 2;
|
||||
}
|
||||
MainPed.Velocity=Velocity+5*dist*(Position-MainPed.ReadPosition());
|
||||
MainPed.Velocity = Velocity + 5 * dist * (predicted - MainPed.ReadPosition());
|
||||
}
|
||||
else if (Main.Ticked - _lastRagdollTime < 10)
|
||||
{
|
||||
@ -708,44 +644,49 @@ namespace RageCoop.Client
|
||||
var head = MainPed.Bones[Bone.SkelHead];
|
||||
var rightFoot = MainPed.Bones[Bone.SkelRightFoot];
|
||||
var leftFoot = MainPed.Bones[Bone.SkelLeftFoot];
|
||||
|
||||
Vector3 amount;
|
||||
// 20:head, 3:left foot, 6:right foot, 17:right hand,
|
||||
|
||||
amount = 20 * (Predict(HeadPosition) - head.Position);
|
||||
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
|
||||
helper.EqualizeAmount = 1;
|
||||
helper.PartIndex = 20;
|
||||
helper.Impulse=20*(HeadPosition-head.Position);
|
||||
helper.Impulse = amount;
|
||||
helper.Start();
|
||||
helper.Stop();
|
||||
|
||||
amount = 20 * (Predict(RightFootPosition) - rightFoot.Position);
|
||||
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
|
||||
helper.EqualizeAmount = 1;
|
||||
helper.PartIndex = 6;
|
||||
helper.Impulse=20*(RightFootPosition-rightFoot.Position);
|
||||
helper.Impulse = amount;
|
||||
helper.Start();
|
||||
helper.Stop();
|
||||
|
||||
amount = 20 * (Predict(LeftFootPosition) - leftFoot.Position);
|
||||
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
|
||||
helper.EqualizeAmount = 1;
|
||||
helper.PartIndex = 3;
|
||||
helper.Impulse=20*(LeftFootPosition-leftFoot.Position);
|
||||
helper.Impulse = amount;
|
||||
helper.Start();
|
||||
helper.Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
MainPed.Velocity=Velocity+5*dist*(Position-MainPed.ReadPosition());
|
||||
// localRagdoll
|
||||
var force = Velocity - MainPed.Velocity + 5 * dist * (predicted - MainPed.ReadPosition());
|
||||
if (force.Length() > 20) { force = force.Normalized * 20; }
|
||||
MainPed.ApplyForce(force);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
private void DisplayInVehicle()
|
||||
{
|
||||
if (CurrentVehicle==null || CurrentVehicle.MainVehicle==null) { Main.Logger.Error("Veh not found"); return; }
|
||||
if (CurrentVehicle?.MainVehicle == null) { return; }
|
||||
switch (Speed)
|
||||
{
|
||||
case 4:
|
||||
if (MainPed.CurrentVehicle!=CurrentVehicle.MainVehicle)
|
||||
if (MainPed.CurrentVehicle != CurrentVehicle.MainVehicle || MainPed.SeatIndex != Seat || (!MainPed.IsSittingInVehicle() && !MainPed.IsBeingJacked))
|
||||
{
|
||||
MainPed.SetIntoVehicle(CurrentVehicle.MainVehicle, Seat);
|
||||
}
|
||||
@ -757,7 +698,6 @@ namespace RageCoop.Client
|
||||
if (MainPed.VehicleWeapon == VehicleWeaponHash.Invalid)
|
||||
{
|
||||
// World.DrawMarker(MarkerType.DebugSphere,AimCoords,default,default,new Vector3(0.2f,0.2f,0.2f),Color.AliceBlue);
|
||||
CheckCurrentWeapon();
|
||||
if (IsAiming)
|
||||
{
|
||||
Function.Call(Hash.SET_DRIVEBY_TASK_TARGET, MainPed, 0, 0, AimCoords.X, AimCoords.Y, AimCoords.Z);
|
||||
@ -782,7 +722,7 @@ namespace RageCoop.Client
|
||||
case 5:
|
||||
if (MainPed.VehicleTryingToEnter != CurrentVehicle.MainVehicle || MainPed.GetSeatTryingToEnter() != Seat)
|
||||
{
|
||||
MainPed.Task.EnterVehicle(CurrentVehicle.MainVehicle,Seat,-1,5,EnterVehicleFlags.AllowJacking);
|
||||
MainPed.Task.EnterVehicle(CurrentVehicle.MainVehicle, Seat, -1, 5, EnterVehicleFlags.JackAnyone);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
|
@ -36,6 +36,10 @@ namespace RageCoop.Client
|
||||
if (value == _ownerID && Owner != null) { return; }
|
||||
_ownerID = value;
|
||||
Owner = PlayerList.GetPlayer(value);
|
||||
if (this is SyncedPed && Owner != null)
|
||||
{
|
||||
Owner.Character = ((SyncedPed)this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,16 +84,33 @@ namespace RageCoop.Client
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal protected bool _lastFrozen = false;
|
||||
protected internal bool _lastFrozen = false;
|
||||
internal Model Model { get; set; }
|
||||
internal Vector3 Position { get; set; }
|
||||
internal Vector3 Rotation { get; set; }
|
||||
internal Quaternion Quaternion { get; set; }
|
||||
internal Vector3 Velocity { get; set; }
|
||||
public Stopwatch LastSyncedStopWatch = new Stopwatch();
|
||||
internal abstract void Update();
|
||||
internal void PauseUpdate(ulong frames)
|
||||
{
|
||||
LastUpdated = Main.Ticked + frames;
|
||||
}
|
||||
protected Vector3 Predict(Vector3 input)
|
||||
{
|
||||
return (Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds) * Velocity + input;
|
||||
}
|
||||
private float _accumulatedOff = 0;
|
||||
protected bool IsOff(float thisOff, float tolerance = 3, float limit = 30)
|
||||
{
|
||||
_accumulatedOff += thisOff - tolerance;
|
||||
if (_accumulatedOff < 0) { _accumulatedOff = 0; }
|
||||
else if (_accumulatedOff >= limit)
|
||||
{
|
||||
_accumulatedOff = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using RageCoop.Core;
|
||||
using GTA.Native;
|
||||
using RageCoop.Core;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -19,12 +19,11 @@ namespace RageCoop.Client
|
||||
public SyncedEntity Shooter { get; set; }
|
||||
public bool Exploded => Flags.HasProjDataFlag(ProjectileDataFlags.Exploded);
|
||||
|
||||
internal override Player Owner => Shooter.Owner;
|
||||
/// <summary>
|
||||
/// Invalid property for projectile.
|
||||
/// </summary>
|
||||
private new int OwnerID { set { } }
|
||||
|
||||
internal override Player Owner => Shooter.Owner;
|
||||
public WeaponHash WeaponHash { get; set; }
|
||||
private WeaponAsset Asset { get; set; }
|
||||
public void ExtractData(ref Packets.ProjectileSync p)
|
||||
@ -101,7 +100,7 @@ namespace RageCoop.Client
|
||||
CreateProjectile();
|
||||
return;
|
||||
}
|
||||
MainProjectile.Velocity=Velocity+(Position+Shooter.Owner.PacketTravelTime*Velocity-MainProjectile.Position);
|
||||
MainProjectile.Velocity = Velocity + 10 * (Predict(Position) - MainProjectile.Position);
|
||||
MainProjectile.Rotation = Rotation;
|
||||
LastUpdated = Main.Ticked;
|
||||
}
|
||||
@ -113,15 +112,14 @@ namespace RageCoop.Client
|
||||
if (Shooter == null) { return; }
|
||||
Entity owner;
|
||||
owner = (Shooter as SyncedPed)?.MainPed ?? (Entity)(Shooter as SyncedVehicle)?.MainVehicle;
|
||||
Position = (Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds) * Shooter.Velocity + Position;
|
||||
var end = Position + Velocity;
|
||||
Function.Call(Hash.SHOOT_SINGLE_BULLET_BETWEEN_COORDS_IGNORE_ENTITY, Position.X, Position.Y, Position.Z, end.X, end.Y, end.Z, 0, 1, WeaponHash, owner?.Handle ?? 0, 1, 0, -1,owner);
|
||||
Function.Call(Hash.SHOOT_SINGLE_BULLET_BETWEEN_COORDS_IGNORE_ENTITY, Position.X, Position.Y, Position.Z, end.X, end.Y, end.Z, 0, 1, WeaponHash, owner?.Handle ?? 0, 1, 0, -1);
|
||||
var ps = World.GetAllProjectiles();
|
||||
MainProjectile = ps[ps.Length - 1];
|
||||
MainProjectile.IsCollisionEnabled=false;
|
||||
MainProjectile.Position = Position;
|
||||
MainProjectile.Rotation = Rotation;
|
||||
MainProjectile.Velocity = Velocity;
|
||||
Main.Delay(()=>MainProjectile.IsCollisionEnabled=true, 100);
|
||||
EntityPool.Add(this);
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using RageCoop.Core;
|
||||
using GTA;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using RageCoop.Core;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Client{
|
||||
public partial class SyncedVehicle{
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
public partial class SyncedVehicle
|
||||
{
|
||||
public Vehicle MainVehicle { get; internal set; }
|
||||
public Stopwatch LastSyncedStopWatch = new Stopwatch();
|
||||
|
||||
|
||||
#region -- SYNC DATA --
|
||||
@ -69,11 +67,9 @@ namespace RageCoop.Client{
|
||||
private bool _lastHornActive = false;
|
||||
private bool _lastTransformed = false;
|
||||
internal int _lastLivery = -1;
|
||||
List<Vector3> _predictedTrace = new List<Vector3>();
|
||||
List<Vector3> _orgTrace = new List<Vector3>();
|
||||
private readonly List<Vector3> _predictedTrace = new List<Vector3>();
|
||||
private readonly List<Vector3> _orgTrace = new List<Vector3>();
|
||||
private Vector3 _predictedPosition;
|
||||
|
||||
float _elapsed;
|
||||
#endregion
|
||||
|
||||
#region OUTGOING
|
@ -4,8 +4,7 @@ using GTA.Native;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -31,7 +30,9 @@ namespace RageCoop.Client
|
||||
SetUpFixedData();
|
||||
|
||||
}
|
||||
private void SetUpFixedData(){
|
||||
internal void SetUpFixedData()
|
||||
{
|
||||
if (MainVehicle == null) { return; }
|
||||
|
||||
IsAircraft = MainVehicle.IsAircraft;
|
||||
IsMotorcycle = MainVehicle.IsMotorcycle;
|
||||
@ -85,6 +86,8 @@ namespace RageCoop.Client
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DisplayVehicle();
|
||||
// Skip update if no new sync message has arrived.
|
||||
if (!NeedUpdate)
|
||||
{
|
||||
@ -97,8 +100,6 @@ namespace RageCoop.Client
|
||||
}
|
||||
MainVehicle.ThrottlePower = ThrottlePower;
|
||||
MainVehicle.BrakePower = BrakePower;
|
||||
var v = Main.P.CurrentVehicle;
|
||||
DisplayVehicle(v != null && MainVehicle.IsTouching(v));
|
||||
|
||||
if (IsDead)
|
||||
{
|
||||
@ -149,8 +150,6 @@ namespace RageCoop.Client
|
||||
MainVehicle.AreHighBeamsOn = HighBeamsOn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (IsAircraft)
|
||||
{
|
||||
if (LandingGear != (byte)MainVehicle.LandingGearState)
|
||||
@ -184,10 +183,12 @@ namespace RageCoop.Client
|
||||
MainVehicle.RoofState = RoofState;
|
||||
}
|
||||
|
||||
if(HasRocketBoost && Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive) != MainVehicle.IsRocketBoostActive()){
|
||||
if (HasRocketBoost && Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive) != MainVehicle.IsRocketBoostActive())
|
||||
{
|
||||
MainVehicle.SetRocketBoostActive(Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive));
|
||||
}
|
||||
if(HasParachute && Flags.HasFlag(VehicleDataFlags.IsParachuteActive) != MainVehicle.IsParachuteActive()){
|
||||
if (HasParachute && Flags.HasFlag(VehicleDataFlags.IsParachuteActive) != MainVehicle.IsParachuteActive())
|
||||
{
|
||||
MainVehicle.SetParachuteActive(Flags.HasFlag(VehicleDataFlags.IsParachuteActive));
|
||||
}
|
||||
if (IsSubmarineCar)
|
||||
@ -197,31 +198,32 @@ namespace RageCoop.Client
|
||||
if (!_lastTransformed)
|
||||
{
|
||||
_lastTransformed = true;
|
||||
Function.Call(Hash._TRANSFORM_VEHICLE_TO_SUBMARINE, MainVehicle.Handle, false);
|
||||
Function.Call(Hash.TRANSFORM_TO_SUBMARINE, MainVehicle.Handle, false);
|
||||
}
|
||||
}
|
||||
else if (_lastTransformed)
|
||||
{
|
||||
_lastTransformed = false;
|
||||
Function.Call(Hash._TRANSFORM_SUBMARINE_TO_VEHICLE, MainVehicle.Handle, false);
|
||||
Function.Call(Hash.TRANSFORM_TO_CAR, MainVehicle.Handle, false);
|
||||
}
|
||||
}
|
||||
else if(IsDeluxo && IsDeluxoHovering!=MainVehicle.IsDeluxoHovering()){
|
||||
else if (IsDeluxo)
|
||||
{
|
||||
MainVehicle.SetDeluxoHoverState(IsDeluxoHovering);
|
||||
if(IsDeluxoHovering){
|
||||
if (IsDeluxoHovering)
|
||||
{
|
||||
MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
|
||||
}
|
||||
}
|
||||
|
||||
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
|
||||
MainVehicle.SetDamageModel(DamageModel);
|
||||
|
||||
|
||||
}
|
||||
MainVehicle.LockStatus = LockStatus;
|
||||
|
||||
if (LastFullSynced >= LastUpdated)
|
||||
{
|
||||
#region -- SYNC STATE --
|
||||
if (Flags.HasVehFlag(VehicleDataFlags.Repaired))
|
||||
{
|
||||
MainVehicle.Repair();
|
||||
@ -255,14 +257,14 @@ namespace RageCoop.Client
|
||||
Function.Call(Hash.SET_VEHICLE_LIVERY, MainVehicle, Livery);
|
||||
_lastLivery = Livery;
|
||||
}
|
||||
#endregion
|
||||
MainVehicle.SetDamageModel(DamageModel);
|
||||
}
|
||||
LastUpdated = Main.Ticked;
|
||||
}
|
||||
void DisplayVehicle(bool touching)
|
||||
|
||||
private void DisplayVehicle()
|
||||
{
|
||||
_elapsed = Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds;
|
||||
_predictedPosition = Position + _elapsed * Velocity;
|
||||
_predictedPosition = Predict(Position);
|
||||
var current = MainVehicle.ReadPosition();
|
||||
var dist = current.DistanceTo(_predictedPosition);
|
||||
var cali = dist * (_predictedPosition - current);
|
||||
@ -274,41 +276,20 @@ namespace RageCoop.Client
|
||||
MainVehicle.Quaternion = Quaternion;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (dist > 0.03)
|
||||
{
|
||||
MainVehicle.Velocity = Velocity + cali;
|
||||
}
|
||||
|
||||
if (IsFlipped)
|
||||
Vector3 calirot;
|
||||
if (IsFlipped || (calirot = GetCalibrationRotation()).Length() > 50)
|
||||
{
|
||||
MainVehicle.Quaternion = Quaternion.Slerp(MainVehicle.ReadQuaternion(), Quaternion, 0.5f);
|
||||
MainVehicle.RotationVelocity = RotationVelocity;
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 calirot = GetCalibrationRotation();
|
||||
if (calirot.Length() < 50)
|
||||
{
|
||||
MainVehicle.RotationVelocity = RotationVelocity + calirot * 0.2f;
|
||||
}
|
||||
else
|
||||
{
|
||||
MainVehicle.Quaternion = Quaternion;
|
||||
MainVehicle.RotationVelocity = RotationVelocity;
|
||||
}
|
||||
|
||||
#if DEBUG_VEH
|
||||
if (_orgTrace.Count >= 30)
|
||||
{
|
||||
_orgTrace.RemoveAt(0);
|
||||
}
|
||||
if (_predictedTrace.Count >= 30)
|
||||
{
|
||||
_predictedTrace.RemoveAt(0);
|
||||
}
|
||||
_orgTrace.Add(Position);
|
||||
_predictedTrace.Add(_predictedPos);
|
||||
#endif
|
||||
}
|
||||
private Vector3 GetCalibrationRotation()
|
||||
{
|
||||
var rot = Quaternion.LookRotation(Quaternion * Vector3.RelativeFront, Quaternion * Vector3.RelativeTop).ToEulerAngles();
|
||||
@ -327,6 +308,16 @@ namespace RageCoop.Client
|
||||
}
|
||||
private bool CreateVehicle()
|
||||
{
|
||||
var existing = World.GetNearbyVehicles(Position, 2).ToList().FirstOrDefault();
|
||||
if (existing != null && existing != MainVehicle)
|
||||
{
|
||||
if (EntityPool.VehiclesByHandle.ContainsKey(existing.Handle))
|
||||
{
|
||||
EntityPool.RemoveVehicle(ID);
|
||||
return false;
|
||||
}
|
||||
existing.Delete();
|
||||
}
|
||||
MainVehicle?.Delete();
|
||||
MainVehicle = Util.CreateVehicle(Model, Position);
|
||||
if (!Model.IsInCdImage)
|
||||
@ -334,7 +325,7 @@ namespace RageCoop.Client
|
||||
// GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
|
||||
return false;
|
||||
}
|
||||
else if (MainVehicle==null)
|
||||
if (MainVehicle == null)
|
||||
{
|
||||
Model.Request();
|
||||
return false;
|
||||
@ -357,43 +348,5 @@ namespace RageCoop.Client
|
||||
Model.MarkAsNoLongerNeeded();
|
||||
return true;
|
||||
}
|
||||
#region -- PEDALING --
|
||||
/*
|
||||
* Thanks to @oldnapalm.
|
||||
*/
|
||||
|
||||
private string PedalingAnimDict()
|
||||
{
|
||||
switch ((VehicleHash)Model)
|
||||
{
|
||||
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
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,18 +1,17 @@
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Client.Scripting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class EntityPool
|
||||
{
|
||||
public static object PedsLock = new object();
|
||||
public static int CharactersCount { get { return PedsByID.Count; } }
|
||||
#if BENCHMARK
|
||||
private static Stopwatch PerfCounter=new Stopwatch();
|
||||
private static Stopwatch PerfCounter2=Stopwatch.StartNew();
|
||||
@ -44,15 +43,15 @@ namespace RageCoop.Client
|
||||
#endregion
|
||||
public static void Cleanup(bool keepPlayer = true, bool keepMine = true)
|
||||
{
|
||||
foreach (int id in new List<int>(PedsByID.Keys))
|
||||
foreach (var ped in PedsByID.Values.ToArray())
|
||||
{
|
||||
if (keepPlayer && (id==Main.LocalPlayerID)|| keepMine && (PedsByID[id].OwnerID == Main.LocalPlayerID)) { continue; }
|
||||
RemovePed(id);
|
||||
if ((keepPlayer && (ped.ID == Main.LocalPlayerID)) || (keepMine && (ped.OwnerID == Main.LocalPlayerID))) { continue; }
|
||||
RemovePed(ped.ID);
|
||||
}
|
||||
PedsByID.Clear();
|
||||
PedsByHandle.Clear();
|
||||
|
||||
foreach (int id in new List<int>(VehiclesByID.Keys))
|
||||
foreach (int id in VehiclesByID.Keys.ToArray())
|
||||
{
|
||||
if (keepMine && (VehiclesByID[id].OwnerID == Main.LocalPlayerID)) { continue; }
|
||||
RemoveVehicle(id);
|
||||
@ -93,6 +92,8 @@ namespace RageCoop.Client
|
||||
public static bool AddPlayer()
|
||||
{
|
||||
Ped p = Game.Player.Character;
|
||||
// var clipset=p.Gender==Gender.Male? "MOVE_M@TOUGH_GUY@" : "MOVE_F@TOUGH_GUY@";
|
||||
// Function.Call(Hash.SET_PED_MOVEMENT_CLIPSET,p,clipset,1f);
|
||||
SyncedPed player = GetPedByID(Main.LocalPlayerID);
|
||||
if (player == null)
|
||||
{
|
||||
@ -276,8 +277,8 @@ namespace RageCoop.Client
|
||||
{
|
||||
ProjectilesByHandle.Remove(p.Handle);
|
||||
}
|
||||
Main.Logger.Debug($"Removing projectile {sp.ID}. Reason:{reason}");
|
||||
p.Explode();
|
||||
//Main.Logger.Debug($"Removing projectile {sp.ID}. Reason:{reason}");
|
||||
if (sp.Exploded) p.Explode();
|
||||
}
|
||||
ProjectilesByID.Remove(id);
|
||||
}
|
||||
@ -287,11 +288,11 @@ namespace RageCoop.Client
|
||||
public static bool VehicleExists(int id) => VehiclesByID.ContainsKey(id);
|
||||
public static bool ProjectileExists(int id) => ProjectilesByID.ContainsKey(id);
|
||||
#endregion
|
||||
static int vehStateIndex;
|
||||
static int pedStateIndex;
|
||||
static int vehStatesPerFrame;
|
||||
static int pedStatesPerFrame;
|
||||
static int i;
|
||||
private static int vehStateIndex;
|
||||
private static int pedStateIndex;
|
||||
private static int vehStatesPerFrame;
|
||||
private static int pedStatesPerFrame;
|
||||
private static int i;
|
||||
public static Ped[] allPeds = new Ped[0];
|
||||
public static Vehicle[] allVehicles = new Vehicle[0];
|
||||
public static Projectile[] allProjectiles = new Projectile[0];
|
||||
@ -308,17 +309,6 @@ namespace RageCoop.Client
|
||||
allProjectiles = World.GetAllProjectiles();
|
||||
vehStatesPerFrame = allVehicles.Length * 2 / (int)Game.FPS + 1;
|
||||
pedStatesPerFrame = allPeds.Length * 2 / (int)Game.FPS + 1;
|
||||
/*
|
||||
if (Main.Ticked%50==0)
|
||||
{
|
||||
bool flag1 = allVehicles.Length>Main.Settings.WorldVehicleSoftLimit && Main.Settings.WorldVehicleSoftLimit>-1;
|
||||
bool flag2 = allPeds.Length>Main.Settings.WorldPedSoftLimit && Main.Settings.WorldPedSoftLimit>-1;
|
||||
if ((flag1||flag2) && _trafficSpawning)
|
||||
{ SetBudget(0); _trafficSpawning=false; }
|
||||
else if(!_trafficSpawning)
|
||||
{ SetBudget(1); _trafficSpawning=true; }
|
||||
}
|
||||
*/
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.GetAllEntities]=PerfCounter.ElapsedTicks;
|
||||
@ -343,7 +333,7 @@ namespace RageCoop.Client
|
||||
if (p.MainProjectile.AttachedEntity == null)
|
||||
{
|
||||
// Prevent projectiles from exploding next to vehicle
|
||||
if (p.WeaponHash==(WeaponHash)VehicleWeaponHash.Tank || p.MainProjectile.Position.DistanceTo(p.Origin)<2)
|
||||
if (p.WeaponHash == (WeaponHash)VehicleWeaponHash.Tank || (p.MainProjectile.OwnerEntity?.EntityType == EntityType.Vehicle && p.MainProjectile.Position.DistanceTo(p.Origin) < 2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -368,22 +358,25 @@ namespace RageCoop.Client
|
||||
|
||||
lock (PedsLock)
|
||||
{
|
||||
EntityPool.AddPlayer();
|
||||
AddPlayer();
|
||||
var mainCharacters = new List<PedHash> { PedHash.Michael, PedHash.Franklin, PedHash.Franklin02, PedHash.Trevor };
|
||||
|
||||
foreach (Ped p in allPeds)
|
||||
{
|
||||
SyncedPed c = EntityPool.GetPedByHandle(p.Handle);
|
||||
if (c==null && (p!=Game.Player.Character))
|
||||
if (!PedsByHandle.ContainsKey(p.Handle) && p != Game.Player.Character && !mainCharacters.Contains((PedHash)p.Model.Hash))
|
||||
{
|
||||
if (allPeds.Length>Main.Settings.WorldPedSoftLimit && p.PopulationType != EntityPopulationType.RandomAmbient)
|
||||
if (PedsByID.Count(x => x.Value.IsLocal) > Main.Settings.WorldPedSoftLimit)
|
||||
{
|
||||
if (p.PopulationType == EntityPopulationType.RandomAmbient && !p.IsInVehicle())
|
||||
{
|
||||
p.Delete();
|
||||
continue;
|
||||
}
|
||||
if (p.PopulationType == EntityPopulationType.RandomScenario) continue;
|
||||
}
|
||||
// Main.Logger.Trace($"Creating SyncEntity for ped, handle:{p.Handle}");
|
||||
c=new SyncedPed(p);
|
||||
|
||||
EntityPool.Add(c);
|
||||
Add(new SyncedPed(p));
|
||||
}
|
||||
}
|
||||
#if BENCHMARK
|
||||
@ -402,7 +395,7 @@ namespace RageCoop.Client
|
||||
i++;
|
||||
if ((c.MainPed != null) && (!c.MainPed.Exists()))
|
||||
{
|
||||
EntityPool.RemovePed(c.ID, "non-existent");
|
||||
RemovePed(c.ID, "non-existent");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -439,27 +432,25 @@ namespace RageCoop.Client
|
||||
Debug.TimeStamps[TimeStamp.PedTotal]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
}
|
||||
|
||||
var check = Main.Ticked % 100 == 0;
|
||||
i = -1;
|
||||
|
||||
lock (VehiclesLock)
|
||||
{
|
||||
foreach (Vehicle veh in allVehicles)
|
||||
{
|
||||
if (!VehiclesByHandle.ContainsKey(veh.Handle))
|
||||
{
|
||||
if (allVehicles.Length>Main.Settings.WorldVehicleSoftLimit)
|
||||
if (VehiclesByID.Count(x => x.Value.IsLocal) > Main.Settings.WorldVehicleSoftLimit)
|
||||
{
|
||||
var type = veh.PopulationType;
|
||||
if (type==EntityPopulationType.RandomAmbient || type==EntityPopulationType.RandomParked)
|
||||
if (veh.PopulationType == EntityPopulationType.RandomAmbient || veh.PopulationType == EntityPopulationType.RandomParked)
|
||||
{
|
||||
foreach (var p in veh.Occupants)
|
||||
{
|
||||
p.Delete();
|
||||
var c = EntityPool.GetPedByHandle(p.Handle);
|
||||
var c = GetPedByHandle(p.Handle);
|
||||
if (c != null)
|
||||
{
|
||||
EntityPool.RemovePed(c.ID, "ThrottleTraffic");
|
||||
RemovePed(c.ID, "ThrottleTraffic");
|
||||
}
|
||||
}
|
||||
veh.Delete();
|
||||
@ -486,10 +477,13 @@ namespace RageCoop.Client
|
||||
i++;
|
||||
if ((v.MainVehicle != null) && (!v.MainVehicle.Exists()))
|
||||
{
|
||||
EntityPool.RemoveVehicle(v.ID, "non-existent");
|
||||
RemoveVehicle(v.ID, "non-existent");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (check)
|
||||
{
|
||||
v.SetUpFixedData();
|
||||
}
|
||||
// Outgoing sync
|
||||
if (v.IsLocal)
|
||||
{
|
||||
@ -514,7 +508,8 @@ namespace RageCoop.Client
|
||||
}
|
||||
Networking.Peer.FlushSendQueue();
|
||||
}
|
||||
static void UpdateTargets()
|
||||
|
||||
private static void UpdateTargets()
|
||||
{
|
||||
Networking.Targets = new List<NetConnection>(PlayerList.Players.Count) { Networking.ServerConnection };
|
||||
foreach (var p in PlayerList.Players.Values.ToArray())
|
||||
@ -579,21 +574,21 @@ namespace RageCoop.Client
|
||||
{
|
||||
public static void Add(SyncedVehicle v)
|
||||
{
|
||||
lock (EntityPool.VehiclesLock)
|
||||
lock (VehiclesLock)
|
||||
{
|
||||
EntityPool.Add(v);
|
||||
}
|
||||
}
|
||||
public static void Add(SyncedPed p)
|
||||
{
|
||||
lock (EntityPool.PedsLock)
|
||||
lock (PedsLock)
|
||||
{
|
||||
EntityPool.Add(p);
|
||||
}
|
||||
}
|
||||
public static void Add(SyncedProjectile sp)
|
||||
{
|
||||
lock (EntityPool.ProjectilesLock)
|
||||
lock (ProjectilesLock)
|
||||
{
|
||||
EntityPool.Add(sp);
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -73,9 +71,8 @@ namespace RageCoop.Client
|
||||
#region HANDLE
|
||||
|
||||
public static ParticleEffectAsset CorePFXAsset = new ParticleEffectAsset("core");
|
||||
|
||||
static WeaponAsset _weaponAsset = default;
|
||||
static uint _lastWeaponHash;
|
||||
private static WeaponAsset _weaponAsset = default;
|
||||
private static uint _lastWeaponHash;
|
||||
|
||||
private static void HandlePedKilled(Packets.PedKilled p)
|
||||
{
|
||||
@ -129,7 +126,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
var p = EntityPool.GetPedByID(ownerID)?.MainPed;
|
||||
if (p == null) { p=Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); }
|
||||
if (p == null) { return; /* p = Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); */ }
|
||||
if (!CorePFXAsset.IsLoaded) { CorePFXAsset.Request(); }
|
||||
if (_lastWeaponHash != weaponHash)
|
||||
{
|
||||
@ -162,44 +159,39 @@ namespace RageCoop.Client
|
||||
WeaponUtil.GetFlashFX((WeaponHash)p.WeaponHash),
|
||||
b.Position, b.ForwardVector.ToEulerRotation(v.Bones[35].UpVector), 1);
|
||||
}
|
||||
public static void HandleEvent(PacketType type, byte[] data)
|
||||
public static void HandleEvent(PacketType type, NetIncomingMessage msg)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PacketType.BulletShot:
|
||||
{
|
||||
Packets.BulletShot p = new Packets.BulletShot();
|
||||
p.Deserialize(data);
|
||||
p.Deserialize(msg);
|
||||
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
|
||||
break;
|
||||
}
|
||||
case PacketType.VehicleBulletShot:
|
||||
{
|
||||
HandleVehicleBulletShot(data.GetPacket<Packets.VehicleBulletShot>());
|
||||
HandleVehicleBulletShot(msg.GetPacket<Packets.VehicleBulletShot>());
|
||||
break;
|
||||
}
|
||||
case PacketType.OwnerChanged:
|
||||
{
|
||||
Packets.OwnerChanged packet = new Packets.OwnerChanged();
|
||||
packet.Deserialize(data);
|
||||
HandleOwnerChanged(packet);
|
||||
HandleOwnerChanged(msg.GetPacket<Packets.OwnerChanged>());
|
||||
}
|
||||
break;
|
||||
case PacketType.PedKilled:
|
||||
{
|
||||
var packet = new Packets.PedKilled();
|
||||
packet.Deserialize(data);
|
||||
HandlePedKilled(packet);
|
||||
HandlePedKilled(msg.GetPacket<Packets.PedKilled>());
|
||||
}
|
||||
break;
|
||||
case PacketType.NozzleTransform:
|
||||
{
|
||||
var packet = new Packets.NozzleTransform();
|
||||
packet.Deserialize(data);
|
||||
HandleNozzleTransform(packet);
|
||||
HandleNozzleTransform(msg.GetPacket<Packets.NozzleTransform>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
Networking.Peer.Recycle(msg);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -1,6 +1,5 @@
|
||||
using System.Threading;
|
||||
|
||||
using NAudio.Wave;
|
||||
using NAudio.Wave;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
|
64
RageCoop.Client/Util/AddOnDataProvider.cs
Normal file
64
RageCoop.Client/Util/AddOnDataProvider.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using GTA;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Class providing support for addon mods
|
||||
/// </summary>
|
||||
internal class AddOnDataProvider
|
||||
{
|
||||
public static int GetMuzzleIndex(Model model)
|
||||
{
|
||||
switch (model.Hash)
|
||||
{
|
||||
// f14a2
|
||||
case -848721350:
|
||||
return 48;
|
||||
|
||||
// f15e
|
||||
case 881261972:
|
||||
return 32;
|
||||
|
||||
// f16c
|
||||
case -2051171080:
|
||||
return 25;
|
||||
|
||||
// F22A
|
||||
case 2061630439:
|
||||
return 14;
|
||||
|
||||
// f35c
|
||||
case -343547392:
|
||||
return 44;
|
||||
|
||||
// mig29a
|
||||
case 513887552:
|
||||
return 18;
|
||||
|
||||
// su30sm
|
||||
case -733985185:
|
||||
return 34;
|
||||
|
||||
// su33
|
||||
case -722216722:
|
||||
return 34;
|
||||
|
||||
// su35s
|
||||
case -268602544:
|
||||
return 28;
|
||||
|
||||
// su57
|
||||
case 1490050781:
|
||||
return 21;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,19 @@
|
||||
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using RageCoop.Core;
|
||||
using SHVDN;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GTA.Math;
|
||||
using GTA;
|
||||
using SHVDN;
|
||||
using RageCoop.Core;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal unsafe class MemPatch{
|
||||
private byte[] _data;
|
||||
private byte[] _orginal;
|
||||
private IntPtr _address;
|
||||
internal unsafe class MemPatch
|
||||
{
|
||||
private readonly byte[] _data;
|
||||
private readonly byte[] _orginal;
|
||||
private readonly IntPtr _address;
|
||||
public MemPatch(byte* address, byte[] data)
|
||||
{
|
||||
_data = data;
|
||||
@ -68,8 +69,8 @@ internal static unsafe class Memory
|
||||
public const int MatrixOffset = 96;
|
||||
#endregion
|
||||
#region OPCODE
|
||||
const byte XOR_32_64 = 0x31;
|
||||
const byte RET = 0xC3;
|
||||
private const byte XOR_32_64 = 0x31;
|
||||
private const byte RET = 0xC3;
|
||||
#endregion
|
||||
public static Vector3 ReadPosition(this Entity e) => ReadVector3(e.MemoryAddress + PositionOffset);
|
||||
public static Quaternion ReadQuaternion(this Entity e) => Quaternion.RotationMatrix(e.Matrix);
|
||||
|
@ -1,14 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using GTA.Math;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LemonUI.Elements;
|
||||
using System.Drawing;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -68,16 +61,16 @@ namespace RageCoop.Client
|
||||
{
|
||||
// These are borrowed from ScriptHookVDotNet's
|
||||
[DllImport("ScriptHookV.dll", ExactSpelling = true, EntryPoint = "?nativeInit@@YAX_K@Z")]
|
||||
static extern void NativeInit(ulong hash);
|
||||
private static extern void NativeInit(ulong hash);
|
||||
|
||||
[DllImport("ScriptHookV.dll", ExactSpelling = true, EntryPoint = "?nativePush64@@YAX_K@Z")]
|
||||
static extern void NativePush64(ulong val);
|
||||
private static extern void NativePush64(ulong val);
|
||||
|
||||
[DllImport("ScriptHookV.dll", ExactSpelling = true, EntryPoint = "?nativeCall@@YAPEA_KXZ")]
|
||||
static extern unsafe ulong* NativeCall();
|
||||
private static extern unsafe ulong* NativeCall();
|
||||
|
||||
// These are from ScriptHookV's nativeCaller.h
|
||||
static unsafe void NativePush<T>(T val) where T : unmanaged
|
||||
private static unsafe void NativePush<T>(T val) where T : unmanaged
|
||||
{
|
||||
ulong val64 = 0;
|
||||
*(T*)(&val64) = val;
|
||||
@ -106,7 +99,7 @@ namespace RageCoop.Client
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
static unsafe ulong[] ConvertPrimitiveArguments(object[] args)
|
||||
private static unsafe ulong[] ConvertPrimitiveArguments(object[] args)
|
||||
{
|
||||
var result = new ulong[args.Length];
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
@ -118,7 +111,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
if (args[i] is byte valueByte)
|
||||
{
|
||||
result[i] = (ulong)valueByte;
|
||||
result[i] = valueByte;
|
||||
continue;
|
||||
}
|
||||
if (args[i] is int valueInt32)
|
||||
|
@ -2,8 +2,8 @@
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using RageCoop.Core;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -146,7 +146,8 @@ namespace RageCoop.Client
|
||||
{
|
||||
flags |= PedDataFlags.IsInCover;
|
||||
}
|
||||
if (!Function.Call<bool>(Hash.IS_PED_IN_HIGH_COVER, ped)){
|
||||
if (!Function.Call<bool>(Hash.IS_PED_IN_HIGH_COVER, ped))
|
||||
{
|
||||
flags |= PedDataFlags.IsInLowCover;
|
||||
}
|
||||
if (ped.IsTaskActive(TaskType.CTaskAimGunBlindFire))
|
||||
@ -155,6 +156,11 @@ namespace RageCoop.Client
|
||||
}
|
||||
}
|
||||
|
||||
if (ped.IsInvincible)
|
||||
{
|
||||
flags |= PedDataFlags.IsInvincible;
|
||||
}
|
||||
|
||||
if (Function.Call<bool>(Hash.GET_PED_STEALTH_MOVEMENT, ped))
|
||||
{
|
||||
flags |= PedDataFlags.IsInStealthMode;
|
||||
@ -290,7 +296,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
else if (veh.GetPedOnSeat(seat) != null)
|
||||
{
|
||||
|
||||
bool isDead = veh.GetPedOnSeat(seat).IsDead;
|
||||
|
@ -6,13 +6,12 @@ using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml.Serialization;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[assembly: InternalsVisibleTo("RageCoop.Client.Installer")]
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class Util
|
||||
@ -112,11 +111,11 @@ namespace RageCoop.Client
|
||||
|
||||
#endregion
|
||||
public static string SettingsPath = "Scripts\\RageCoop\\Data\\RageCoop.Client.Settings.xml";
|
||||
public static Settings ReadSettings()
|
||||
public static Settings ReadSettings(string path = null)
|
||||
{
|
||||
path = path ?? SettingsPath;
|
||||
XmlSerializer ser = new XmlSerializer(typeof(Settings));
|
||||
|
||||
string path = SettingsPath;
|
||||
Directory.CreateDirectory(Directory.GetParent(path).FullName);
|
||||
Settings settings = null;
|
||||
|
||||
@ -124,12 +123,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
using (FileStream stream = File.OpenRead(path))
|
||||
{
|
||||
settings = (RageCoop.Client.Settings)ser.Deserialize(stream);
|
||||
}
|
||||
|
||||
using (FileStream stream = new FileStream(path, FileMode.Truncate, FileAccess.ReadWrite))
|
||||
{
|
||||
ser.Serialize(stream, settings);
|
||||
settings = (Settings)ser.Deserialize(stream);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -142,22 +136,25 @@ namespace RageCoop.Client
|
||||
|
||||
return settings;
|
||||
}
|
||||
public static void SaveSettings()
|
||||
public static bool SaveSettings(string path = null, Settings settings = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
string path = SettingsPath;
|
||||
path = path ?? SettingsPath;
|
||||
settings = settings ?? Main.Settings;
|
||||
Directory.CreateDirectory(Directory.GetParent(path).FullName);
|
||||
|
||||
using (FileStream stream = new FileStream(path, File.Exists(path) ? FileMode.Truncate : FileMode.Create, FileAccess.ReadWrite))
|
||||
{
|
||||
XmlSerializer ser = new XmlSerializer(typeof(Settings));
|
||||
ser.Serialize(stream, Main.Settings);
|
||||
ser.Serialize(stream, settings);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GTA.UI.Notification.Show("Error saving player settings: " + ex.Message);
|
||||
return false;
|
||||
// GTA.UI.Notification.Show("Error saving player settings: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,7 +216,7 @@ namespace RageCoop.Client
|
||||
|
||||
#region WIN32
|
||||
|
||||
const UInt32 WM_KEYDOWN = 0x0100;
|
||||
private const UInt32 WM_KEYDOWN = 0x0100;
|
||||
public static void Reload()
|
||||
{
|
||||
string reloadKey = "None";
|
||||
@ -238,6 +235,7 @@ namespace RageCoop.Client
|
||||
foreach (var l in lines)
|
||||
{
|
||||
var ss = l.Split('=');
|
||||
ss.ForEach(s => s.Replace(" ", ""));
|
||||
if (ss.Length > 0 && ss[0] == "ReloadKey")
|
||||
{
|
||||
reloadKey = ss[1];
|
||||
@ -268,7 +266,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
|
||||
private static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
|
||||
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
|
@ -50,47 +50,54 @@ namespace RageCoop.Client
|
||||
flags |= VehicleDataFlags.IsHornActive;
|
||||
}
|
||||
|
||||
if (v.IsSubmarineCar && Function.Call<bool>(Hash._GET_IS_SUBMARINE_VEHICLE_TRANSFORMED, veh.Handle))
|
||||
if (v.IsSubmarineCar && Function.Call<bool>(Hash.IS_VEHICLE_IN_SUBMARINE_MODE, veh.Handle))
|
||||
{
|
||||
flags |= VehicleDataFlags.IsTransformed;
|
||||
}
|
||||
|
||||
if (v.IsAircraft)
|
||||
{
|
||||
flags |= VehicleDataFlags.IsAircraft;
|
||||
}
|
||||
|
||||
if (v.IsDeluxo && veh.IsDeluxoHovering())
|
||||
{
|
||||
flags |= VehicleDataFlags.IsDeluxoHovering;
|
||||
}
|
||||
|
||||
if (v.HasRoof)
|
||||
{
|
||||
flags |= VehicleDataFlags.HasRoof;
|
||||
}
|
||||
|
||||
if (v.HasRocketBoost && veh.IsRocketBoostActive())
|
||||
{
|
||||
flags |= VehicleDataFlags.IsRocketBoostActive;
|
||||
}
|
||||
if(v.HasParachute && veh.IsParachuteActive()){
|
||||
|
||||
if (v.HasParachute && veh.IsParachuteActive())
|
||||
{
|
||||
flags |= VehicleDataFlags.IsParachuteActive;
|
||||
}
|
||||
|
||||
if (veh.IsOnFire)
|
||||
{
|
||||
flags |= VehicleDataFlags.IsOnFire;
|
||||
}
|
||||
|
||||
|
||||
return flags;
|
||||
}
|
||||
public static bool IsRocketBoostActive(this Vehicle veh)
|
||||
{
|
||||
return Function.Call<bool>(Hash._IS_VEHICLE_ROCKET_BOOST_ACTIVE,veh);
|
||||
return Function.Call<bool>(Hash.IS_ROCKET_BOOST_ACTIVE, veh);
|
||||
}
|
||||
public static bool IsParachuteActive(this Vehicle veh){
|
||||
public static bool IsParachuteActive(this Vehicle veh)
|
||||
{
|
||||
return Function.Call<bool>((Hash)0x3DE51E9C80B116CF, veh);
|
||||
}
|
||||
public static void SetRocketBoostActive(this Vehicle veh, bool toggle)
|
||||
{
|
||||
Function.Call(Hash._SET_VEHICLE_ROCKET_BOOST_ACTIVE,veh,toggle);
|
||||
Function.Call(Hash.SET_ROCKET_BOOST_ACTIVE, veh, toggle);
|
||||
}
|
||||
public static void SetParachuteActive(this Vehicle veh, bool toggle)
|
||||
{
|
||||
@ -133,7 +140,6 @@ namespace RageCoop.Client
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Bursted tires
|
||||
short burstedTires = 0;
|
||||
foreach (VehicleWheel wheel in veh.Wheels.GetAllWheels())
|
||||
@ -228,16 +234,15 @@ namespace RageCoop.Client
|
||||
{
|
||||
if (p.IsSittingInVehicle())
|
||||
{
|
||||
ps.Add((int)p.SeatIndex, (int)p.GetSyncEntity().ID);
|
||||
ps.Add((int)p.SeatIndex, p.GetSyncEntity().ID);
|
||||
}
|
||||
}
|
||||
return ps;
|
||||
}
|
||||
|
||||
|
||||
public static void SetDeluxoHoverState(this Vehicle deluxo, bool hover)
|
||||
{
|
||||
Function.Call(Hash._SET_VEHICLE_HOVER_TRANSFORM_PERCENTAGE, deluxo, hover ? 1f : 0f);
|
||||
Function.Call(Hash.SET_SPECIAL_FLIGHT_MODE_TARGET_RATIO, deluxo, hover ? 1f : 0f);
|
||||
}
|
||||
public static bool IsDeluxoHovering(this Vehicle deluxo)
|
||||
{
|
||||
@ -245,7 +250,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
public static void SetDeluxoWingRatio(this Vehicle v, float ratio)
|
||||
{
|
||||
Function.Call(Hash._SET_SPECIALFLIGHT_WING_RATIO, v, ratio);
|
||||
Function.Call(Hash.SET_HOVER_MODE_WING_RATIO, v, ratio);
|
||||
}
|
||||
public static float GetDeluxoWingRatio(this Vehicle v)
|
||||
{
|
||||
@ -253,7 +258,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
public static float GetNozzleAngel(this Vehicle plane)
|
||||
{
|
||||
return Function.Call<float>(Hash._GET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane);
|
||||
return Function.Call<float>(Hash.GET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane);
|
||||
}
|
||||
public static bool HasNozzle(this Vehicle v)
|
||||
{
|
||||
@ -283,8 +288,6 @@ namespace RageCoop.Client
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane, ratio);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -46,7 +45,8 @@ namespace RageCoop.Client
|
||||
}
|
||||
return p.Bones[Bone.SkelRightHand].Position;
|
||||
}
|
||||
static long BulletsShot = 0;
|
||||
|
||||
private static long BulletsShot = 0;
|
||||
|
||||
public static float GetWeaponDamage(this Ped P, uint hash)
|
||||
{
|
||||
@ -362,7 +362,7 @@ namespace RageCoop.Client
|
||||
return 30;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
return AddOnDataProvider.GetMuzzleIndex(v.Model.Hash);
|
||||
}
|
||||
}
|
||||
public static bool IsUsingProjectileWeapon(this Ped p)
|
||||
@ -371,18 +371,12 @@ namespace RageCoop.Client
|
||||
var type = Function.Call<int>(Hash.GET_WEAPON_DAMAGE_TYPE, vp);
|
||||
if (vp != VehicleWeaponHash.Invalid)
|
||||
{
|
||||
if (type==3)
|
||||
{
|
||||
return false;
|
||||
return type == 3 ? false : VehicleProjectileWeapons.Contains(vp) || (type == 5 && !ExplosiveBullets.Contains((uint)vp));
|
||||
}
|
||||
return VehicleProjectileWeapons.Contains(vp) || (type==5 && !ExplosiveBullets.Contains((uint)vp));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var w = p.Weapons.Current;
|
||||
return w.Group == WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly HashSet<uint> ExplosiveBullets = new HashSet<uint>
|
||||
{
|
||||
@ -460,7 +454,6 @@ namespace RageCoop.Client
|
||||
|
||||
};
|
||||
|
||||
|
||||
public static readonly HashSet<WeaponHash> ProjectileWeapons = new HashSet<WeaponHash> {
|
||||
WeaponHash.HomingLauncher,
|
||||
WeaponHash.RPG,
|
||||
|
@ -9,7 +9,6 @@ namespace RageCoop.Client
|
||||
/// </summary>
|
||||
public class WorldThread : Script
|
||||
{
|
||||
private static bool _lastDisableTraffic = false;
|
||||
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
@ -19,13 +18,11 @@ namespace RageCoop.Client
|
||||
Tick += OnTick;
|
||||
Aborted += (sender, e) =>
|
||||
{
|
||||
if (_lastDisableTraffic)
|
||||
{
|
||||
Traffic(true);
|
||||
}
|
||||
ChangeTraffic(true);
|
||||
};
|
||||
}
|
||||
|
||||
private static bool _trafficEnabled;
|
||||
private void OnTick(object sender, EventArgs e)
|
||||
{
|
||||
if (Game.IsLoading || !Networking.IsOnServer)
|
||||
@ -34,28 +31,42 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
Game.DisableControlThisFrame(Control.FrontendPause);
|
||||
Game.DisableControlThisFrame(Control.VehicleExit);
|
||||
Game.DisableControlThisFrame(Control.Enter);
|
||||
|
||||
if (Main.Settings.DisableAlternatePause)
|
||||
{
|
||||
Game.DisableControlThisFrame(Control.FrontendPauseAlternate);
|
||||
}
|
||||
var P = Game.Player.Character;
|
||||
|
||||
// Sets a value that determines how aggressive the ocean waves will be.
|
||||
// Values of 2.0 or more make for very aggressive waves like you see during a thunderstorm.
|
||||
Function.Call(Hash.SET_DEEP_OCEAN_SCALER, 0.0f); // Works only ~200 meters around the player
|
||||
|
||||
// Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, Game.Player.Character.Handle, true, false);
|
||||
if (Main.Settings==null) { return; }
|
||||
if (Main.Settings.DisableTraffic)
|
||||
if (Main.Settings.ShowEntityOwnerName)
|
||||
{
|
||||
if (!_lastDisableTraffic)
|
||||
unsafe
|
||||
{
|
||||
Traffic(false);
|
||||
int handle;
|
||||
if (Function.Call<bool>(Hash.GET_ENTITY_PLAYER_IS_FREE_AIMING_AT, 0, &handle))
|
||||
{
|
||||
var entity = Entity.FromHandle(handle);
|
||||
if (entity != null)
|
||||
{
|
||||
var owner = "invalid";
|
||||
if (entity.EntityType == EntityType.Vehicle)
|
||||
{
|
||||
owner = (entity as Vehicle).GetSyncEntity()?.Owner?.Username ?? "unknown";
|
||||
}
|
||||
if (entity.EntityType == EntityType.Ped)
|
||||
{
|
||||
owner = (entity as Ped).GetSyncEntity()?.Owner?.Username ?? "unknown";
|
||||
}
|
||||
GTA.UI.Screen.ShowHelpTextThisFrame("Entity owner: " + owner);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!_trafficEnabled)
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 0);
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
|
||||
Function.Call(Hash.SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
|
||||
@ -64,15 +75,13 @@ namespace RageCoop.Client
|
||||
Function.Call(Hash.SUPPRESS_SHOCKING_EVENTS_NEXT_FRAME);
|
||||
Function.Call(Hash.SUPPRESS_AGITATION_EVENTS_NEXT_FRAME);
|
||||
}
|
||||
else if (_lastDisableTraffic)
|
||||
{
|
||||
Traffic(true);
|
||||
}
|
||||
|
||||
_lastDisableTraffic = Main.Settings.DisableTraffic;
|
||||
}
|
||||
|
||||
public static void Traffic(bool enable)
|
||||
{
|
||||
ChangeTraffic(enable);
|
||||
_trafficEnabled = enable;
|
||||
}
|
||||
private static void ChangeTraffic(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
@ -81,15 +90,15 @@ namespace RageCoop.Client
|
||||
Function.Call(Hash.SET_RANDOM_TRAINS, true);
|
||||
Function.Call(Hash.SET_RANDOM_BOATS, true);
|
||||
Function.Call(Hash.SET_GARBAGE_TRUCKS, true);
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 1); // 0 - 3
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 1); // 0 - 3
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 3); // 0 - 3
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 3); // 0 - 3
|
||||
Function.Call(Hash.SET_ALL_VEHICLE_GENERATORS_ACTIVE);
|
||||
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, true);
|
||||
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, -1);
|
||||
Function.Call(Hash.SET_DISTANT_CARS_ENABLED, true);
|
||||
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, false);
|
||||
}
|
||||
else
|
||||
else if (Networking.IsOnServer)
|
||||
{
|
||||
Function.Call(Hash.ADD_SCENARIO_BLOCKING_AREA, -10000.0f, -10000.0f, -1000.0f, 10000.0f, 10000.0f, 1000.0f, 0, 1, 1, 1);
|
||||
Function.Call(Hash.SET_CREATE_RANDOM_COPS, false);
|
||||
@ -97,34 +106,31 @@ namespace RageCoop.Client
|
||||
Function.Call(Hash.SET_RANDOM_BOATS, false);
|
||||
Function.Call(Hash.SET_GARBAGE_TRUCKS, false);
|
||||
Function.Call(Hash.DELETE_ALL_TRAINS);
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 3);
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 3);
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 0);
|
||||
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, false);
|
||||
Function.Call(Hash.SET_FAR_DRAW_VEHICLES, false);
|
||||
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, 0);
|
||||
Function.Call(Hash.SET_DISTANT_CARS_ENABLED, false);
|
||||
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, true);
|
||||
|
||||
|
||||
foreach (Ped ped in World.GetAllPeds())
|
||||
{
|
||||
if (ped == Game.Player.Character) { continue; }
|
||||
SyncedPed c = EntityPool.GetPedByHandle(ped.Handle);
|
||||
if ((c == null) || (c.IsLocal && (ped.Handle != Game.Player.Character.Handle) && ped.PopulationType != EntityPopulationType.Mission))
|
||||
{
|
||||
if (ped.Handle==Game.Player.Character.Handle) { continue; }
|
||||
|
||||
// Main.Logger.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
|
||||
ped.CurrentVehicle?.Delete();
|
||||
ped.Kill();
|
||||
ped.Delete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
foreach (Vehicle veh in World.GetAllVehicles())
|
||||
{
|
||||
SyncedVehicle v = veh.GetSyncEntity();
|
||||
if (v.MainVehicle==Game.Player.LastVehicle)
|
||||
if (v.MainVehicle == Game.Player.LastVehicle || v.MainVehicle == Game.Player.Character.CurrentVehicle)
|
||||
{
|
||||
// Don't delete player's vehicle
|
||||
continue;
|
||||
|
@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using GTA.Math;
|
||||
using GTA.Math;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
|
@ -1,20 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA.Math;
|
||||
using System.Security.Cryptography;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Sockets;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
[assembly: InternalsVisibleTo("RageCoop.Server")]
|
||||
[assembly: InternalsVisibleTo("RageCoop.Client")]
|
||||
[assembly: InternalsVisibleTo("RageCoop.Client.Installer")]
|
||||
[assembly: InternalsVisibleTo("RageCoop.ResourceBuilder")]
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
internal static class CoreUtils
|
||||
@ -31,43 +34,44 @@ namespace RageCoop.Core
|
||||
{
|
||||
return ToIgnore.Contains(name);
|
||||
}
|
||||
public static (byte, byte[]) GetBytesFromObject(object obj)
|
||||
public static void GetBytesFromObject(object obj, NetOutgoingMessage m)
|
||||
{
|
||||
switch (obj)
|
||||
{
|
||||
case byte _:
|
||||
return (0x01, new byte[] { (byte)obj });
|
||||
case short _:
|
||||
return (0x02, BitConverter.GetBytes((short)obj));
|
||||
case ushort _:
|
||||
return (0x03, BitConverter.GetBytes((ushort)obj));
|
||||
case int _:
|
||||
return (0x04, BitConverter.GetBytes((int)obj));
|
||||
case uint _:
|
||||
return (0x05, BitConverter.GetBytes((uint)obj));
|
||||
case long _:
|
||||
return (0x06, BitConverter.GetBytes((long)obj));
|
||||
case ulong _:
|
||||
return (0x07, BitConverter.GetBytes((ulong)obj));
|
||||
case float _:
|
||||
return (0x08, BitConverter.GetBytes((float)obj));
|
||||
case bool _:
|
||||
return (0x09, BitConverter.GetBytes((bool)obj));
|
||||
case string _:
|
||||
return (0x10, ((string)obj).GetBytesWithLength());
|
||||
case Vector3 _:
|
||||
return (0x11,((Vector3)obj).GetBytes());
|
||||
case Quaternion _:
|
||||
return (0x12, ((Quaternion)obj).GetBytes());
|
||||
case GTA.Model _:
|
||||
return (0x13, BitConverter.GetBytes((GTA.Model)obj));
|
||||
case Vector2 _:
|
||||
return (0x14, ((Vector2)obj).GetBytes());
|
||||
case Tuple<byte, byte[]> _:
|
||||
var tup = (Tuple<byte, byte[]>)obj;
|
||||
return (tup.Item1, tup.Item2);
|
||||
case byte value:
|
||||
m.Write((byte)0x01); m.Write(value); break;
|
||||
case short value:
|
||||
m.Write((byte)0x02); m.Write(value); break;
|
||||
case ushort value:
|
||||
m.Write((byte)0x03); m.Write(value); break;
|
||||
case int value:
|
||||
m.Write((byte)0x04); m.Write(value); break;
|
||||
case uint value:
|
||||
m.Write((byte)0x05); m.Write(value); break;
|
||||
case long value:
|
||||
m.Write((byte)0x06); m.Write(value); break;
|
||||
case ulong value:
|
||||
m.Write((byte)0x07); m.Write(value); break;
|
||||
case float value:
|
||||
m.Write((byte)0x08); m.Write(value); break;
|
||||
case bool value:
|
||||
m.Write((byte)0x09); m.Write(value); break;
|
||||
case string value:
|
||||
m.Write((byte)0x10); m.Write(value); break;
|
||||
case Vector3 value:
|
||||
m.Write((byte)0x11); m.Write(value); break;
|
||||
case Quaternion value:
|
||||
m.Write((byte)0x12); m.Write(value); break;
|
||||
case GTA.Model value:
|
||||
m.Write((byte)0x13); m.Write(value); break;
|
||||
case Vector2 value:
|
||||
m.Write((byte)0x14); m.Write(value); break;
|
||||
case byte[] value:
|
||||
m.Write((byte)0x15); m.WriteByteArray(value); break;
|
||||
case Tuple<byte, byte[]> value:
|
||||
m.Write(value.Item1); m.Write(value.Item2); break;
|
||||
default:
|
||||
return (0x0, null);
|
||||
throw new Exception("Unsupported object type: " + obj.GetType());
|
||||
}
|
||||
}
|
||||
public static IPEndPoint StringToEndPoint(string endpointstring)
|
||||
@ -134,9 +138,8 @@ namespace RageCoop.Core
|
||||
|
||||
private static int getPort(string p)
|
||||
{
|
||||
int port;
|
||||
|
||||
if (!int.TryParse(p, out port)
|
||||
if (!int.TryParse(p, out int port)
|
||||
|| port < IPEndPoint.MinPort
|
||||
|| port > IPEndPoint.MaxPort)
|
||||
{
|
||||
@ -181,10 +184,49 @@ namespace RageCoop.Core
|
||||
return JsonConvert.DeserializeObject<IpInfo>(content);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target)
|
||||
{
|
||||
foreach (DirectoryInfo dir in source.GetDirectories())
|
||||
CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
|
||||
foreach (FileInfo file in source.GetFiles())
|
||||
file.CopyTo(Path.Combine(target.FullName, file.Name), true);
|
||||
}
|
||||
internal struct IpInfo
|
||||
public static string GetInvariantRID()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return "win-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
|
||||
}
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
return "linux-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
|
||||
}
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
return "osx-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get local ip addresses on all network interfaces
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<IPAddress> GetLocalAddress()
|
||||
{
|
||||
var addresses = new List<IPAddress>();
|
||||
foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
|
||||
{
|
||||
IPInterfaceProperties ipProps = netInterface.GetIPProperties();
|
||||
foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
|
||||
{
|
||||
addresses.Add(addr.Address);
|
||||
}
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
}
|
||||
internal class IpInfo
|
||||
{
|
||||
[JsonProperty("ip")]
|
||||
public string Address { get; set; }
|
||||
@ -194,74 +236,10 @@ namespace RageCoop.Core
|
||||
}
|
||||
internal static class Extensions
|
||||
{
|
||||
public static void AddVector3(this List<byte> bytes, Vector3 vec3)
|
||||
{
|
||||
bytes.AddRange(BitConverter.GetBytes(vec3.X));
|
||||
bytes.AddRange(BitConverter.GetBytes(vec3.Y));
|
||||
bytes.AddRange(BitConverter.GetBytes(vec3.Z));
|
||||
}
|
||||
public static void AddQuaternion(this List<byte> bytes, Quaternion quat)
|
||||
{
|
||||
bytes.AddRange(BitConverter.GetBytes(quat.X));
|
||||
bytes.AddRange(BitConverter.GetBytes(quat.Y));
|
||||
bytes.AddRange(BitConverter.GetBytes(quat.Z));
|
||||
bytes.AddRange(BitConverter.GetBytes(quat.W));
|
||||
}
|
||||
public static void AddInt(this List<byte> bytes,int i)
|
||||
{
|
||||
bytes.AddRange(BitConverter.GetBytes(i));
|
||||
}
|
||||
public static void AddUint(this List<byte> bytes, uint i)
|
||||
{
|
||||
bytes.AddRange(BitConverter.GetBytes(i));
|
||||
}
|
||||
public static void AddShort(this List<byte> bytes, short i)
|
||||
{
|
||||
bytes.AddRange(BitConverter.GetBytes(i));
|
||||
}
|
||||
public static void AddUshort(this List<byte> bytes, ushort i)
|
||||
{
|
||||
bytes.AddRange(BitConverter.GetBytes(i));
|
||||
}
|
||||
public static void AddLong(this List<byte> bytes, long i)
|
||||
{
|
||||
bytes.AddRange(BitConverter.GetBytes(i));
|
||||
}
|
||||
public static void AddUlong(this List<byte> bytes, ulong i)
|
||||
{
|
||||
bytes.AddRange(BitConverter.GetBytes(i));
|
||||
}
|
||||
public static void AddFloat(this List<byte> bytes, float i)
|
||||
{
|
||||
bytes.AddRange(BitConverter.GetBytes(i));
|
||||
}
|
||||
public static void AddBool(this List<byte> bytes, bool b)
|
||||
{
|
||||
bytes.Add(b? (byte)1 :(byte)0);
|
||||
}
|
||||
public static void AddString(this List<byte> bytes, string s)
|
||||
{
|
||||
var sb = Encoding.UTF8.GetBytes(s);
|
||||
bytes.AddInt(sb.Length);
|
||||
bytes.AddRange(sb);
|
||||
}
|
||||
public static void AddArray(this List<byte> bytes, byte[] toadd)
|
||||
{
|
||||
bytes.AddInt(toadd.Length);
|
||||
bytes.AddRange(toadd);
|
||||
}
|
||||
public static byte[] GetBytes(this string s)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(s);
|
||||
}
|
||||
public static byte[] GetBytesWithLength(this string s)
|
||||
{
|
||||
var data = new List<byte>(100);
|
||||
var sb = Encoding.UTF8.GetBytes(s);
|
||||
data.AddInt(sb.Length);
|
||||
data.AddRange(sb);
|
||||
return data.ToArray();
|
||||
}
|
||||
public static string GetString(this byte[] data)
|
||||
{
|
||||
return Encoding.UTF8.GetString(data);
|
||||
@ -288,17 +266,10 @@ namespace RageCoop.Core
|
||||
// 16 bytes
|
||||
return new List<byte[]>() { BitConverter.GetBytes(qua.X), BitConverter.GetBytes(qua.Y), BitConverter.GetBytes(qua.Z), BitConverter.GetBytes(qua.W) }.Join(4);
|
||||
}
|
||||
|
||||
|
||||
public static T GetPacket<T>(this NetIncomingMessage msg, T existingPacket = null) where T : Packet, new()
|
||||
public static T GetPacket<T>(this NetIncomingMessage msg) where T : Packet, new()
|
||||
{
|
||||
msg.ReadByte();
|
||||
return GetPacket<T>(msg.ReadBytes(msg.ReadInt32()),existingPacket);
|
||||
}
|
||||
public static T GetPacket<T>(this byte[] data, T existingPacket=null) where T : Packet, new()
|
||||
{
|
||||
var p = existingPacket??new T();
|
||||
p.Deserialize(data);
|
||||
var p = new T();
|
||||
p.Deserialize(msg);
|
||||
return p;
|
||||
}
|
||||
public static bool HasPedFlag(this PedDataFlags flagToCheck, PedDataFlags flag)
|
||||
@ -391,7 +362,7 @@ namespace RageCoop.Core
|
||||
}
|
||||
public static string Dump<T>(this IEnumerable<T> objects)
|
||||
{
|
||||
return "{"+string.Join(",",objects)+"}";
|
||||
return $"{{{string.Join(",", objects)}}}";
|
||||
}
|
||||
public static void ForEach<T>(this IEnumerable<T> objects, Action<T> action)
|
||||
{
|
||||
@ -411,6 +382,12 @@ namespace RageCoop.Core
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
public static MemoryStream ToMemStream(this Stream stream)
|
||||
{
|
||||
var memoryStream = new MemoryStream();
|
||||
stream.CopyTo(memoryStream);
|
||||
return memoryStream;
|
||||
}
|
||||
public static byte[] Join(this List<byte[]> arrays, int lengthPerArray = -1)
|
||||
{
|
||||
if (arrays.Count == 1) { return arrays[0]; }
|
||||
@ -468,5 +445,6 @@ namespace RageCoop.Core
|
||||
{
|
||||
return IPAddress.Parse(ip);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -32,9 +31,9 @@ namespace RageCoop.Core
|
||||
private StreamWriter logWriter;
|
||||
|
||||
private string Buffer = "";
|
||||
private Thread LoggerThread;
|
||||
private readonly Thread LoggerThread;
|
||||
private bool Stopping = false;
|
||||
private bool FlushImmediately;
|
||||
private readonly bool FlushImmediately;
|
||||
|
||||
internal Logger(bool flushImmediately = false, bool overwrite = true)
|
||||
{
|
||||
|
@ -1,9 +1,8 @@
|
||||
using System;
|
||||
using GTA.Math;
|
||||
using GTA.Math;
|
||||
using System;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
|
||||
internal static class MathExtensions
|
||||
{
|
||||
public const float Deg2Rad = (float)(Math.PI * 2) / 360;
|
||||
@ -82,14 +81,14 @@ namespace RageCoop.Core
|
||||
vect = vect.ToRadians();
|
||||
|
||||
float rollOver2 = vect.Z * 0.5f;
|
||||
float sinRollOver2 = (float)Math.Sin((double)rollOver2);
|
||||
float cosRollOver2 = (float)Math.Cos((double)rollOver2);
|
||||
float sinRollOver2 = (float)Math.Sin(rollOver2);
|
||||
float cosRollOver2 = (float)Math.Cos(rollOver2);
|
||||
float pitchOver2 = vect.Y * 0.5f;
|
||||
float sinPitchOver2 = (float)Math.Sin((double)pitchOver2);
|
||||
float cosPitchOver2 = (float)Math.Cos((double)pitchOver2);
|
||||
float sinPitchOver2 = (float)Math.Sin(pitchOver2);
|
||||
float cosPitchOver2 = (float)Math.Cos(pitchOver2);
|
||||
float yawOver2 = vect.X * 0.5f; // pitch
|
||||
float sinYawOver2 = (float)Math.Sin((double)yawOver2);
|
||||
float cosYawOver2 = (float)Math.Cos((double)yawOver2);
|
||||
float sinYawOver2 = (float)Math.Sin(yawOver2);
|
||||
float cosYawOver2 = (float)Math.Cos(yawOver2);
|
||||
Quaternion result = new Quaternion()
|
||||
{
|
||||
X = cosYawOver2 * cosPitchOver2 * cosRollOver2 + sinYawOver2 * sinPitchOver2 * sinRollOver2,
|
||||
@ -146,16 +145,12 @@ namespace RageCoop.Core
|
||||
}
|
||||
private static float CopySign(double x, double y)
|
||||
{
|
||||
bool isPositive = y>=0;
|
||||
if (isPositive)
|
||||
if (y >= 0)
|
||||
{
|
||||
if (x>=0) { return (float)x; } else { return (float)-x; }
|
||||
return x >= 0 ? (float)x : (float)-x;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x>=0) { return (float)-x; } else { return (float)x; }
|
||||
|
||||
}
|
||||
return x >= 0 ? (float)-x : (float)x;
|
||||
}
|
||||
public static double AngelTo(this Vector3 v1, Vector3 v2)
|
||||
{
|
||||
@ -163,7 +158,6 @@ namespace RageCoop.Core
|
||||
}
|
||||
public static float GetCosTheta(this Vector3 v1, Vector3 v2)
|
||||
{
|
||||
|
||||
return Vector3.Dot(v1, v2) / (v1.Length() * v2.Length());
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Lidgren.Network;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -57,6 +56,5 @@ namespace RageCoop.Core
|
||||
p.Pack(outgoingMessage);
|
||||
SendMessage(outgoingMessage, cons, method, (int)channel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
42
RageCoop.Core/Networking/HttpHelper.cs
Normal file
42
RageCoop.Core/Networking/HttpHelper.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
internal static class HttpHelper
|
||||
{
|
||||
public static void DownloadFile(string url, string destination, Action<int> progressCallback)
|
||||
{
|
||||
if (File.Exists(destination)) { File.Delete(destination); }
|
||||
AutoResetEvent ae = new AutoResetEvent(false);
|
||||
WebClient client = new WebClient();
|
||||
|
||||
// TLS only
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
|
||||
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||
|
||||
client.DownloadProgressChanged += (s, e1) => progressCallback?.Invoke(e1.ProgressPercentage);
|
||||
client.DownloadFileCompleted += (s, e2) =>
|
||||
{
|
||||
ae.Set();
|
||||
};
|
||||
client.DownloadFileAsync(new Uri(url), destination);
|
||||
ae.WaitOne();
|
||||
}
|
||||
public static string DownloadString(string url)
|
||||
{
|
||||
// TLS only
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 |
|
||||
SecurityProtocolType.Tls11 |
|
||||
SecurityProtocolType.Tls;
|
||||
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||
|
||||
WebClient client = new WebClient();
|
||||
return client.DownloadString(url);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Lidgren.Network;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
internal class PublicKey{
|
||||
public PublicKey(){
|
||||
internal class PublicKey
|
||||
{
|
||||
public PublicKey()
|
||||
{
|
||||
|
||||
}
|
||||
public static PublicKey FromServerInfo(ServerInfo info){
|
||||
return new PublicKey{
|
||||
public static PublicKey FromServerInfo(ServerInfo info)
|
||||
{
|
||||
return new PublicKey
|
||||
{
|
||||
Modulus = Convert.FromBase64String(info.publicKeyModulus),
|
||||
Exponent = Convert.FromBase64String(info.publicKeyExponent)
|
||||
};
|
||||
|
@ -1,13 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace RageCoop.Core
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
|
||||
internal class ServerInfo
|
||||
/// <summary>
|
||||
/// A json object representing a server's information as annouced to master server.
|
||||
/// </summary>
|
||||
public class ServerInfo
|
||||
{
|
||||
#pragma warning disable 1591
|
||||
public string address { get; set; }
|
||||
public string port { get; set; }
|
||||
public string name { get; set; }
|
||||
|
@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -93,7 +91,8 @@ namespace RageCoop.Core
|
||||
}
|
||||
public static Dictionary<string, ZeroTierNetwork> Networks
|
||||
{
|
||||
get {
|
||||
get
|
||||
{
|
||||
Dictionary<string, ZeroTierNetwork> networks = new Dictionary<string, ZeroTierNetwork>();
|
||||
var p = Run("listnetworks");
|
||||
var lines = Regex.Split(p.StandardOutput.ReadToEnd(), "\n").Skip(1);
|
||||
@ -131,5 +130,9 @@ namespace RageCoop.Core
|
||||
var p = Run(command);
|
||||
return p.StandardOutput.ReadToEnd() + p.StandardError.ReadToEnd();
|
||||
}
|
||||
public static void Check()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
71
RageCoop.Core/PacketExtensions.cs
Normal file
71
RageCoop.Core/PacketExtensions.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
internal static class PacketExtensions
|
||||
{
|
||||
#region MESSAGE-READ
|
||||
public static Vector3 ReadVector3(this NetIncomingMessage m)
|
||||
{
|
||||
return new Vector3
|
||||
{
|
||||
X = m.ReadFloat(),
|
||||
Y = m.ReadFloat(),
|
||||
Z = m.ReadFloat(),
|
||||
};
|
||||
}
|
||||
public static Vector2 ReadVector2(this NetIncomingMessage m)
|
||||
{
|
||||
return new Vector2
|
||||
{
|
||||
X = m.ReadFloat(),
|
||||
Y = m.ReadFloat(),
|
||||
};
|
||||
}
|
||||
public static Quaternion ReadQuaternion(this NetIncomingMessage m)
|
||||
{
|
||||
return new Quaternion
|
||||
{
|
||||
X = m.ReadFloat(),
|
||||
Y = m.ReadFloat(),
|
||||
Z = m.ReadFloat(),
|
||||
W = m.ReadFloat(),
|
||||
};
|
||||
}
|
||||
public static byte[] ReadByteArray(this NetIncomingMessage m)
|
||||
{
|
||||
return m.ReadBytes(m.ReadInt32());
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MESSAGE-WRITE
|
||||
public static void Write(this NetOutgoingMessage m, Vector3 v)
|
||||
{
|
||||
m.Write(v.X);
|
||||
m.Write(v.Y);
|
||||
m.Write(v.Z);
|
||||
}
|
||||
public static void Write(this NetOutgoingMessage m, Quaternion q)
|
||||
{
|
||||
m.Write(q.X);
|
||||
m.Write(q.Y);
|
||||
m.Write(q.Z);
|
||||
m.Write(q.W);
|
||||
}
|
||||
public static void WriteByteArray(this NetOutgoingMessage m, byte[] b)
|
||||
{
|
||||
m.Write(b.Length);
|
||||
m.Write(b);
|
||||
}
|
||||
#endregion
|
||||
|
||||
internal static bool IsSyncEvent(this PacketType p)
|
||||
{
|
||||
return (30 <= (byte)p) && ((byte)p <= 40);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Lidgren.Network;
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
@ -11,8 +10,8 @@ namespace RageCoop.Core
|
||||
internal class ChatMessage : Packet
|
||||
{
|
||||
public override PacketType Type => PacketType.ChatMessage;
|
||||
private Func<string, byte[]> crypt;
|
||||
private Func<byte[], byte[]> decrypt;
|
||||
private readonly Func<string, byte[]> crypt;
|
||||
private readonly Func<byte[], byte[]> decrypt;
|
||||
public ChatMessage(Func<string, byte[]> crypter)
|
||||
{
|
||||
crypt = crypter;
|
||||
@ -25,33 +24,31 @@ namespace RageCoop.Core
|
||||
|
||||
public string Message { get; set; }
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
|
||||
|
||||
|
||||
// Write Username
|
||||
byteArray.AddString(Username);
|
||||
m.Write(Username);
|
||||
|
||||
|
||||
// Write Message
|
||||
byteArray.AddArray(crypt(Message));
|
||||
|
||||
return byteArray.ToArray();
|
||||
m.WriteByteArray(crypt(Message));
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
|
||||
// Read username
|
||||
Username = reader.ReadString();
|
||||
Username = m.ReadString();
|
||||
|
||||
Message = decrypt(reader.ReadByteArray()).GetString();
|
||||
Message = decrypt(m.ReadByteArray()).GetString();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Lidgren.Network;
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
internal partial class Packets
|
||||
@ -10,85 +8,78 @@ namespace RageCoop.Core
|
||||
internal class CustomEvent : Packet
|
||||
{
|
||||
public override PacketType Type => (_queued ? PacketType.CustomEventQueued : PacketType.CustomEvent);
|
||||
public CustomEvent(Func<byte,BitReader,object> onResolve = null,bool queued=false)
|
||||
public CustomEvent(Func<byte, NetIncomingMessage, object> onResolve = null, bool queued = false)
|
||||
{
|
||||
_resolve = onResolve;
|
||||
_queued = queued;
|
||||
}
|
||||
private bool _queued;
|
||||
private Func<byte, BitReader, object> _resolve { get; set; }
|
||||
private readonly bool _queued;
|
||||
private Func<byte, NetIncomingMessage, object> _resolve { get; set; }
|
||||
public int Hash { get; set; }
|
||||
public object[] Args { get; set; }
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
Args = Args ?? new object[] { };
|
||||
|
||||
List<byte> result = new List<byte>();
|
||||
result.AddInt(Hash);
|
||||
result.AddInt(Args.Length);
|
||||
(byte, byte[]) tup;
|
||||
m.Write(Hash);
|
||||
m.Write(Args.Length);
|
||||
foreach (var arg in Args)
|
||||
{
|
||||
tup=CoreUtils.GetBytesFromObject(arg);
|
||||
if (tup.Item1==0||tup.Item2==null)
|
||||
{
|
||||
throw new ArgumentException($"Object of type {arg.GetType()} is not supported");
|
||||
CoreUtils.GetBytesFromObject(arg, m);
|
||||
}
|
||||
result.Add(tup.Item1);
|
||||
result.AddRange(tup.Item2);
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
Hash = reader.ReadInt32();
|
||||
var len=reader.ReadInt32();
|
||||
|
||||
Hash = m.ReadInt32();
|
||||
var len = m.ReadInt32();
|
||||
Args = new object[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
byte type = reader.ReadByte();
|
||||
byte type = m.ReadByte();
|
||||
switch (type)
|
||||
{
|
||||
case 0x01:
|
||||
Args[i]=reader.ReadByte(); break;
|
||||
Args[i] = m.ReadByte(); break;
|
||||
case 0x02:
|
||||
Args[i]=reader.ReadInt32(); break;
|
||||
Args[i] = m.ReadInt32(); break;
|
||||
case 0x03:
|
||||
Args[i]=reader.ReadUInt16(); break;
|
||||
Args[i] = m.ReadUInt16(); break;
|
||||
case 0x04:
|
||||
Args[i]=reader.ReadInt32(); break;
|
||||
Args[i] = m.ReadInt32(); break;
|
||||
case 0x05:
|
||||
Args[i]=reader.ReadUInt32(); break;
|
||||
Args[i] = m.ReadUInt32(); break;
|
||||
case 0x06:
|
||||
Args[i]=reader.ReadInt64(); break;
|
||||
Args[i] = m.ReadInt64(); break;
|
||||
case 0x07:
|
||||
Args[i]=reader.ReadUInt64(); break;
|
||||
Args[i] = m.ReadUInt64(); break;
|
||||
case 0x08:
|
||||
Args[i]=reader.ReadSingle(); break;
|
||||
Args[i] = m.ReadFloat(); break;
|
||||
case 0x09:
|
||||
Args[i]=reader.ReadBoolean(); break;
|
||||
Args[i] = m.ReadBoolean(); break;
|
||||
case 0x10:
|
||||
Args[i]=reader.ReadString(); break;
|
||||
Args[i] = m.ReadString(); break;
|
||||
case 0x11:
|
||||
Args[i]=reader.ReadVector3(); break;
|
||||
Args[i] = m.ReadVector3(); break;
|
||||
case 0x12:
|
||||
Args[i]=reader.ReadQuaternion(); break;
|
||||
Args[i] = m.ReadQuaternion(); break;
|
||||
case 0x13:
|
||||
Args[i]=(GTA.Model)reader.ReadInt32(); break;
|
||||
Args[i] = (GTA.Model)m.ReadInt32(); break;
|
||||
case 0x14:
|
||||
Args[i]=reader.ReadVector2(); break;
|
||||
Args[i] = m.ReadVector2(); break;
|
||||
case 0x15:
|
||||
Args[i] = m.ReadByteArray(); break;
|
||||
default:
|
||||
if (_resolve == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Unexpected type:{type}\r\n{array.Dump()}");
|
||||
throw new InvalidOperationException($"Unexpected type: {type}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Args[i]=_resolve(type, reader); break;
|
||||
Args[i] = _resolve(type, m); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -25,34 +22,30 @@ namespace RageCoop.Core
|
||||
|
||||
public long FileLength { get; set; }
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
|
||||
// The ID from the download
|
||||
byteArray.AddInt(ID);
|
||||
m.Write(ID);
|
||||
|
||||
|
||||
// The name of the file
|
||||
byte[] nameBytes = Encoding.UTF8.GetBytes(Name);
|
||||
byteArray.AddRange(BitConverter.GetBytes(nameBytes.Length));
|
||||
byteArray.AddRange(nameBytes);
|
||||
m.Write(Name);
|
||||
|
||||
// The length of the file
|
||||
byteArray.AddRange(BitConverter.GetBytes(FileLength));
|
||||
|
||||
return byteArray.ToArray();
|
||||
m.Write(FileLength);
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
ID = reader.ReadInt32();
|
||||
Name = reader.ReadString();
|
||||
FileLength = reader.ReadInt64();
|
||||
|
||||
ID = m.ReadInt32();
|
||||
Name = m.ReadString();
|
||||
FileLength = m.ReadInt64();
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,25 +54,21 @@ namespace RageCoop.Core
|
||||
public override PacketType Type => PacketType.FileTransferResponse;
|
||||
public int ID { get; set; }
|
||||
public FileResponse Response { get; set; }
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// The ID from the download
|
||||
byteArray.AddInt(ID);
|
||||
m.Write(ID);
|
||||
|
||||
byteArray.Add((byte)Response);
|
||||
m.Write((byte)Response);
|
||||
|
||||
return byteArray.ToArray();
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
ID = reader.ReadInt32();
|
||||
Response = (FileResponse)reader.ReadByte();
|
||||
ID = m.ReadInt32();
|
||||
Response = (FileResponse)m.ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,27 +79,21 @@ namespace RageCoop.Core
|
||||
|
||||
public byte[] FileChunk { get; set; }
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
|
||||
// The ID from the download
|
||||
byteArray.AddInt(ID);
|
||||
|
||||
// The chunk of the file
|
||||
byteArray.AddInt(FileChunk.Length);
|
||||
byteArray.AddRange(FileChunk);
|
||||
|
||||
return byteArray.ToArray();
|
||||
m.Write(ID);
|
||||
m.WriteByteArray(FileChunk);
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
ID = reader.ReadInt32();
|
||||
FileChunk = reader.ReadByteArray();
|
||||
ID = m.ReadInt32();
|
||||
FileChunk = m.ReadByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,22 +102,20 @@ namespace RageCoop.Core
|
||||
public override PacketType Type => PacketType.FileTransferComplete;
|
||||
public int ID { get; set; }
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
|
||||
// The ID for the download
|
||||
byteArray.AddInt(ID);
|
||||
|
||||
return byteArray.ToArray();
|
||||
m.Write(ID);
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
ID = reader.ReadInt32();
|
||||
|
||||
ID = m.ReadInt32();
|
||||
}
|
||||
}
|
||||
internal class AllResourcesSent : Packet
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Lidgren.Network;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
@ -14,26 +12,26 @@ namespace RageCoop.Core
|
||||
public string TargetInternal { get; set; }
|
||||
public string TargetExternal { get; set; }
|
||||
public bool Connect { get; set; }
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
byteArray.AddInt(TargetID);
|
||||
byteArray.AddString(TargetInternal);
|
||||
byteArray.AddString(TargetExternal);
|
||||
byteArray.AddBool(Connect);
|
||||
return byteArray.ToArray();
|
||||
|
||||
m.Write(TargetID);
|
||||
m.Write(TargetInternal);
|
||||
m.Write(TargetExternal);
|
||||
m.Write(Connect);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
TargetID = reader.ReadInt32();
|
||||
TargetInternal = reader.ReadString();
|
||||
TargetExternal = reader.ReadString();
|
||||
Connect=reader.ReadBoolean();
|
||||
|
||||
TargetID = m.ReadInt32();
|
||||
TargetInternal = m.ReadString();
|
||||
TargetExternal = m.ReadString();
|
||||
Connect = m.ReadBoolean();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -46,22 +44,22 @@ namespace RageCoop.Core
|
||||
/// 1:initial, 2:acknowledged, 3:confirmed
|
||||
/// </summary>
|
||||
public byte Status { get; set; }
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
byteArray.AddInt(Puncher);
|
||||
byteArray.Add(Status);
|
||||
return byteArray.ToArray();
|
||||
|
||||
m.Write(Puncher);
|
||||
m.Write(Status);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
Puncher = reader.ReadInt32();
|
||||
Status = reader.ReadByte();
|
||||
|
||||
Puncher = m.ReadInt32();
|
||||
Status = m.ReadByte();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using Lidgren.Network;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -12,16 +12,15 @@ namespace RageCoop.Core
|
||||
{
|
||||
public int TargetID { get; set; }
|
||||
public override PacketType Type => PacketType.ConnectionRequest;
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
var data = new List<byte>(10);
|
||||
data.AddInt(TargetID);
|
||||
return data.ToArray();
|
||||
m.Write(TargetID);
|
||||
}
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
var reader=new BitReader(array);
|
||||
TargetID = reader.ReadInt32();
|
||||
|
||||
TargetID = m.ReadInt32();
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,16 +32,16 @@ namespace RageCoop.Core
|
||||
{
|
||||
public int ID { get; set; }
|
||||
public override PacketType Type => PacketType.P2PConnect;
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
var data = new List<byte>(10);
|
||||
data.AddInt(ID);
|
||||
return data.ToArray();
|
||||
m.Write(ID);
|
||||
|
||||
}
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
var reader = new BitReader(array);
|
||||
ID = reader.ReadInt32();
|
||||
|
||||
ID = m.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Lidgren.Network;
|
||||
using Newtonsoft.Json;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
@ -55,14 +51,6 @@ namespace RageCoop.Core
|
||||
|
||||
Unknown = 255
|
||||
}
|
||||
internal static class PacketExtensions
|
||||
{
|
||||
internal static bool IsSyncEvent(this PacketType p)
|
||||
{
|
||||
return (30<=(byte)p)&&((byte)p<=40);
|
||||
}
|
||||
}
|
||||
|
||||
internal enum ConnectionChannel
|
||||
{
|
||||
Default = 0,
|
||||
@ -98,6 +86,7 @@ namespace RageCoop.Core
|
||||
IsInLowCover = 1 << 11,
|
||||
IsInCoverFacingLeft = 1 << 12,
|
||||
IsBlindFiring = 1 << 13,
|
||||
IsInvincible = 1 << 14,
|
||||
IsFullSync = 1 << 15,
|
||||
}
|
||||
|
||||
@ -152,25 +141,19 @@ namespace RageCoop.Core
|
||||
internal interface IPacket
|
||||
{
|
||||
PacketType Type { get; }
|
||||
byte[] Serialize();
|
||||
|
||||
void Deserialize(byte[] data);
|
||||
void Deserialize(NetIncomingMessage m);
|
||||
}
|
||||
|
||||
internal abstract class Packet : IPacket
|
||||
{
|
||||
public abstract PacketType Type { get; }
|
||||
public virtual byte[] Serialize()
|
||||
public void Pack(NetOutgoingMessage m)
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
public virtual void Deserialize(byte[] array) { }
|
||||
public void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
var d=Serialize();
|
||||
message.Write((byte)Type);
|
||||
message.Write(d.Length);
|
||||
message.Write(d);
|
||||
m.Write((byte)Type);
|
||||
Serialize(m);
|
||||
}
|
||||
protected virtual void Serialize(NetOutgoingMessage m) { }
|
||||
public virtual void Deserialize(NetIncomingMessage m) { }
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA;
|
||||
using Lidgren.Network;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
@ -61,92 +59,92 @@ namespace RageCoop.Core
|
||||
public float BlipScale { get; set; } = 1;
|
||||
#endregion
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
byteArray.AddInt(ID);
|
||||
byteArray.AddInt(OwnerID);
|
||||
byteArray.AddRange(BitConverter.GetBytes((ushort)Flags));
|
||||
byteArray.AddRange(BitConverter.GetBytes(Health));
|
||||
byteArray.Add(Speed);
|
||||
|
||||
m.Write(ID);
|
||||
m.Write(OwnerID);
|
||||
m.Write((ushort)Flags);
|
||||
m.Write(Health);
|
||||
m.Write(Speed);
|
||||
if (Flags.HasPedFlag(PedDataFlags.IsRagdoll))
|
||||
{
|
||||
byteArray.AddVector3(HeadPosition);
|
||||
byteArray.AddVector3(RightFootPosition);
|
||||
byteArray.AddVector3(LeftFootPosition);
|
||||
m.Write(HeadPosition);
|
||||
m.Write(RightFootPosition);
|
||||
m.Write(LeftFootPosition);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Speed >= 4)
|
||||
{
|
||||
byteArray.AddInt(VehicleID);
|
||||
byteArray.Add((byte)(Seat+3));
|
||||
m.Write(VehicleID);
|
||||
m.Write((byte)(Seat + 3));
|
||||
}
|
||||
byteArray.AddVector3(Position);
|
||||
m.Write(Position);
|
||||
}
|
||||
byteArray.AddVector3(Rotation);
|
||||
byteArray.AddVector3(Velocity);
|
||||
m.Write(Rotation);
|
||||
m.Write(Velocity);
|
||||
|
||||
|
||||
if (Flags.HasPedFlag(PedDataFlags.IsAiming))
|
||||
{
|
||||
byteArray.AddVector3(AimCoords);
|
||||
m.Write(AimCoords);
|
||||
}
|
||||
|
||||
byteArray.AddFloat(Heading);
|
||||
m.Write(Heading);
|
||||
|
||||
if (Flags.HasPedFlag(PedDataFlags.IsFullSync))
|
||||
{
|
||||
byteArray.AddInt(ModelHash);
|
||||
byteArray.AddUint(CurrentWeaponHash);
|
||||
byteArray.AddRange(Clothes);
|
||||
m.Write(ModelHash);
|
||||
m.Write(CurrentWeaponHash);
|
||||
m.Write(Clothes);
|
||||
if (WeaponComponents != null)
|
||||
{
|
||||
byteArray.Add(0x01);
|
||||
byteArray.AddRange(BitConverter.GetBytes((ushort)WeaponComponents.Count));
|
||||
m.Write(true);
|
||||
m.Write((ushort)WeaponComponents.Count);
|
||||
foreach (KeyValuePair<uint, bool> component in WeaponComponents)
|
||||
{
|
||||
byteArray.AddRange(BitConverter.GetBytes(component.Key));
|
||||
byteArray.AddRange(BitConverter.GetBytes(component.Value));
|
||||
m.Write(component.Key);
|
||||
m.Write(component.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Player weapon doesn't have any components
|
||||
byteArray.Add(0x00);
|
||||
m.Write(false);
|
||||
}
|
||||
|
||||
byteArray.Add(WeaponTint);
|
||||
m.Write(WeaponTint);
|
||||
|
||||
byteArray.Add((byte)BlipColor);
|
||||
m.Write((byte)BlipColor);
|
||||
if ((byte)BlipColor != 255)
|
||||
{
|
||||
byteArray.AddUshort((ushort)BlipSprite);
|
||||
byteArray.AddFloat(BlipScale);
|
||||
m.Write((ushort)BlipSprite);
|
||||
m.Write(BlipScale);
|
||||
}
|
||||
}
|
||||
|
||||
return byteArray.ToArray();
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
ID = reader.ReadInt32();
|
||||
OwnerID=reader.ReadInt32();
|
||||
Flags = (PedDataFlags)reader.ReadUInt16();
|
||||
Health = reader.ReadInt32();
|
||||
Speed = reader.ReadByte();
|
||||
|
||||
ID = m.ReadInt32();
|
||||
OwnerID = m.ReadInt32();
|
||||
Flags = (PedDataFlags)m.ReadUInt16();
|
||||
Health = m.ReadInt32();
|
||||
Speed = m.ReadByte();
|
||||
|
||||
if (Flags.HasPedFlag(PedDataFlags.IsRagdoll))
|
||||
{
|
||||
HeadPosition=reader.ReadVector3();
|
||||
RightFootPosition=reader.ReadVector3();
|
||||
LeftFootPosition=reader.ReadVector3();
|
||||
HeadPosition = m.ReadVector3();
|
||||
RightFootPosition = m.ReadVector3();
|
||||
LeftFootPosition = m.ReadVector3();
|
||||
Position = HeadPosition;
|
||||
}
|
||||
else
|
||||
@ -154,54 +152,54 @@ namespace RageCoop.Core
|
||||
// Vehicle related
|
||||
if (Speed >= 4)
|
||||
{
|
||||
VehicleID=reader.ReadInt32();
|
||||
Seat=(VehicleSeat)(reader.ReadByte()-3);
|
||||
VehicleID = m.ReadInt32();
|
||||
Seat = (VehicleSeat)(m.ReadByte() - 3);
|
||||
}
|
||||
|
||||
// Read player position
|
||||
Position = reader.ReadVector3();
|
||||
Position = m.ReadVector3();
|
||||
}
|
||||
|
||||
Rotation = reader.ReadVector3();
|
||||
Velocity = reader.ReadVector3();
|
||||
Rotation = m.ReadVector3();
|
||||
Velocity = m.ReadVector3();
|
||||
|
||||
if (Flags.HasPedFlag(PedDataFlags.IsAiming))
|
||||
{
|
||||
// Read player aim coords
|
||||
AimCoords = reader.ReadVector3();
|
||||
AimCoords = m.ReadVector3();
|
||||
}
|
||||
|
||||
Heading=reader.ReadSingle();
|
||||
Heading = m.ReadFloat();
|
||||
|
||||
if (Flags.HasPedFlag(PedDataFlags.IsFullSync))
|
||||
{
|
||||
// Read player model hash
|
||||
ModelHash = reader.ReadInt32();
|
||||
ModelHash = m.ReadInt32();
|
||||
|
||||
// Read player weapon hash
|
||||
CurrentWeaponHash = reader.ReadUInt32();
|
||||
CurrentWeaponHash = m.ReadUInt32();
|
||||
|
||||
// Read player clothes
|
||||
Clothes =reader.ReadBytes(36);
|
||||
Clothes = m.ReadBytes(36);
|
||||
|
||||
// Read player weapon components
|
||||
if (reader.ReadBoolean())
|
||||
if (m.ReadBoolean())
|
||||
{
|
||||
WeaponComponents = new Dictionary<uint, bool>();
|
||||
ushort comCount = reader.ReadUInt16();
|
||||
ushort comCount = m.ReadUInt16();
|
||||
for (ushort i = 0; i < comCount; i++)
|
||||
{
|
||||
WeaponComponents.Add(reader.ReadUInt32(), reader.ReadBoolean());
|
||||
WeaponComponents.Add(m.ReadUInt32(), m.ReadBoolean());
|
||||
}
|
||||
}
|
||||
WeaponTint=reader.ReadByte();
|
||||
WeaponTint = m.ReadByte();
|
||||
|
||||
BlipColor=(BlipColor)reader.ReadByte();
|
||||
BlipColor = (BlipColor)m.ReadByte();
|
||||
|
||||
if ((byte)BlipColor != 255)
|
||||
{
|
||||
BlipSprite=(BlipSprite)reader.ReadUInt16();
|
||||
BlipScale=reader.ReadSingle();
|
||||
BlipSprite = (BlipSprite)m.ReadUInt16();
|
||||
BlipScale = m.ReadFloat();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GTA.Math;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
using System.Net;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -38,62 +36,55 @@ namespace RageCoop.Core
|
||||
public byte[] PasswordEncrypted { get; set; }
|
||||
|
||||
public IPEndPoint InternalEndPoint { get; set; }
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write Player Ped ID
|
||||
byteArray.AddRange(BitConverter.GetBytes(PedID));
|
||||
m.Write(PedID);
|
||||
|
||||
// Write Username
|
||||
byte[] usernameBytes = Encoding.UTF8.GetBytes(Username);
|
||||
byteArray.AddRange(BitConverter.GetBytes(usernameBytes.Length));
|
||||
byteArray.AddRange(usernameBytes);
|
||||
m.Write(Username);
|
||||
|
||||
// Write ModVersion
|
||||
byte[] modVersionBytes = Encoding.UTF8.GetBytes(ModVersion);
|
||||
byteArray.AddRange(BitConverter.GetBytes(modVersionBytes.Length));
|
||||
byteArray.AddRange(modVersionBytes);
|
||||
m.Write(ModVersion);
|
||||
|
||||
byteArray.AddString(InternalEndPoint.ToString());
|
||||
m.Write(InternalEndPoint.ToString());
|
||||
|
||||
// Write AesKeyCrypted
|
||||
byteArray.AddArray(AesKeyCrypted);
|
||||
m.WriteByteArray(AesKeyCrypted);
|
||||
|
||||
// Write AesIVCrypted
|
||||
byteArray.AddArray(AesIVCrypted);
|
||||
m.WriteByteArray(AesIVCrypted);
|
||||
|
||||
|
||||
// Write PassHash
|
||||
byteArray.AddArray(PasswordEncrypted);
|
||||
m.WriteByteArray(PasswordEncrypted);
|
||||
|
||||
return byteArray.ToArray();
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
|
||||
// Read player netHandle
|
||||
PedID = reader.ReadInt32();
|
||||
PedID = m.ReadInt32();
|
||||
|
||||
// Read Username
|
||||
Username = reader.ReadString();
|
||||
Username = m.ReadString();
|
||||
|
||||
// Read ModVersion
|
||||
ModVersion = reader.ReadString();
|
||||
ModVersion = m.ReadString();
|
||||
|
||||
InternalEndPoint=CoreUtils.StringToEndPoint(reader.ReadString());
|
||||
InternalEndPoint = CoreUtils.StringToEndPoint(m.ReadString());
|
||||
|
||||
AesKeyCrypted=reader.ReadByteArray();
|
||||
AesKeyCrypted = m.ReadByteArray();
|
||||
|
||||
AesIVCrypted=reader.ReadByteArray();
|
||||
AesIVCrypted = m.ReadByteArray();
|
||||
|
||||
|
||||
PasswordEncrypted=reader.ReadByteArray();
|
||||
PasswordEncrypted = m.ReadByteArray();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -101,27 +92,25 @@ namespace RageCoop.Core
|
||||
{
|
||||
public PlayerData[] Players { get; set; }
|
||||
public override PacketType Type => PacketType.HandshakeSuccess;
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
var data = new List<byte>();
|
||||
data.AddInt(Players.Length);
|
||||
m.Write(Players.Length);
|
||||
foreach (var p in Players)
|
||||
{
|
||||
data.AddInt(p.ID);
|
||||
data.AddString(p.Username);
|
||||
m.Write(p.ID);
|
||||
m.Write(p.Username);
|
||||
}
|
||||
return data.ToArray();
|
||||
}
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
var reader = new BitReader(array);
|
||||
Players=new PlayerData[reader.ReadInt32()];
|
||||
|
||||
Players = new PlayerData[m.ReadInt32()];
|
||||
for (int i = 0; i < Players.Length; i++)
|
||||
{
|
||||
Players[i] = new PlayerData()
|
||||
{
|
||||
ID=reader.ReadInt32(),
|
||||
Username=reader.ReadString(),
|
||||
ID = m.ReadInt32(),
|
||||
Username = m.ReadString(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -133,36 +122,24 @@ namespace RageCoop.Core
|
||||
|
||||
public string Username { get; set; }
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write NetHandle
|
||||
byteArray.AddRange(BitConverter.GetBytes(PedID));
|
||||
m.Write(PedID);
|
||||
|
||||
// Get Username bytes
|
||||
byte[] usernameBytes = Encoding.UTF8.GetBytes(Username);
|
||||
|
||||
// Write UsernameLength
|
||||
byteArray.AddRange(BitConverter.GetBytes(usernameBytes.Length));
|
||||
|
||||
// Write Username
|
||||
byteArray.AddRange(usernameBytes);
|
||||
|
||||
return byteArray.ToArray();
|
||||
m.Write(Username);
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
// Read player netHandle
|
||||
PedID = reader.ReadInt32();
|
||||
PedID = m.ReadInt32();
|
||||
|
||||
// Read Username
|
||||
Username = reader.ReadString();
|
||||
Username = m.ReadString();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -172,22 +149,18 @@ namespace RageCoop.Core
|
||||
public override PacketType Type => PacketType.PlayerDisconnect;
|
||||
public int PedID { get; set; }
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
m.Write(PedID);
|
||||
|
||||
byteArray.AddRange(BitConverter.GetBytes(PedID));
|
||||
|
||||
return byteArray.ToArray();
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
PedID = reader.ReadInt32();
|
||||
PedID = m.ReadInt32();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -202,38 +175,39 @@ namespace RageCoop.Core
|
||||
public string Username { get; set; }
|
||||
public float Latency { get; set; }
|
||||
public Vector3 Position { get; set; }
|
||||
public override byte[] Serialize()
|
||||
public bool IsHost;
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write ID
|
||||
byteArray.AddRange(BitConverter.GetBytes(PedID));
|
||||
m.Write(PedID);
|
||||
|
||||
// Write Username
|
||||
byteArray.AddString(Username);
|
||||
m.Write(Username);
|
||||
|
||||
// Write Latency
|
||||
byteArray.AddFloat(Latency);
|
||||
m.Write(Latency);
|
||||
|
||||
byteArray.AddVector3(Position);
|
||||
m.Write(Position);
|
||||
|
||||
return byteArray.ToArray();
|
||||
m.Write(IsHost);
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
|
||||
// Read player ID
|
||||
PedID = reader.ReadInt32();
|
||||
PedID = m.ReadInt32();
|
||||
|
||||
// Read Username
|
||||
Username = reader.ReadString();
|
||||
Username = m.ReadString();
|
||||
|
||||
Latency=reader.ReadSingle();
|
||||
Latency = m.ReadFloat();
|
||||
|
||||
Position=reader.ReadVector3();
|
||||
Position = m.ReadVector3();
|
||||
|
||||
IsHost = m.ReadBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,24 +218,24 @@ namespace RageCoop.Core
|
||||
public byte[] Modulus;
|
||||
public byte[] Exponent;
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
byteArray.AddArray(Modulus);
|
||||
|
||||
byteArray.AddArray(Exponent);
|
||||
|
||||
|
||||
return byteArray.ToArray();
|
||||
m.WriteByteArray(Modulus);
|
||||
|
||||
m.WriteByteArray(Exponent);
|
||||
|
||||
|
||||
|
||||
}
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
var reader=new BitReader(array);
|
||||
Modulus=reader.ReadByteArray();
|
||||
Exponent=reader.ReadByteArray();
|
||||
|
||||
Modulus = m.ReadByteArray();
|
||||
Exponent = m.ReadByteArray();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GTA.Math;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -26,57 +23,57 @@ namespace RageCoop.Core
|
||||
|
||||
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
|
||||
// Write id
|
||||
byteArray.AddInt(ID);
|
||||
m.Write(ID);
|
||||
|
||||
// Write ShooterID
|
||||
byteArray.AddInt(ShooterID);
|
||||
m.Write(ShooterID);
|
||||
|
||||
byteArray.AddUint(WeaponHash);
|
||||
m.Write(WeaponHash);
|
||||
|
||||
// Write position
|
||||
byteArray.AddVector3(Position);
|
||||
m.Write(Position);
|
||||
|
||||
|
||||
// Write rotation
|
||||
byteArray.AddVector3(Rotation);
|
||||
m.Write(Rotation);
|
||||
|
||||
// Write velocity
|
||||
byteArray.AddVector3(Velocity);
|
||||
byteArray.Add((byte)Flags);
|
||||
m.Write(Velocity);
|
||||
m.Write((byte)Flags);
|
||||
|
||||
|
||||
return byteArray.ToArray();
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
|
||||
// Read id
|
||||
ID = reader.ReadInt32();
|
||||
ID = m.ReadInt32();
|
||||
|
||||
// Read ShooterID
|
||||
ShooterID= reader.ReadInt32();
|
||||
ShooterID = m.ReadInt32();
|
||||
|
||||
WeaponHash= reader.ReadUInt32();
|
||||
WeaponHash = m.ReadUInt32();
|
||||
|
||||
// Read position
|
||||
Position = reader.ReadVector3();
|
||||
Position = m.ReadVector3();
|
||||
|
||||
// Read rotation
|
||||
Rotation = reader.ReadVector3();
|
||||
Rotation = m.ReadVector3();
|
||||
|
||||
// Read velocity
|
||||
Velocity =reader.ReadVector3();
|
||||
Velocity = m.ReadVector3();
|
||||
|
||||
Flags=(ProjectileDataFlags)reader.ReadByte();
|
||||
Flags = (ProjectileDataFlags)m.ReadByte();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GTA.Math;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -19,44 +16,44 @@ namespace RageCoop.Core
|
||||
public Vector3 StartPosition { get; set; }
|
||||
public Vector3 EndPosition { get; set; }
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
|
||||
// Write OwnerID
|
||||
byteArray.AddRange(BitConverter.GetBytes(OwnerID));
|
||||
m.Write(OwnerID);
|
||||
|
||||
// Write weapon hash
|
||||
byteArray.AddRange(BitConverter.GetBytes(WeaponHash));
|
||||
m.Write(WeaponHash);
|
||||
|
||||
// Write StartPosition
|
||||
byteArray.AddVector3(StartPosition);
|
||||
m.Write(StartPosition);
|
||||
|
||||
// Write EndPosition
|
||||
byteArray.AddVector3(EndPosition);
|
||||
m.Write(EndPosition);
|
||||
|
||||
|
||||
|
||||
return byteArray.ToArray();
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
|
||||
// Read OwnerID
|
||||
OwnerID=reader.ReadInt32();
|
||||
OwnerID = m.ReadInt32();
|
||||
|
||||
// Read WeponHash
|
||||
WeaponHash=reader.ReadUInt32();
|
||||
WeaponHash = m.ReadUInt32();
|
||||
|
||||
// Read StartPosition
|
||||
StartPosition=reader.ReadVector3();
|
||||
StartPosition = m.ReadVector3();
|
||||
|
||||
// Read EndPosition
|
||||
EndPosition=reader.ReadVector3();
|
||||
EndPosition = m.ReadVector3();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -15,24 +12,24 @@ namespace RageCoop.Core
|
||||
|
||||
public bool Hover { get; set; }
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
byteArray.AddInt(VehicleID);
|
||||
byteArray.AddBool(Hover);
|
||||
|
||||
return byteArray.ToArray();
|
||||
m.Write(VehicleID);
|
||||
m.Write(Hover);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
VehicleID=reader.ReadInt32();
|
||||
Hover=reader.ReadBoolean();
|
||||
|
||||
VehicleID = m.ReadInt32();
|
||||
Hover = m.ReadBoolean();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -16,24 +13,19 @@ namespace RageCoop.Core
|
||||
|
||||
public int NewOwnerID { get; set; }
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
byteArray.AddInt(ID);
|
||||
byteArray.AddInt(NewOwnerID);
|
||||
|
||||
return byteArray.ToArray();
|
||||
m.Write(ID);
|
||||
m.Write(NewOwnerID);
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
ID=reader.ReadInt32();
|
||||
NewOwnerID=reader.ReadInt32();
|
||||
|
||||
ID = m.ReadInt32();
|
||||
NewOwnerID = m.ReadInt32();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -14,22 +11,22 @@ namespace RageCoop.Core
|
||||
public override PacketType Type => PacketType.PedKilled;
|
||||
public int VictimID { get; set; }
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
byteArray.AddInt(VictimID);
|
||||
return byteArray.ToArray();
|
||||
|
||||
m.Write(VictimID);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
VictimID=reader.ReadInt32();
|
||||
|
||||
VictimID = m.ReadInt32();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GTA.Math;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
@ -18,31 +16,31 @@ namespace RageCoop.Core
|
||||
public Vector3 StartPosition { get; set; }
|
||||
public Vector3 EndPosition { get; set; }
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
byteArray.AddInt(OwnerID);
|
||||
byteArray.AddUshort(Bone);
|
||||
byteArray.AddUint(WeaponHash);
|
||||
byteArray.AddVector3(StartPosition);
|
||||
byteArray.AddVector3(EndPosition);
|
||||
|
||||
return byteArray.ToArray();
|
||||
m.Write(OwnerID);
|
||||
m.Write(Bone);
|
||||
m.Write(WeaponHash);
|
||||
m.Write(StartPosition);
|
||||
m.Write(EndPosition);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
OwnerID=reader.ReadInt32();
|
||||
Bone=reader.ReadUInt16();
|
||||
WeaponHash=reader.ReadUInt32();
|
||||
StartPosition=reader.ReadVector3();
|
||||
EndPosition=reader.ReadVector3();
|
||||
|
||||
OwnerID = m.ReadInt32();
|
||||
Bone = m.ReadUInt16();
|
||||
WeaponHash = m.ReadUInt32();
|
||||
StartPosition = m.ReadVector3();
|
||||
EndPosition = m.ReadVector3();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GTA;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
@ -58,200 +55,170 @@ namespace RageCoop.Core
|
||||
public string LicensePlate { get; set; }
|
||||
#endregion
|
||||
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
|
||||
List<byte> byteArray = new List<byte>(100);
|
||||
|
||||
byteArray.AddInt(ID);
|
||||
byteArray.AddInt(OwnerID);
|
||||
byteArray.AddUshort((ushort)Flags);
|
||||
byteArray.AddVector3(Position);
|
||||
byteArray.AddQuaternion(Quaternion);
|
||||
byteArray.AddVector3(Velocity);
|
||||
byteArray.AddVector3(RotationVelocity);
|
||||
byteArray.AddFloat(ThrottlePower);
|
||||
byteArray.AddFloat(BrakePower);
|
||||
byteArray.AddFloat(SteeringAngle);
|
||||
m.Write(ID);
|
||||
m.Write(OwnerID);
|
||||
m.Write((ushort)Flags);
|
||||
m.Write(Position);
|
||||
m.Write(Quaternion);
|
||||
m.Write(Velocity);
|
||||
m.Write(RotationVelocity);
|
||||
m.Write(ThrottlePower);
|
||||
m.Write(BrakePower);
|
||||
m.Write(SteeringAngle);
|
||||
|
||||
if (Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering))
|
||||
{
|
||||
byteArray.AddFloat(DeluxoWingRatio);
|
||||
m.Write(DeluxoWingRatio);
|
||||
}
|
||||
|
||||
if (Flags.HasVehFlag(VehicleDataFlags.IsFullSync))
|
||||
{
|
||||
byteArray.AddInt(ModelHash);
|
||||
byteArray.AddFloat(EngineHealth);
|
||||
m.Write(ModelHash);
|
||||
m.Write(EngineHealth);
|
||||
|
||||
// Check
|
||||
if (Flags.HasVehFlag(VehicleDataFlags.IsAircraft))
|
||||
{
|
||||
// Write the vehicle landing gear
|
||||
byteArray.Add(LandingGear);
|
||||
m.Write(LandingGear);
|
||||
}
|
||||
if (Flags.HasVehFlag(VehicleDataFlags.HasRoof))
|
||||
{
|
||||
byteArray.Add(RoofState);
|
||||
m.Write(RoofState);
|
||||
}
|
||||
|
||||
// Write vehicle colors
|
||||
byteArray.Add(Colors[0]);
|
||||
byteArray.Add(Colors[1]);
|
||||
m.Write(Colors[0]);
|
||||
m.Write(Colors[1]);
|
||||
|
||||
// Write vehicle mods
|
||||
// Write the count of mods
|
||||
byteArray.AddRange(BitConverter.GetBytes((short)Mods.Count));
|
||||
m.Write((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));
|
||||
m.Write(mod.Key);
|
||||
m.Write(mod.Value);
|
||||
}
|
||||
|
||||
if (!DamageModel.Equals(default(VehicleDamageModel)))
|
||||
{
|
||||
// Write boolean = true
|
||||
byteArray.Add(0x01);
|
||||
m.Write(true);
|
||||
// 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);
|
||||
m.Write(DamageModel.BrokenDoors);
|
||||
m.Write(DamageModel.OpenedDoors);
|
||||
m.Write(DamageModel.BrokenWindows);
|
||||
m.Write(DamageModel.BurstedTires);
|
||||
m.Write(DamageModel.LeftHeadLightBroken);
|
||||
m.Write(DamageModel.RightHeadLightBroken);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write boolean = false
|
||||
byteArray.Add(0x00);
|
||||
m.Write(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Write LockStatus
|
||||
byteArray.Add((byte)LockStatus);
|
||||
m.Write((byte)LockStatus);
|
||||
|
||||
// Write RadioStation
|
||||
byteArray.Add(RadioStation);
|
||||
m.Write(RadioStation);
|
||||
|
||||
// Write LicensePlate
|
||||
while (LicensePlate.Length<8)
|
||||
{
|
||||
LicensePlate+=" ";
|
||||
}
|
||||
if (LicensePlate.Length>8)
|
||||
{
|
||||
LicensePlate=new string(LicensePlate.Take(8).ToArray());
|
||||
}
|
||||
byteArray.AddRange(Encoding.ASCII.GetBytes(LicensePlate));
|
||||
m.Write(LicensePlate);
|
||||
|
||||
byteArray.Add((byte)(Livery+1));
|
||||
m.Write((byte)(Livery + 1));
|
||||
}
|
||||
return byteArray.ToArray();
|
||||
}
|
||||
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
// Read vehicle id
|
||||
ID = reader.ReadInt32();
|
||||
|
||||
OwnerID = reader.ReadInt32();
|
||||
|
||||
Flags=(VehicleDataFlags)reader.ReadUInt16();
|
||||
|
||||
// Read position
|
||||
Position = reader.ReadVector3();
|
||||
|
||||
// Read quaternion
|
||||
Quaternion=reader.ReadQuaternion();
|
||||
|
||||
// Read velocity
|
||||
Velocity =reader.ReadVector3();
|
||||
|
||||
// Read rotation velocity
|
||||
RotationVelocity=reader.ReadVector3();
|
||||
|
||||
// Read throttle power
|
||||
ThrottlePower=reader.ReadSingle();
|
||||
|
||||
// Read brake power
|
||||
BrakePower=reader.ReadSingle();
|
||||
|
||||
// Read steering angle
|
||||
SteeringAngle = reader.ReadSingle();
|
||||
ID = m.ReadInt32();
|
||||
OwnerID = m.ReadInt32();
|
||||
Flags = (VehicleDataFlags)m.ReadUInt16();
|
||||
Position = m.ReadVector3();
|
||||
Quaternion = m.ReadQuaternion();
|
||||
Velocity = m.ReadVector3();
|
||||
RotationVelocity = m.ReadVector3();
|
||||
ThrottlePower = m.ReadFloat();
|
||||
BrakePower = m.ReadFloat();
|
||||
SteeringAngle = m.ReadFloat();
|
||||
|
||||
|
||||
if (Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering))
|
||||
{
|
||||
DeluxoWingRatio = reader.ReadSingle();
|
||||
DeluxoWingRatio = m.ReadFloat();
|
||||
}
|
||||
|
||||
if (Flags.HasVehFlag(VehicleDataFlags.IsFullSync))
|
||||
{
|
||||
// Read vehicle model hash
|
||||
ModelHash = reader.ReadInt32();
|
||||
ModelHash = m.ReadInt32();
|
||||
|
||||
// Read vehicle engine health
|
||||
EngineHealth = reader.ReadSingle();
|
||||
EngineHealth = m.ReadFloat();
|
||||
|
||||
|
||||
// Check
|
||||
if (Flags.HasVehFlag(VehicleDataFlags.IsAircraft))
|
||||
{
|
||||
// Read vehicle landing gear
|
||||
LandingGear = reader.ReadByte();
|
||||
LandingGear = m.ReadByte();
|
||||
}
|
||||
if (Flags.HasVehFlag(VehicleDataFlags.HasRoof))
|
||||
{
|
||||
RoofState=reader.ReadByte();
|
||||
RoofState = m.ReadByte();
|
||||
}
|
||||
|
||||
// Read vehicle colors
|
||||
byte vehColor1 = reader.ReadByte();
|
||||
byte vehColor2 = reader.ReadByte();
|
||||
byte vehColor1 = m.ReadByte();
|
||||
byte vehColor2 = m.ReadByte();
|
||||
Colors = new byte[] { vehColor1, vehColor2 };
|
||||
|
||||
// Read vehicle mods
|
||||
// Create new Dictionary
|
||||
Mods = new Dictionary<int, int>();
|
||||
// Read count of mods
|
||||
short vehModCount = reader.ReadInt16();
|
||||
short vehModCount = m.ReadInt16();
|
||||
// Loop
|
||||
for (int i = 0; i < vehModCount; i++)
|
||||
{
|
||||
// Read the mod value
|
||||
Mods.Add(reader.ReadInt32(), reader.ReadInt32());
|
||||
Mods.Add(m.ReadInt32(), m.ReadInt32());
|
||||
}
|
||||
|
||||
if (reader.ReadBoolean())
|
||||
if (m.ReadBoolean())
|
||||
{
|
||||
// Read vehicle damage model
|
||||
DamageModel = new VehicleDamageModel()
|
||||
{
|
||||
BrokenDoors = reader.ReadByte(),
|
||||
OpenedDoors=reader.ReadByte(),
|
||||
BrokenWindows = reader.ReadByte(),
|
||||
BurstedTires = reader.ReadInt16(),
|
||||
LeftHeadLightBroken = reader.ReadByte(),
|
||||
RightHeadLightBroken = reader.ReadByte()
|
||||
BrokenDoors = m.ReadByte(),
|
||||
OpenedDoors = m.ReadByte(),
|
||||
BrokenWindows = m.ReadByte(),
|
||||
BurstedTires = m.ReadInt16(),
|
||||
LeftHeadLightBroken = m.ReadByte(),
|
||||
RightHeadLightBroken = m.ReadByte()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Read LockStatus
|
||||
LockStatus=(VehicleLockStatus)reader.ReadByte();
|
||||
LockStatus = (VehicleLockStatus)m.ReadByte();
|
||||
|
||||
// Read RadioStation
|
||||
RadioStation=reader.ReadByte();
|
||||
RadioStation = m.ReadByte();
|
||||
|
||||
LicensePlate=Encoding.ASCII.GetString(reader.ReadBytes(8));
|
||||
LicensePlate = m.ReadString();
|
||||
|
||||
Livery=(int)(reader.ReadByte()-1);
|
||||
Livery = m.ReadByte() - 1;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
@ -10,20 +10,19 @@ namespace RageCoop.Core
|
||||
public byte[] Buffer { get; set; }
|
||||
public int Recorded { get; set; }
|
||||
public override PacketType Type => PacketType.Voice;
|
||||
public override byte[] Serialize()
|
||||
protected override void Serialize(NetOutgoingMessage m)
|
||||
{
|
||||
var data = new List<byte>();
|
||||
data.AddInt(ID);
|
||||
data.AddArray(Buffer);
|
||||
data.AddInt(Recorded);
|
||||
return data.ToArray();
|
||||
m.Write(ID);
|
||||
m.Write(Buffer);
|
||||
m.Write(Recorded);
|
||||
|
||||
}
|
||||
public override void Deserialize(byte[] array)
|
||||
public override void Deserialize(NetIncomingMessage m)
|
||||
{
|
||||
var reader = new BitReader(array);
|
||||
ID = reader.ReadInt32();
|
||||
Buffer = reader.ReadByteArray();
|
||||
Recorded = reader.ReadInt32();
|
||||
|
||||
ID = m.ReadInt32();
|
||||
Buffer = m.ReadByteArray();
|
||||
Recorded = m.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace RageCoop.Core.Scripting
|
||||
{
|
||||
@ -10,8 +10,8 @@ namespace RageCoop.Core.Scripting
|
||||
/// </summary>
|
||||
public static class CustomEvents
|
||||
{
|
||||
static MD5 Hasher = MD5.Create();
|
||||
static Dictionary<int,string> Hashed=new Dictionary<int,string>();
|
||||
private static readonly MD5 Hasher = MD5.Create();
|
||||
private static readonly Dictionary<int, string> Hashed = new Dictionary<int, string>();
|
||||
internal static readonly int OnPlayerDied = Hash("RageCoop.OnPlayerDied");
|
||||
internal static readonly int SetWeather = Hash("RageCoop.SetWeather");
|
||||
internal static readonly int OnPedDeleted = Hash("RageCoop.OnPedDeleted");
|
||||
@ -40,26 +40,21 @@ namespace RageCoop.Core.Scripting
|
||||
public static int Hash(string s)
|
||||
{
|
||||
var hash = BitConverter.ToInt32(Hasher.ComputeHash(Encoding.UTF8.GetBytes(s)), 0);
|
||||
string name;
|
||||
lock (Hashed)
|
||||
{
|
||||
if (Hashed.TryGetValue(hash, out name))
|
||||
if (Hashed.TryGetValue(hash, out string name))
|
||||
{
|
||||
if (name != s)
|
||||
{
|
||||
throw new ArgumentException($"Hashed value has collision with another name:{name}, hashed value:{hash}");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Hashed.Add(hash, s);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace RageCoop.Core.Scripting
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
@ -9,8 +9,8 @@ namespace RageCoop.Core
|
||||
/// </summary>
|
||||
public class Worker : IDisposable
|
||||
{
|
||||
private SemaphoreSlim _semaphoreSlim;
|
||||
private Thread _workerThread;
|
||||
private readonly SemaphoreSlim _semaphoreSlim;
|
||||
private readonly Thread _workerThread;
|
||||
private bool _stopping = false;
|
||||
/// <summary>
|
||||
/// Name of the worker
|
||||
@ -81,6 +81,6 @@ namespace RageCoop.Core
|
||||
Stop();
|
||||
_semaphoreSlim.Dispose();
|
||||
}
|
||||
private ConcurrentQueue<Action> Jobs=new ConcurrentQueue<Action>();
|
||||
private readonly ConcurrentQueue<Action> Jobs = new ConcurrentQueue<Action>();
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using Lidgren.Network;
|
||||
using System.Diagnostics;
|
||||
using RageCoop.Core.Scripting;
|
||||
using System.Security.Cryptography;
|
||||
using RageCoop.Server.Scripting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
@ -20,10 +20,15 @@ namespace RageCoop.Server
|
||||
{
|
||||
Server = server;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total number of entities owned by this client
|
||||
/// </summary>
|
||||
public int EntitiesCount { get; internal set; }
|
||||
/// <summary>
|
||||
/// Th client's IP address and port.
|
||||
/// </summary>
|
||||
public IPEndPoint EndPoint { get { return Connection?.RemoteEndPoint; } }
|
||||
public IPEndPoint EndPoint => Connection?.RemoteEndPoint;
|
||||
|
||||
/// <summary>
|
||||
/// Internal(LAN) address of this client, used for NAT hole-punching
|
||||
@ -57,23 +62,25 @@ namespace RageCoop.Server
|
||||
/// <summary>
|
||||
/// Gets or sets whether to enable automatic respawn for this client's main ped.
|
||||
/// </summary>
|
||||
public bool EnableAutoRespawn {
|
||||
get { return _autoRespawn; }
|
||||
set {
|
||||
public bool EnableAutoRespawn
|
||||
{
|
||||
get => _autoRespawn;
|
||||
set
|
||||
{
|
||||
BaseScript.SetAutoRespawn(this, value);
|
||||
_autoRespawn = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _displayNameTag = true;
|
||||
private Stopwatch _latencyWatch = new Stopwatch();
|
||||
private readonly Stopwatch _latencyWatch = new Stopwatch();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to enable automatic respawn for this client's main ped.
|
||||
/// </summary>
|
||||
public bool DisplayNameTag
|
||||
{
|
||||
get { return _displayNameTag; }
|
||||
get => _displayNameTag;
|
||||
set
|
||||
{
|
||||
Server.BaseScript.SetNameTag(this, value);
|
||||
|
@ -1,10 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RageCoop.Server
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
internal class FileTransfer
|
||||
{
|
||||
|
@ -1,12 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using RageCoop.Core;
|
||||
namespace RageCoop.Server
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
internal class HolePunch
|
||||
{
|
||||
|
197
RageCoop.Server/Networking/Server.Background.cs
Normal file
197
RageCoop.Server/Networking/Server.Background.cs
Normal file
@ -0,0 +1,197 @@
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using Lidgren.Network;
|
||||
using Newtonsoft.Json;
|
||||
using RageCoop.Core;
|
||||
using RageCoop.Server.Scripting;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
public partial class Server
|
||||
{
|
||||
private const string _versionURL = "https://raw.githubusercontent.com/RAGECOOP/RAGECOOP-V/main/RageCoop.Server/Properties/AssemblyInfo.cs";
|
||||
private void SendPlayerUpdate()
|
||||
{
|
||||
foreach (var c in ClientsByNetHandle.Values.ToArray())
|
||||
{
|
||||
try
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
new Packets.PlayerInfoUpdate()
|
||||
{
|
||||
PedID = c.Player.ID,
|
||||
Username = c.Username,
|
||||
Latency = c.Latency,
|
||||
Position = c.Player.Position,
|
||||
IsHost = c == _hostClient
|
||||
}.Pack(outgoingMessage);
|
||||
MainNetServer.SendToAll(outgoingMessage, NetDeliveryMethod.ReliableSequenced, (byte)ConnectionChannel.Default);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
private IpInfo IpInfo = null;
|
||||
private bool CanAnnounce = false;
|
||||
private void Announce()
|
||||
{
|
||||
HttpResponseMessage response = null;
|
||||
HttpClient httpClient = new();
|
||||
if (IpInfo == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TLS only
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 |
|
||||
SecurityProtocolType.Tls12 |
|
||||
SecurityProtocolType.Tls11 |
|
||||
SecurityProtocolType.Tls;
|
||||
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||
|
||||
try
|
||||
{
|
||||
IpInfo = CoreUtils.GetIPInfo();
|
||||
Logger?.Info($"Your public IP is {IpInfo.Address}, announcing to master server...");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error(ex.InnerException?.Message ?? ex.Message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
Logger?.Error($"MasterServer: {ex.InnerException.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error($"MasterServer: {ex.Message}");
|
||||
}
|
||||
}
|
||||
if (!CanAnnounce)
|
||||
{
|
||||
var existing = JsonConvert.DeserializeObject<List<ServerInfo>>(HttpHelper.DownloadString(Util.GetFinalRedirect(Settings.MasterServer))).Where(x => x.address == IpInfo.Address && x.port == Settings.Port.ToString()).FirstOrDefault();
|
||||
if(existing != null)
|
||||
{
|
||||
Logger.Warning("Server info already present in master server, waiting for 10 seconds...");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
CanAnnounce = true;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
Security.GetPublicKey(out var pModulus, out var pExpoenet);
|
||||
var serverInfo = new ServerInfo
|
||||
{
|
||||
address = IpInfo.Address,
|
||||
port = Settings.Port.ToString(),
|
||||
country = IpInfo.Country,
|
||||
name = Settings.Name,
|
||||
version = Version.ToString(),
|
||||
players = MainNetServer.ConnectionsCount.ToString(),
|
||||
maxPlayers = Settings.MaxPlayers.ToString(),
|
||||
description = Settings.Description,
|
||||
website = Settings.Website,
|
||||
gameMode = Settings.GameMode,
|
||||
language = Settings.Language,
|
||||
useP2P = Settings.UseP2P,
|
||||
useZT = Settings.UseZeroTier,
|
||||
ztID = Settings.UseZeroTier ? Settings.ZeroTierNetworkID : "",
|
||||
ztAddress = Settings.UseZeroTier ? ZeroTierHelper.Networks[Settings.ZeroTierNetworkID].Addresses.Where(x => !x.Contains(":")).First() : "0.0.0.0",
|
||||
publicKeyModulus = Convert.ToBase64String(pModulus),
|
||||
publicKeyExponent = Convert.ToBase64String(pExpoenet)
|
||||
};
|
||||
string msg = JsonConvert.SerializeObject(serverInfo);
|
||||
|
||||
var realUrl = Util.GetFinalRedirect(Settings.MasterServer);
|
||||
response = httpClient.PostAsync(realUrl, new StringContent(msg, Encoding.UTF8, "application/json")).GetAwaiter().GetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error($"MasterServer: {ex.Message}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (response == null)
|
||||
{
|
||||
Logger?.Error("MasterServer: Something went wrong!");
|
||||
}
|
||||
else if (response.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
if (response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
string requestContent = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
|
||||
Logger?.Error($"MasterServer: [{(int)response.StatusCode}], {requestContent}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger?.Error($"MasterServer: [{(int)response.StatusCode}]");
|
||||
Logger?.Error($"MasterServer: [{response.Content.ReadAsStringAsync().GetAwaiter().GetResult()}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
private void CheckUpdate()
|
||||
{
|
||||
try
|
||||
{
|
||||
var versionLine = HttpHelper.DownloadString(_versionURL).Split('\n', StringSplitOptions.RemoveEmptyEntries).Where(x => x.Contains("[assembly: AssemblyVersion(")).First();
|
||||
var start = versionLine.IndexOf('\"') + 1;
|
||||
var end = versionLine.LastIndexOf('\"');
|
||||
var latest = Version.Parse(versionLine.AsSpan(start, end - start));
|
||||
if (latest <= Version) { return; }
|
||||
|
||||
// wait ten minutes for the build to complete
|
||||
API.SendChatMessage($"New server version found: {latest}, server will update in 10 minutes");
|
||||
Thread.Sleep(10 * 60 * 1000);
|
||||
|
||||
API.SendChatMessage("downloading update...");
|
||||
var downloadURL = $"https://github.com/RAGECOOP/RAGECOOP-V/releases/download/nightly/RageCoop.Server-{CoreUtils.GetInvariantRID()}.zip";
|
||||
if (Directory.Exists("Update")) { Directory.Delete("Update", true); }
|
||||
HttpHelper.DownloadFile(downloadURL, "Update.zip", null);
|
||||
Logger?.Info("Installing update");
|
||||
Directory.CreateDirectory("Update");
|
||||
new FastZip().ExtractZip("Update.zip", "Update", FastZip.Overwrite.Always, null, null, null, true);
|
||||
MainNetServer.Shutdown("Server updating");
|
||||
Logger.Info("Server shutting down!");
|
||||
Logger.Flush();
|
||||
Process.Start(Path.Combine("Update", RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "RageCoop.Server.exe" : "RageCoop.Server"), "update \"" + AppDomain.CurrentDomain.BaseDirectory[0..^1] + "\"");
|
||||
Environment.Exit(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error("Update", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void KickAssholes()
|
||||
{
|
||||
foreach (var c in ClientsByNetHandle.Values.ToArray())
|
||||
{
|
||||
if (c.EntitiesCount > Settings.SpamLimit && Settings.KickSpamming)
|
||||
{
|
||||
c.Kick("Bye bye asshole: spamming");
|
||||
API.SendChatMessage($"Asshole {c.Username} was kicked: Spamming");
|
||||
}
|
||||
else if (Settings.KickGodMode && c.Player.IsInvincible)
|
||||
{
|
||||
c.Kick("Bye bye asshole: godmode");
|
||||
API.SendChatMessage($"Asshole {c.Username} was kicked: GodMode");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Lidgren.Network;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using RageCoop.Core.Scripting;
|
||||
using RageCoop.Server.Scripting;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
@ -43,6 +41,7 @@ namespace RageCoop.Server
|
||||
connection.Deny("Username is already taken!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Security.AddConnection(connection.RemoteEndPoint, packet.AesKeyCrypted, packet.AesIVCrypted);
|
||||
@ -68,6 +67,7 @@ namespace RageCoop.Server
|
||||
connection.Deny("Malformed handshak packet!");
|
||||
return;
|
||||
}
|
||||
|
||||
var handshakeSuccess = MainNetServer.CreateMessage();
|
||||
var currentClients = ClientsByID.Values.ToArray();
|
||||
var players = new Packets.PlayerData[currentClients.Length];
|
||||
@ -79,6 +79,7 @@ namespace RageCoop.Server
|
||||
Username = currentClients[i].Username,
|
||||
};
|
||||
}
|
||||
|
||||
new Packets.HandshakeSuccess()
|
||||
{
|
||||
Players = players
|
||||
@ -146,8 +147,6 @@ namespace RageCoop.Server
|
||||
// Send all blips to this player
|
||||
BaseScript.SendServerBlipsTo(new(Entities.Blips.Values), new() { newClient });
|
||||
|
||||
|
||||
|
||||
// Create P2P connection
|
||||
if (Settings.UseP2P)
|
||||
{
|
||||
@ -181,7 +180,7 @@ namespace RageCoop.Server
|
||||
MainNetServer.SendMessage(outgoingMessage, cons, NetDeliveryMethod.ReliableOrdered, 0);
|
||||
}
|
||||
Entities.CleanUp(localClient);
|
||||
_worker.QueueJob(() => API.Events.InvokePlayerDisconnected(localClient));
|
||||
QueueJob(() => API.Events.InvokePlayerDisconnected(localClient));
|
||||
Logger?.Info($"Player {localClient.Username} disconnected! ID:{localClient.Player.ID}");
|
||||
if (ClientsByNetHandle.ContainsKey(localClient.NetHandle)) { ClientsByNetHandle.Remove(localClient.NetHandle); }
|
||||
if (ClientsByName.ContainsKey(localClient.Username.ToLower())) { ClientsByName.Remove(localClient.Username.ToLower()); }
|
||||
|
@ -1,11 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Lidgren.Network;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using RageCoop.Core.Scripting;
|
||||
using RageCoop.Server.Scripting;
|
||||
|
||||
namespace RageCoop.Server
|
||||
@ -14,12 +8,12 @@ namespace RageCoop.Server
|
||||
{
|
||||
private void PedSync(Packets.PedSync packet, Client client)
|
||||
{
|
||||
_worker.QueueJob(() => Entities.Update(packet, client));
|
||||
QueueJob(() => Entities.Update(packet, client));
|
||||
|
||||
bool isPlayer = packet.ID == client.Player.ID;
|
||||
if (isPlayer)
|
||||
{
|
||||
_worker.QueueJob(() => API.Events.InvokePlayerUpdate(client));
|
||||
QueueJob(() => API.Events.InvokePlayerUpdate(client));
|
||||
}
|
||||
|
||||
if (Settings.UseP2P) { return; }
|
||||
@ -49,7 +43,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
private void VehicleSync(Packets.VehicleSync packet, Client client)
|
||||
{
|
||||
_worker.QueueJob(() => Entities.Update(packet, client));
|
||||
QueueJob(() => Entities.Update(packet, client));
|
||||
bool isPlayer = packet.ID == client.Player?.LastVehicle?.ID;
|
||||
|
||||
|
||||
@ -64,7 +58,6 @@ namespace RageCoop.Server
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
else if ((Settings.NpcStreamingDistance != -1) && (packet.Position.DistanceTo(c.Player.Position) > Settings.NpcStreamingDistance))
|
||||
{
|
||||
@ -72,12 +65,11 @@ namespace RageCoop.Server
|
||||
}
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
packet.Pack(outgoingMessage);
|
||||
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.VehicleSync);
|
||||
}
|
||||
}
|
||||
private void ProjectileSync(Packets.ProjectileSync packet, Client client)
|
||||
{
|
||||
|
||||
if (Settings.UseP2P) { return; }
|
||||
Forward(packet, client, ConnectionChannel.ProjectileSync);
|
||||
}
|
||||
|
@ -1,12 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Lidgren.Network;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using RageCoop.Core.Scripting;
|
||||
using RageCoop.Server.Scripting;
|
||||
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
|
247
RageCoop.Server/Networking/Server.Listener.cs
Normal file
247
RageCoop.Server/Networking/Server.Listener.cs
Normal file
@ -0,0 +1,247 @@
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using RageCoop.Server.Scripting;
|
||||
using System;
|
||||
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
public partial class Server
|
||||
{
|
||||
private void Listen()
|
||||
{
|
||||
NetIncomingMessage msg = null;
|
||||
while (!_stopping)
|
||||
{
|
||||
try
|
||||
{
|
||||
msg = MainNetServer.WaitMessage(200);
|
||||
ProcessMessage(msg);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error("Error processing message");
|
||||
Logger?.Error(ex);
|
||||
if (msg != null)
|
||||
{
|
||||
DisconnectAndLog(msg.SenderConnection, PacketType.Unknown, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
Logger?.Info("Server is shutting down!");
|
||||
MainNetServer.Shutdown("Server is shutting down!");
|
||||
BaseScript.OnStop();
|
||||
Resources.UnloadAll();
|
||||
}
|
||||
|
||||
private void ProcessMessage(NetIncomingMessage message)
|
||||
{
|
||||
Client sender;
|
||||
if (message == null) { return; }
|
||||
switch (message.MessageType)
|
||||
{
|
||||
case NetIncomingMessageType.ConnectionApproval:
|
||||
{
|
||||
Logger?.Info($"New incoming connection from: [{message.SenderConnection.RemoteEndPoint}]");
|
||||
if (message.ReadByte() != (byte)PacketType.Handshake)
|
||||
{
|
||||
Logger?.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: Wrong packet!");
|
||||
message.SenderConnection.Deny("Wrong packet!");
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
GetHandshake(message.SenderConnection, message.GetPacket<Packets.Handshake>());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger?.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: {e.Message}");
|
||||
Logger?.Error(e);
|
||||
message.SenderConnection.Deny(e.Message);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NetIncomingMessageType.StatusChanged:
|
||||
{
|
||||
// Get sender client
|
||||
if (!ClientsByNetHandle.TryGetValue(message.SenderConnection.RemoteUniqueIdentifier, out sender))
|
||||
{
|
||||
break;
|
||||
}
|
||||
NetConnectionStatus status = (NetConnectionStatus)message.ReadByte();
|
||||
|
||||
if (status == NetConnectionStatus.Disconnected)
|
||||
{
|
||||
|
||||
PlayerDisconnected(sender);
|
||||
}
|
||||
else if (status == NetConnectionStatus.Connected)
|
||||
{
|
||||
PlayerConnected(sender);
|
||||
QueueJob(() => API.Events.InvokePlayerConnected(sender));
|
||||
Resources.SendTo(sender);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NetIncomingMessageType.Data:
|
||||
{
|
||||
|
||||
// Get sender client
|
||||
if (ClientsByNetHandle.TryGetValue(message.SenderConnection.RemoteUniqueIdentifier, out sender))
|
||||
{
|
||||
// Get packet type
|
||||
var type = (PacketType)message.ReadByte();
|
||||
switch (type)
|
||||
{
|
||||
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 reqType = (PacketType)message.ReadByte();
|
||||
if (RequestHandlers.TryGetValue(reqType, out var handler))
|
||||
{
|
||||
var response = MainNetServer.CreateMessage();
|
||||
response.Write((byte)PacketType.Response);
|
||||
response.Write(id);
|
||||
handler(message, sender).Pack(response);
|
||||
MainNetServer.SendMessage(response, message.SenderConnection, NetDeliveryMethod.ReliableOrdered);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warning("Did not find a request handler of type: " + reqType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (type.IsSyncEvent())
|
||||
{
|
||||
// Sync Events
|
||||
|
||||
if (Settings.UseP2P) { break; }
|
||||
try
|
||||
{
|
||||
var toSend = MainNetServer.Connections.Exclude(message.SenderConnection);
|
||||
if (toSend.Count != 0)
|
||||
{
|
||||
var outgoingMessage = MainNetServer.CreateMessage();
|
||||
outgoingMessage.Write((byte)type);
|
||||
outgoingMessage.Write(message.ReadBytes(message.LengthBytes - 1));
|
||||
MainNetServer.SendMessage(outgoingMessage, toSend, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.SyncEvents);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DisconnectAndLog(message.SenderConnection, type, e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HandlePacket(type, message, sender);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NetIncomingMessageType.ErrorMessage:
|
||||
Logger?.Error(message.ReadString());
|
||||
break;
|
||||
case NetIncomingMessageType.WarningMessage:
|
||||
Logger?.Warning(message.ReadString());
|
||||
break;
|
||||
case NetIncomingMessageType.DebugMessage:
|
||||
case NetIncomingMessageType.VerboseDebugMessage:
|
||||
Logger?.Debug(message.ReadString());
|
||||
break;
|
||||
case NetIncomingMessageType.UnconnectedData:
|
||||
{
|
||||
if (message.ReadByte() == (byte)PacketType.PublicKeyRequest)
|
||||
{
|
||||
var msg = MainNetServer.CreateMessage();
|
||||
var p = new Packets.PublicKeyResponse();
|
||||
Security.GetPublicKey(out p.Modulus, out p.Exponent);
|
||||
p.Pack(msg);
|
||||
Logger?.Debug($"Sending public key to {message.SenderEndPoint}, length:{msg.LengthBytes}");
|
||||
MainNetServer.SendUnconnectedMessage(msg, message.SenderEndPoint);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Logger?.Error(string.Format("Unhandled type: {0} {1} bytes {2} | {3}", message.MessageType, message.LengthBytes, message.DeliveryMethod, message.SequenceChannel));
|
||||
break;
|
||||
}
|
||||
|
||||
MainNetServer.Recycle(message);
|
||||
}
|
||||
|
||||
private void HandlePacket(PacketType type, NetIncomingMessage msg, Client sender)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PacketType.PedSync:
|
||||
PedSync(msg.GetPacket<Packets.PedSync>(), sender);
|
||||
break;
|
||||
|
||||
case PacketType.VehicleSync:
|
||||
VehicleSync(msg.GetPacket<Packets.VehicleSync>(), sender);
|
||||
break;
|
||||
|
||||
case PacketType.ProjectileSync:
|
||||
ProjectileSync(msg.GetPacket<Packets.ProjectileSync>(), sender);
|
||||
break;
|
||||
|
||||
case PacketType.ChatMessage:
|
||||
{
|
||||
Packets.ChatMessage packet = new((b) =>
|
||||
{
|
||||
return Security.Decrypt(b, sender.EndPoint);
|
||||
});
|
||||
packet.Deserialize(msg);
|
||||
ChatMessageReceived(packet.Username, packet.Message, sender);
|
||||
}
|
||||
break;
|
||||
|
||||
case PacketType.Voice:
|
||||
{
|
||||
if (Settings.UseVoice && !Settings.UseP2P)
|
||||
{
|
||||
Forward(msg.GetPacket<Packets.Voice>(), sender, ConnectionChannel.Voice);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PacketType.CustomEvent:
|
||||
{
|
||||
Packets.CustomEvent packet = new Packets.CustomEvent();
|
||||
packet.Deserialize(msg);
|
||||
QueueJob(() => API.Events.InvokeCustomEventReceived(packet, sender));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Logger?.Error("Unhandled Data / Packet type");
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DisconnectAndLog(sender.Connection, type, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +1,16 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using Newtonsoft.Json;
|
||||
using Lidgren.Network;
|
||||
using System.Timers;
|
||||
using System.Security.Cryptography;
|
||||
using RageCoop.Server.Scripting;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using RageCoop.Core.Scripting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
@ -41,18 +35,20 @@ namespace RageCoop.Server
|
||||
internal readonly Dictionary<int, Client> ClientsByID = new();
|
||||
internal Client _hostClient;
|
||||
|
||||
private Dictionary<int,FileTransfer> InProgressFileTransfers=new();
|
||||
private readonly Dictionary<int, FileTransfer> InProgressFileTransfers = new();
|
||||
internal Resources Resources;
|
||||
internal Logger Logger;
|
||||
private Security Security;
|
||||
internal Security Security;
|
||||
private bool _stopping = false;
|
||||
private Thread _listenerThread;
|
||||
private Thread _announceThread;
|
||||
private Thread _latencyThread;
|
||||
private Worker _worker;
|
||||
private HashSet<char> _allowedCharacterSet;
|
||||
private Dictionary<int,Action<PacketType,byte[]>> PendingResponses=new();
|
||||
internal Dictionary<PacketType, Func<byte[],Client,Packet>> RequestHandlers=new();
|
||||
private readonly Thread _listenerThread;
|
||||
private readonly Timer _announceTimer = new();
|
||||
private readonly Timer _playerUpdateTimer = new();
|
||||
private readonly Timer _antiAssholesTimer = new();
|
||||
private readonly Timer _updateTimer = new();
|
||||
private readonly Worker _worker;
|
||||
private readonly HashSet<char> _allowedCharacterSet;
|
||||
private readonly Dictionary<int, Action<PacketType, NetIncomingMessage>> PendingResponses = new();
|
||||
internal Dictionary<PacketType, Func<NetIncomingMessage, Client, Packet>> RequestHandlers = new();
|
||||
/// <summary>
|
||||
/// Get the current server version
|
||||
/// </summary>
|
||||
@ -80,134 +76,32 @@ namespace RageCoop.Server
|
||||
_worker = new Worker("ServerWorker", Logger);
|
||||
|
||||
_listenerThread = new Thread(() => Listen());
|
||||
_latencyThread=new Thread(() =>
|
||||
{
|
||||
while (!_stopping)
|
||||
{
|
||||
foreach(var c in ClientsByNetHandle.Values.ToArray())
|
||||
{
|
||||
try
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
new Packets.PlayerInfoUpdate()
|
||||
{
|
||||
PedID=c.Player.ID,
|
||||
Username=c.Username,
|
||||
Latency=c.Latency,
|
||||
Position=c.Player.Position
|
||||
}.Pack(outgoingMessage);
|
||||
MainNetServer.SendToAll(outgoingMessage, NetDeliveryMethod.ReliableSequenced, (byte)ConnectionChannel.Default);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Logger?.Error(ex);
|
||||
}
|
||||
}
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
});
|
||||
_announceThread=new Thread(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// TLS only
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
|
||||
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||
|
||||
HttpClient httpClient = new();
|
||||
IpInfo info;
|
||||
try
|
||||
_announceTimer.Interval = 1;
|
||||
_announceTimer.Elapsed += (s, e) =>
|
||||
{
|
||||
info = CoreUtils.GetIPInfo();
|
||||
Logger?.Info($"Your public IP is {info.Address}, announcing to master server...");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error(ex.InnerException?.Message ?? ex.Message);
|
||||
return;
|
||||
}
|
||||
while (!_stopping)
|
||||
{
|
||||
HttpResponseMessage response = null;
|
||||
try
|
||||
{
|
||||
Security.GetPublicKey(out var pModulus,out var pExpoenet);
|
||||
var serverInfo = new ServerInfo
|
||||
{
|
||||
address = info.Address,
|
||||
port=Settings.Port.ToString(),
|
||||
country=info.Country,
|
||||
name=Settings.Name,
|
||||
version=Version.ToString(),
|
||||
players=MainNetServer.ConnectionsCount.ToString(),
|
||||
maxPlayers=Settings.MaxPlayers.ToString(),
|
||||
description=Settings.Description,
|
||||
website=Settings.Website,
|
||||
gameMode=Settings.GameMode,
|
||||
language=Settings.Language,
|
||||
useP2P=Settings.UseP2P,
|
||||
useZT=Settings.UseZeroTier,
|
||||
ztID=Settings.UseZeroTier ? Settings.ZeroTierNetworkID : "",
|
||||
ztAddress=Settings.UseZeroTier ? ZeroTierHelper.Networks[Settings.ZeroTierNetworkID].Addresses.Where(x => !x.Contains(":")).First() : "0.0.0.0",
|
||||
publicKeyModulus=Convert.ToBase64String(pModulus),
|
||||
publicKeyExponent=Convert.ToBase64String(pExpoenet)
|
||||
_announceTimer.Interval = 10000;
|
||||
_announceTimer.Stop();
|
||||
Announce();
|
||||
_announceTimer.Start();
|
||||
};
|
||||
string msg = JsonConvert.SerializeObject(serverInfo);
|
||||
|
||||
var realUrl = Util.GetFinalRedirect(Settings.MasterServer);
|
||||
response = await httpClient.PostAsync(realUrl, new StringContent(msg, Encoding.UTF8, "application/json"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error($"MasterServer: {ex.Message}");
|
||||
_playerUpdateTimer.Interval = 1000;
|
||||
_playerUpdateTimer.Elapsed += (s, e) => SendPlayerUpdate();
|
||||
|
||||
// Sleep for 5s
|
||||
Thread.Sleep(5000);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (response == null)
|
||||
{
|
||||
Logger?.Error("MasterServer: Something went wrong!");
|
||||
}
|
||||
else if (response.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
if (response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
string requestContent = await response.Content.ReadAsStringAsync();
|
||||
Logger?.Error($"MasterServer: [{(int)response.StatusCode}], {requestContent}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger?.Error($"MasterServer: [{(int)response.StatusCode}]");
|
||||
Logger?.Error($"MasterServer: [{await response.Content.ReadAsStringAsync()}]");
|
||||
}
|
||||
}
|
||||
_antiAssholesTimer.Interval = 5000;
|
||||
_antiAssholesTimer.Elapsed += (s, e) => KickAssholes();
|
||||
|
||||
// Sleep for 10s
|
||||
for (int i = 0; i<10; i++)
|
||||
|
||||
_updateTimer.Interval = 1;
|
||||
_updateTimer.Elapsed += (s, e) =>
|
||||
{
|
||||
if (_stopping)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
Logger?.Error($"MasterServer: {ex.InnerException.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error($"MasterServer: {ex.Message}");
|
||||
}
|
||||
});
|
||||
_updateTimer.Interval = 1000 * 60 * 10; // 10 minutes
|
||||
_updateTimer.Stop();
|
||||
CheckUpdate();
|
||||
_updateTimer.Start();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -217,11 +111,22 @@ namespace RageCoop.Server
|
||||
public void Start()
|
||||
{
|
||||
Logger?.Info("================");
|
||||
Logger?.Info($"Server bound to: 0.0.0.0:{Settings.Port}");
|
||||
Logger?.Info($"Listening port: {Settings.Port}");
|
||||
Logger?.Info($"Server version: {Version}");
|
||||
Logger?.Info($"Compatible RAGECOOP versions: {Version.ToString(3)}");
|
||||
Logger?.Info($"Compatible client version: {Version.ToString(3)}");
|
||||
Logger?.Info($"Runtime: {CoreUtils.GetInvariantRID()} => {System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier}");
|
||||
Logger?.Info("================");
|
||||
|
||||
Logger?.Info($"Listening addresses:");
|
||||
foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
|
||||
{
|
||||
Logger?.Info($"[{netInterface.Description}]:");
|
||||
IPInterfaceProperties ipProps = netInterface.GetIPProperties();
|
||||
foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
|
||||
{
|
||||
Logger.Info(string.Join(", ", addr.Address));
|
||||
}
|
||||
Logger.Info("");
|
||||
}
|
||||
if (Settings.UseZeroTier)
|
||||
{
|
||||
Logger?.Info($"Joining ZeroTier network: " + Settings.ZeroTierNetworkID);
|
||||
@ -250,273 +155,42 @@ namespace RageCoop.Server
|
||||
|
||||
MainNetServer = new NetServer(config);
|
||||
MainNetServer.Start();
|
||||
Logger?.Info(string.Format("Server listening on {0}:{1}", config.LocalAddress.ToString(), config.Port));
|
||||
|
||||
BaseScript.API = API;
|
||||
BaseScript.OnStart();
|
||||
Resources.LoadAll();
|
||||
_listenerThread.Start();
|
||||
_latencyThread.Start();
|
||||
Logger?.Info("Listening for clients");
|
||||
|
||||
_playerUpdateTimer.Enabled = true;
|
||||
if (Settings.AnnounceSelf)
|
||||
{
|
||||
_announceThread.Start();
|
||||
_announceTimer.Enabled = true;
|
||||
}
|
||||
if (Settings.AutoUpdate)
|
||||
{
|
||||
_updateTimer.Enabled = true;
|
||||
}
|
||||
_antiAssholesTimer.Enabled = true;
|
||||
|
||||
|
||||
Logger?.Info("Listening for clients");
|
||||
}
|
||||
/// <summary>
|
||||
/// Terminate threads and stop the server
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
_stopping = true;
|
||||
Logger?.Flush();
|
||||
Logger?.Dispose();
|
||||
_stopping = true;
|
||||
_listenerThread.Join();
|
||||
_latencyThread.Join();
|
||||
if (_announceThread.IsAlive)
|
||||
{
|
||||
_announceThread.Join();
|
||||
}
|
||||
_playerUpdateTimer.Enabled = false;
|
||||
_announceTimer.Enabled = false;
|
||||
_worker.Dispose();
|
||||
}
|
||||
private void Listen()
|
||||
{
|
||||
NetIncomingMessage msg=null;
|
||||
while (!_stopping)
|
||||
{
|
||||
try
|
||||
{
|
||||
msg=MainNetServer.WaitMessage(200);
|
||||
ProcessMessage(msg);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Logger?.Error("Error processing message");
|
||||
Logger?.Error(ex);
|
||||
if (msg!=null)
|
||||
{
|
||||
DisconnectAndLog(msg.SenderConnection, PacketType.Unknown, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
Logger?.Info("Server is shutting down!");
|
||||
MainNetServer.Shutdown("Server is shutting down!");
|
||||
BaseScript.OnStop();
|
||||
Resources.UnloadAll();
|
||||
}
|
||||
|
||||
private void ProcessMessage(NetIncomingMessage message)
|
||||
{
|
||||
Client sender;
|
||||
if (message == null) { return; }
|
||||
switch (message.MessageType)
|
||||
{
|
||||
case NetIncomingMessageType.ConnectionApproval:
|
||||
{
|
||||
Logger?.Info($"New incoming connection from: [{message.SenderConnection.RemoteEndPoint}]");
|
||||
if (message.ReadByte() != (byte)PacketType.Handshake)
|
||||
{
|
||||
Logger?.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: Wrong packet!");
|
||||
message.SenderConnection.Deny("Wrong packet!");
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
int len = message.ReadInt32();
|
||||
byte[] data = message.ReadBytes(len);
|
||||
GetHandshake(message.SenderConnection, data.GetPacket<Packets.Handshake>());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger?.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: {e.Message}");
|
||||
Logger?.Error(e);
|
||||
message.SenderConnection.Deny(e.Message);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NetIncomingMessageType.StatusChanged:
|
||||
{
|
||||
// Get sender client
|
||||
if (!ClientsByNetHandle.TryGetValue(message.SenderConnection.RemoteUniqueIdentifier, out sender))
|
||||
{
|
||||
break;
|
||||
}
|
||||
NetConnectionStatus status = (NetConnectionStatus)message.ReadByte();
|
||||
|
||||
if (status == NetConnectionStatus.Disconnected)
|
||||
{
|
||||
|
||||
PlayerDisconnected(sender);
|
||||
}
|
||||
else if (status == NetConnectionStatus.Connected)
|
||||
{
|
||||
PlayerConnected(sender);
|
||||
_worker.QueueJob(() => API.Events.InvokePlayerConnected(sender));
|
||||
Resources.SendTo(sender);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NetIncomingMessageType.Data:
|
||||
{
|
||||
|
||||
// Get sender client
|
||||
if (ClientsByNetHandle.TryGetValue(message.SenderConnection.RemoteUniqueIdentifier, out sender))
|
||||
{
|
||||
// Get packet type
|
||||
var type = (PacketType)message.ReadByte();
|
||||
switch (type)
|
||||
{
|
||||
case PacketType.Response:
|
||||
{
|
||||
int id = message.ReadInt32();
|
||||
if (PendingResponses.TryGetValue(id, out var callback))
|
||||
{
|
||||
callback((PacketType)message.ReadByte(), message.ReadBytes(message.ReadInt32()));
|
||||
PendingResponses.Remove(id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PacketType.Request:
|
||||
{
|
||||
int id = message.ReadInt32();
|
||||
if (RequestHandlers.TryGetValue((PacketType)message.ReadByte(), out var handler))
|
||||
{
|
||||
var response=MainNetServer.CreateMessage();
|
||||
response.Write((byte)PacketType.Response);
|
||||
response.Write(id);
|
||||
handler(message.ReadBytes(message.ReadInt32()),sender).Pack(response);
|
||||
MainNetServer.SendMessage(response,message.SenderConnection,NetDeliveryMethod.ReliableOrdered);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
byte[] data = message.ReadBytes(message.ReadInt32());
|
||||
if (type.IsSyncEvent())
|
||||
{
|
||||
// Sync Events
|
||||
|
||||
if (Settings.UseP2P) { break; }
|
||||
try
|
||||
{
|
||||
var toSend = MainNetServer.Connections.Exclude(message.SenderConnection);
|
||||
if (toSend.Count!=0)
|
||||
{
|
||||
var outgoingMessage = MainNetServer.CreateMessage();
|
||||
outgoingMessage.Write((byte)type);
|
||||
outgoingMessage.Write(data.Length);
|
||||
outgoingMessage.Write(data);
|
||||
MainNetServer.SendMessage(outgoingMessage, toSend, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.SyncEvents);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DisconnectAndLog(message.SenderConnection, type, e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HandlePacket(type, data, sender);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NetIncomingMessageType.ErrorMessage:
|
||||
Logger?.Error(message.ReadString());
|
||||
break;
|
||||
case NetIncomingMessageType.WarningMessage:
|
||||
Logger?.Warning(message.ReadString());
|
||||
break;
|
||||
case NetIncomingMessageType.DebugMessage:
|
||||
case NetIncomingMessageType.VerboseDebugMessage:
|
||||
Logger?.Debug(message.ReadString());
|
||||
break;
|
||||
case NetIncomingMessageType.UnconnectedData:
|
||||
{
|
||||
if (message.ReadByte()==(byte)PacketType.PublicKeyRequest)
|
||||
{
|
||||
var msg = MainNetServer.CreateMessage();
|
||||
var p=new Packets.PublicKeyResponse();
|
||||
Security.GetPublicKey(out p.Modulus,out p.Exponent);
|
||||
p.Pack(msg);
|
||||
Logger?.Debug($"Sending public key to {message.SenderEndPoint}, length:{msg.LengthBytes}");
|
||||
MainNetServer.SendUnconnectedMessage(msg, message.SenderEndPoint);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Logger?.Error(string.Format("Unhandled type: {0} {1} bytes {2} | {3}", message.MessageType, message.LengthBytes, message.DeliveryMethod, message.SequenceChannel));
|
||||
break;
|
||||
}
|
||||
|
||||
MainNetServer.Recycle(message);
|
||||
}
|
||||
internal void QueueJob(Action job)
|
||||
{
|
||||
_worker.QueueJob(job);
|
||||
}
|
||||
private void HandlePacket(PacketType type,byte[] data,Client sender)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PacketType.PedSync:
|
||||
PedSync(data.GetPacket<Packets.PedSync>(), sender);
|
||||
break;
|
||||
|
||||
case PacketType.VehicleSync:
|
||||
VehicleSync(data.GetPacket<Packets.VehicleSync>(), sender);
|
||||
break;
|
||||
|
||||
case PacketType.ProjectileSync:
|
||||
ProjectileSync(data.GetPacket<Packets.ProjectileSync>(), sender);
|
||||
break;
|
||||
|
||||
case PacketType.ChatMessage:
|
||||
{
|
||||
Packets.ChatMessage packet = new((b) =>
|
||||
{
|
||||
return Security.Decrypt(b,sender.EndPoint);
|
||||
});
|
||||
packet.Deserialize(data);
|
||||
ChatMessageReceived(packet.Username,packet.Message, sender);
|
||||
}
|
||||
break;
|
||||
|
||||
case PacketType.Voice:
|
||||
{
|
||||
if (Settings.UseVoice)
|
||||
{
|
||||
Forward(data.GetPacket<Packets.Voice>(), sender, ConnectionChannel.Voice);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PacketType.CustomEvent:
|
||||
{
|
||||
Packets.CustomEvent packet = new Packets.CustomEvent();
|
||||
packet.Deserialize(data);
|
||||
_worker.QueueJob(() => API.Events.InvokeCustomEventReceived(packet, sender));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Logger?.Error("Unhandled Data / Packet type");
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DisconnectAndLog(sender.Connection, type, e);
|
||||
}
|
||||
}
|
||||
|
||||
// Send a message to targets or all players
|
||||
internal void ChatMessageReceived(string name, string message, Client sender = null)
|
||||
@ -525,12 +199,12 @@ namespace RageCoop.Server
|
||||
{
|
||||
string[] cmdArgs = message.Split(" ");
|
||||
string cmdName = cmdArgs[0].Remove(0, 1);
|
||||
_worker.QueueJob(()=>API.Events.InvokeOnCommandReceived(cmdName, cmdArgs, sender));
|
||||
QueueJob(() => API.Events.InvokeOnCommandReceived(cmdName, cmdArgs, sender));
|
||||
return;
|
||||
}
|
||||
message = message.Replace("~", "");
|
||||
|
||||
_worker.QueueJob(() => API.Events.InvokeOnChatMessage(message, sender));
|
||||
QueueJob(() => API.Events.InvokeOnChatMessage(message, sender));
|
||||
|
||||
foreach (var c in ClientsByNetHandle.Values)
|
||||
{
|
||||
@ -546,8 +220,6 @@ namespace RageCoop.Server
|
||||
}.Pack(msg);
|
||||
MainNetServer.SendMessage(msg, c.Connection, NetDeliveryMethod.ReliableOrdered, (int)ConnectionChannel.Chat);
|
||||
}
|
||||
|
||||
Logger?.Info(name + ": " + message);
|
||||
}
|
||||
internal void SendChatMessage(string name, string message, Client target)
|
||||
{
|
||||
@ -604,12 +276,13 @@ namespace RageCoop.Server
|
||||
{
|
||||
throw new InvalidOperationException("Cannot wait for response from the listener thread!");
|
||||
}
|
||||
|
||||
var received = new AutoResetEvent(false);
|
||||
byte[] response=null;
|
||||
T response = new T();
|
||||
var id = NewRequestID();
|
||||
PendingResponses.Add(id, (type,p) =>
|
||||
PendingResponses.Add(id, (type, m) =>
|
||||
{
|
||||
response=p;
|
||||
response.Deserialize(m);
|
||||
received.Set();
|
||||
});
|
||||
var msg = MainNetServer.CreateMessage();
|
||||
@ -619,25 +292,24 @@ namespace RageCoop.Server
|
||||
MainNetServer.SendMessage(msg, client.Connection, NetDeliveryMethod.ReliableOrdered, (int)channel);
|
||||
if (received.WaitOne(timeout))
|
||||
{
|
||||
var p = new T();
|
||||
p.Deserialize(response);
|
||||
return p;
|
||||
return response;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
internal void SendFile(string path, string name, Client client, Action<float> updateCallback = null)
|
||||
{
|
||||
SendFile(File.OpenRead(path), name,client,NewFileID(),updateCallback);
|
||||
var fs = File.OpenRead(path);
|
||||
SendFile(fs, name, client, NewFileID(), updateCallback);
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
internal void SendFile(Stream stream, string name, Client client, int id = default, Action<float> updateCallback = null)
|
||||
{
|
||||
|
||||
id = id ==default? NewFileID(): id ;
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
id = id == default ? NewFileID() : id;
|
||||
var total = stream.Length;
|
||||
Logger?.Debug($"Requesting file transfer:{name}, {total}");
|
||||
if (GetResponse<Packets.FileTransferResponse>(client, new Packets.FileTransferRequest()
|
||||
{
|
||||
FileLength = total,
|
||||
@ -646,8 +318,6 @@ namespace RageCoop.Server
|
||||
}, ConnectionChannel.File)?.Response != FileResponse.NeedToDownload)
|
||||
{
|
||||
Logger?.Info($"Skipping file transfer \"{name}\" to {client.Username}");
|
||||
stream.Close();
|
||||
stream.Dispose();
|
||||
return;
|
||||
}
|
||||
Logger?.Debug($"Initiating file transfer:{name}, {total}");
|
||||
@ -688,8 +358,6 @@ namespace RageCoop.Server
|
||||
{
|
||||
Logger.Warning($"File trasfer to {client.Username} failed: " + name);
|
||||
}
|
||||
stream.Close();
|
||||
stream.Dispose();
|
||||
Logger?.Debug($"All file chunks sent:{name}");
|
||||
InProgressFileTransfers.Remove(id);
|
||||
}
|
||||
|
@ -1,18 +1,40 @@
|
||||
using System;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using RageCoop.Core;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
class Program
|
||||
internal class Program
|
||||
{
|
||||
private static bool Stopping = false;
|
||||
static Logger mainLogger;
|
||||
static void Main(string[] args)
|
||||
private static Logger mainLogger;
|
||||
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
if (args.Length >= 2 && args[0] == "update")
|
||||
{
|
||||
var target = args[1];
|
||||
int i = 0;
|
||||
while (i++ < 10)
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine("Applying update to " + target);
|
||||
|
||||
CoreUtils.CopyFilesRecursively(new(AppDomain.CurrentDomain.BaseDirectory), new(target));
|
||||
Process.Start(Path.Combine(target, "RageCoop.Server"));
|
||||
Environment.Exit(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
Thread.Sleep(3000);
|
||||
}
|
||||
}
|
||||
Environment.Exit(i);
|
||||
}
|
||||
AppDomain.CurrentDomain.UnhandledException += UnhandledException;
|
||||
mainLogger = new Logger()
|
||||
{
|
||||
@ -74,11 +96,11 @@ namespace RageCoop.Server
|
||||
|
||||
private static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
mainLogger.Error($"Unhandled exception thrown from user thread:",e.ExceptionObject as Exception);
|
||||
mainLogger.Error($"Unhandled exception thrown from user thread", e.ExceptionObject as Exception);
|
||||
mainLogger.Flush();
|
||||
}
|
||||
|
||||
static void Fatal(Exception e)
|
||||
private static void Fatal(Exception e)
|
||||
{
|
||||
mainLogger.Error(e);
|
||||
mainLogger.Error($"Fatal error occurred, server shutting down.");
|
||||
|
@ -14,8 +14,8 @@ using System.Resources;
|
||||
[assembly: AssemblyTrademark("RAGECOOP")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Version informationr(
|
||||
[assembly: AssemblyVersion("1.5.1.13")]
|
||||
[assembly: AssemblyFileVersion("1.5.1.13")]
|
||||
// Version information
|
||||
[assembly: AssemblyVersion("1.5.4.5")]
|
||||
[assembly: AssemblyFileVersion("1.5.4.5")]
|
||||
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
|
||||
|
||||
|
@ -32,7 +32,7 @@ using System.Resources;
|
||||
[assembly: AssemblyTrademark("RAGECOOP")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Version informationr(
|
||||
// Version information
|
||||
[assembly: AssemblyVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")]
|
||||
[assembly: AssemblyFileVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")]
|
||||
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
|
||||
|
@ -49,12 +49,12 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Fody" Version="6.6.3">
|
||||
<PackageReference Include="Fody" Version="6.8.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="6.0.8" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="7.0.9" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user