Compare commits
118 Commits
1.5.1
...
resource-b
Author | SHA1 | Date | |
---|---|---|---|
4e6bab1b53 | |||
64692bc161 | |||
8d27c072ca | |||
d7c0abdfc2 | |||
d0b6bbaa3a | |||
411b199a98 | |||
b48b15b652 | |||
e83480b7f9 | |||
d1b4f23992 | |||
42c0ef2159 | |||
8701ac703e | |||
fe53e01a4a | |||
617dbc9812 | |||
1606d25fed | |||
5585876005 | |||
54c7f4ce92 | |||
a062322dda | |||
4599c558e4 | |||
71f7f4b257 | |||
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 Client/Installer/RageCoop.Client.Installer.csproj --configuration Release -o bin/Release/Client
|
||||||
|
- name: Build server win-x64
|
||||||
|
run: dotnet build 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
|
||||||
|
|
21
.github/workflows/nightly-build.yaml
vendored
21
.github/workflows/nightly-build.yaml
vendored
@ -2,9 +2,7 @@ name: Nightly-build
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "main" ]
|
branches: [ "dev-nightly" ]
|
||||||
pull_request:
|
|
||||||
branches: [ "main" ]
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@ -24,15 +22,14 @@ jobs:
|
|||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
- name: Restore nuget packages
|
- name: Restore nuget packages
|
||||||
run: nuget restore
|
run: nuget restore
|
||||||
- name: Build client
|
- name: Build client and installer
|
||||||
run: dotnet build RageCoop.Client/RageCoop.Client.csproj --configuration Release -o bin/Release/Client/RageCoop
|
run: dotnet build RageCoop.Client.Installer/RageCoop.Client.Installer.csproj --configuration Release -o bin/Release/Client/RageCoop
|
||||||
- name: Build server win-x64
|
- 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
|
- 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
|
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
|
||||||
- name: Build server linux-arm
|
- 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-arm -o bin/Release/Server/linux-arm -c Release
|
||||||
|
|
||||||
- uses: vimtor/action-zip@v1
|
- uses: vimtor/action-zip@v1
|
||||||
with:
|
with:
|
||||||
files: bin/Release/Client
|
files: bin/Release/Client
|
||||||
@ -40,17 +37,17 @@ jobs:
|
|||||||
|
|
||||||
- uses: vimtor/action-zip@v1
|
- uses: vimtor/action-zip@v1
|
||||||
with:
|
with:
|
||||||
files: RageCoop.Server/bin/win-x64
|
files: bin/Release/Server/win-x64
|
||||||
dest: RageCoop.Server-win-x64.zip
|
dest: RageCoop.Server-win-x64.zip
|
||||||
|
|
||||||
- uses: vimtor/action-zip@v1
|
- uses: vimtor/action-zip@v1
|
||||||
with:
|
with:
|
||||||
files: RageCoop.Server/bin/linux-x64
|
files: bin/Release/Server/linux-x64
|
||||||
dest: RageCoop.Server-linux-x64.zip
|
dest: RageCoop.Server-linux-x64.zip
|
||||||
|
|
||||||
- uses: vimtor/action-zip@v1
|
- uses: vimtor/action-zip@v1
|
||||||
with:
|
with:
|
||||||
files: RageCoop.Server/bin/linux-arm
|
files: bin/Release/Server/linux-arm
|
||||||
dest: RageCoop.Server-linux-arm.zip
|
dest: RageCoop.Server-linux-arm.zip
|
||||||
|
|
||||||
- uses: WebFreak001/deploy-nightly@v1.1.0
|
- uses: WebFreak001/deploy-nightly@v1.1.0
|
||||||
|
9
Client/Installer/App.xaml
Normal file
9
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
Client/Installer/App.xaml.cs
Normal file
11
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
Client/Installer/AssemblyInfo.cs
Normal file
10
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
Client/Installer/MainWindow.xaml
Normal file
15
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>
|
192
Client/Installer/MainWindow.xaml.cs
Normal file
192
Client/Installer/MainWindow.xaml.cs
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
using RageCoop.Core;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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 scriptsPath = Path.Combine(root, "Scripts");
|
||||||
|
var installPath = Path.Combine(root, "RageCoop", "Scripts");
|
||||||
|
var legacyPath = Path.Combine(scriptsPath, "RageCoop");
|
||||||
|
if (Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName.StartsWith(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.");
|
||||||
|
}
|
||||||
|
if (!File.Exists(shvPath))
|
||||||
|
{
|
||||||
|
MessageBox.Show("Please install ScriptHookV first!");
|
||||||
|
Environment.Exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory.CreateDirectory(installPath);
|
||||||
|
|
||||||
|
File.Copy("ScriptHookVDotNet.dll", Path.Combine(root, "ScriptHookVDotNet.asi"), true);
|
||||||
|
File.Copy("ScriptHookVDotNet3.dll", Path.Combine(root, "ScriptHookVDotNet3.dll"), true);
|
||||||
|
|
||||||
|
|
||||||
|
UpdateStatus("Removing old versions");
|
||||||
|
|
||||||
|
foreach (var f in Directory.GetFiles(scriptsPath, "RageCoop.*", SearchOption.AllDirectories))
|
||||||
|
{
|
||||||
|
File.Delete(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.5 installation check
|
||||||
|
if (Directory.Exists(legacyPath))
|
||||||
|
{
|
||||||
|
Directory.Delete(legacyPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var f in Directory.GetFiles(installPath, "*.dll", SearchOption.AllDirectories))
|
||||||
|
{
|
||||||
|
File.Delete(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists("RageCoop.Core.dll") && File.Exists("RageCoop.Client.dll") && File.Exists("RageCoop.Client.Loader.dll"))
|
||||||
|
{
|
||||||
|
UpdateStatus("Installing...");
|
||||||
|
CoreUtils.CopyFilesRecursively(new DirectoryInfo(Directory.GetCurrentDirectory()), new DirectoryInfo(installPath));
|
||||||
|
File.Copy("RageCoop.Client.Loader.dll", Path.Combine(scriptsPath, "RageCoop.Client.Loader.dll"), true);
|
||||||
|
Finish();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Required files are missing, please re-download the installer from official website");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Finish()
|
||||||
|
{
|
||||||
|
|
||||||
|
checkKeys:
|
||||||
|
UpdateStatus("Checking conflicts");
|
||||||
|
var menyooConfig = Path.Combine(root, @"menyooStuff\menyooConfig.ini");
|
||||||
|
var settingsPath = Path.Combine(root, Util.SettingsPath);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
54
Client/Installer/RageCoop.Client.Installer.csproj
Normal file
54
Client/Installer/RageCoop.Client.Installer.csproj
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<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>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
|
||||||
|
<OutDir>..\..\bin\Debug\Client</OutDir>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefineConstants>DEBUG</DefineConstants>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<NoWarn>1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||||
|
<OutDir>..\..\bin\Release\Client</OutDir>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Core\RageCoop.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\Loader\RageCoop.Client.Loader.csproj" />
|
||||||
|
<ProjectReference Include="..\Scripts\RageCoop.Client.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>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Resources\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
9
Client/Installer/RageCoop.Client.Installer.csproj.user
Normal file
9
Client/Installer/RageCoop.Client.Installer.csproj.user
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup />
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Update="Resource.resx">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</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>
|
63
Client/Installer/Resource.Designer.cs
generated
Normal file
63
Client/Installer/Resource.Designer.cs
generated
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
121
Client/Installer/Resource.resx
Normal file
121
Client/Installer/Resource.resx
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?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" />
|
||||||
|
</root>
|
BIN
Client/Installer/bg.png
Normal file
BIN
Client/Installer/bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 MiB |
205
Client/Loader/LoaderContext.cs
Normal file
205
Client/Loader/LoaderContext.cs
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
using SHVDN;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using Console = GTA.Console;
|
||||||
|
|
||||||
|
namespace RageCoop.Client.Loader
|
||||||
|
{
|
||||||
|
|
||||||
|
public class LoaderContext : MarshalByRefObject, IDisposable
|
||||||
|
{
|
||||||
|
#region PRIMARY-LOADING-LOGIC
|
||||||
|
public static ConcurrentDictionary<string, LoaderContext> LoadedDomains => new ConcurrentDictionary<string, LoaderContext>(_loadedDomains);
|
||||||
|
|
||||||
|
private static readonly ConcurrentDictionary<string, LoaderContext> _loadedDomains = new ConcurrentDictionary<string, LoaderContext>();
|
||||||
|
|
||||||
|
public bool UnloadRequested;
|
||||||
|
public string BaseDirectory => AppDomain.CurrentDomain.BaseDirectory;
|
||||||
|
private ScriptDomain CurrentDomain => ScriptDomain.CurrentDomain;
|
||||||
|
public static void CheckForUnloadRequest()
|
||||||
|
{
|
||||||
|
lock (_loadedDomains)
|
||||||
|
{
|
||||||
|
foreach (var p in _loadedDomains.Values)
|
||||||
|
{
|
||||||
|
if (p.UnloadRequested)
|
||||||
|
{
|
||||||
|
Unload(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsLoaded(string dir)
|
||||||
|
{
|
||||||
|
return _loadedDomains.ContainsKey(Path.GetFullPath(dir).ToLower());
|
||||||
|
}
|
||||||
|
public static LoaderContext Load(string dir)
|
||||||
|
{
|
||||||
|
lock (_loadedDomains)
|
||||||
|
{
|
||||||
|
dir = Path.GetFullPath(dir).ToLower();
|
||||||
|
if (IsLoaded(dir))
|
||||||
|
{
|
||||||
|
throw new Exception("Already loaded");
|
||||||
|
}
|
||||||
|
ScriptDomain newDomain = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
dir = Path.GetFullPath(dir).ToLower();
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
Exception e = null;
|
||||||
|
// Load domain in main thread
|
||||||
|
Main.QueueToMainThread(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
var assemblies = new List<string>();
|
||||||
|
assemblies.Add(typeof(DomainLoader).Assembly.Location);
|
||||||
|
assemblies.AddRange(typeof(DomainLoader).Assembly.GetReferencedAssemblies()
|
||||||
|
.Select(x => Assembly.Load(x.FullName).Location)
|
||||||
|
.Where(x => !string.IsNullOrEmpty(x)));
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Delete API assemblies
|
||||||
|
Directory.GetFiles(dir, "ScriptHookVDotNet*", SearchOption.AllDirectories).ToList().ForEach(x => File.Delete(x));
|
||||||
|
var ctxAsm = Path.Combine(dir, "RageCoop.Client.Loader.dll");
|
||||||
|
if (File.Exists(ctxAsm)) { File.Delete(ctxAsm); }
|
||||||
|
|
||||||
|
newDomain = ScriptDomain.Load(
|
||||||
|
Directory.GetParent(typeof(ScriptDomain).Assembly.Location).FullName, dir);
|
||||||
|
newDomain.AppDomain.SetData("Primary", ScriptDomain.CurrentDomain);
|
||||||
|
newDomain.AppDomain.SetData("Console", ScriptDomain.CurrentDomain.AppDomain.GetData("Console"));
|
||||||
|
var context = (LoaderContext)newDomain.AppDomain.CreateInstanceFromAndUnwrap(
|
||||||
|
typeof(LoaderContext).Assembly.Location,
|
||||||
|
typeof(LoaderContext).FullName, ignoreCase: false,
|
||||||
|
BindingFlags.Instance | BindingFlags.NonPublic,
|
||||||
|
null,
|
||||||
|
new object[] { }
|
||||||
|
, null, null);
|
||||||
|
newDomain.AppDomain.SetData("RageCoop.Client.LoaderContext", context);
|
||||||
|
newDomain.Start();
|
||||||
|
_loadedDomains.TryAdd(dir, context);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
e = ex;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Wait till next tick
|
||||||
|
GTA.Script.Yield();
|
||||||
|
if (e != null) { throw e; }
|
||||||
|
return _loadedDomains[dir];
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
GTA.UI.Notification.Show(ex.ToString());
|
||||||
|
Console.Error(ex);
|
||||||
|
if (newDomain != null)
|
||||||
|
{
|
||||||
|
ScriptDomain.Unload(newDomain);
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Unload(LoaderContext domain)
|
||||||
|
{
|
||||||
|
lock (_loadedDomains)
|
||||||
|
{
|
||||||
|
Exception ex = null;
|
||||||
|
var name = domain.CurrentDomain.Name;
|
||||||
|
Console.Info("Unloading domain: " + name);
|
||||||
|
Main.QueueToMainThread(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!_loadedDomains.TryRemove(domain.BaseDirectory.ToLower(), out _))
|
||||||
|
{
|
||||||
|
throw new Exception("Failed to remove domain from list");
|
||||||
|
}
|
||||||
|
domain.Dispose();
|
||||||
|
ScriptDomain.Unload(domain.CurrentDomain);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
ex = e;
|
||||||
|
GTA.UI.Notification.Show(ex.ToString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
GTA.Script.Yield();
|
||||||
|
if (ex != null)
|
||||||
|
{
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
Console.Info("Unloaded domain: " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void Unload(string dir)
|
||||||
|
{
|
||||||
|
Unload(_loadedDomains[Path.GetFullPath(dir).ToLower()]);
|
||||||
|
}
|
||||||
|
public static void UnloadAll()
|
||||||
|
{
|
||||||
|
lock (_loadedDomains)
|
||||||
|
{
|
||||||
|
foreach (var d in _loadedDomains.Values.ToArray())
|
||||||
|
{
|
||||||
|
Unload(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region LOAD-CONTEXT
|
||||||
|
|
||||||
|
|
||||||
|
private LoaderContext()
|
||||||
|
{
|
||||||
|
AppDomain.CurrentDomain.DomainUnload += (s, e) => Dispose();
|
||||||
|
PrimaryDomain.Tick += Tick;
|
||||||
|
PrimaryDomain.KeyEvent += KeyEvent;
|
||||||
|
Console.Info($"Loaded domain: {AppDomain.CurrentDomain.FriendlyName}, {AppDomain.CurrentDomain.BaseDirectory}");
|
||||||
|
}
|
||||||
|
public static ScriptDomain PrimaryDomain => AppDomain.CurrentDomain.GetData("Primary") as ScriptDomain;
|
||||||
|
public static LoaderContext CurrentContext => AppDomain.CurrentDomain.GetData("RageCoop.Client.LoaderContext") as LoaderContext;
|
||||||
|
/// <summary>
|
||||||
|
/// Request the current domain to be unloaded
|
||||||
|
/// </summary>
|
||||||
|
public static void RequestUnload()
|
||||||
|
{
|
||||||
|
if (PrimaryDomain == null)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Current domain not loaded by the loader therfore cannot be unloaded automatically");
|
||||||
|
}
|
||||||
|
CurrentContext.UnloadRequested = true;
|
||||||
|
}
|
||||||
|
private void Tick()
|
||||||
|
{
|
||||||
|
CurrentDomain.DoTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void KeyEvent(Keys keys, bool status)
|
||||||
|
{
|
||||||
|
CurrentDomain.DoKeyEvent(keys, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (PrimaryDomain == null) { return; }
|
||||||
|
PrimaryDomain.Tick -= Tick;
|
||||||
|
PrimaryDomain.KeyEvent -= KeyEvent;
|
||||||
|
AppDomain.CurrentDomain.SetData("Primary", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
69
Client/Loader/Main.cs
Normal file
69
Client/Loader/Main.cs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
using GTA;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using Console = GTA.Console;
|
||||||
|
namespace RageCoop.Client.Loader
|
||||||
|
{
|
||||||
|
public class Main : GTA.Script
|
||||||
|
{
|
||||||
|
private static readonly string GameDir = Directory.GetParent(typeof(SHVDN.ScriptDomain).Assembly.Location).FullName;
|
||||||
|
private static readonly string ScriptsLocation = Path.Combine(GameDir, "RageCoop", "Scripts");
|
||||||
|
private static readonly ConcurrentQueue<Action> TaskQueue = new ConcurrentQueue<Action>();
|
||||||
|
private static int MainThreadID;
|
||||||
|
public Main()
|
||||||
|
{
|
||||||
|
if (LoaderContext.PrimaryDomain != null) { throw new InvalidOperationException("Improperly placed loader assembly, please re-install to fix this issue"); }
|
||||||
|
Tick += OnTick;
|
||||||
|
SHVDN.ScriptDomain.CurrentDomain.Tick += DomainTick;
|
||||||
|
Aborted += (s, e) => LoaderContext.UnloadAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTick(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
while (Game.IsLoading)
|
||||||
|
{
|
||||||
|
GTA.Script.Yield();
|
||||||
|
}
|
||||||
|
LoaderContext.CheckForUnloadRequest();
|
||||||
|
if (!LoaderContext.IsLoaded(ScriptsLocation))
|
||||||
|
{
|
||||||
|
if (!File.Exists(Path.Combine(ScriptsLocation, "RageCoop.Client.dll")))
|
||||||
|
{
|
||||||
|
GTA.UI.Notification.Show("~r~Main assembly is missing, please re-install the client");
|
||||||
|
Abort();
|
||||||
|
}
|
||||||
|
LoaderContext.Load(ScriptsLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void QueueToMainThread(Action task)
|
||||||
|
{
|
||||||
|
if (Thread.CurrentThread.ManagedThreadId != MainThreadID)
|
||||||
|
{
|
||||||
|
TaskQueue.Enqueue(task);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
task();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DomainTick()
|
||||||
|
{
|
||||||
|
if (MainThreadID == default) { MainThreadID = Thread.CurrentThread.ManagedThreadId; }
|
||||||
|
while (TaskQueue.TryDequeue(out var task))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
task.Invoke();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.Error(ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
Client/Loader/Properties/AssemblyInfo.cs
Normal file
35
Client/Loader/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("RageCoop.Client.Loader")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("RageCoop.Client.Loader")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2022")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("fc8cbdbb-6dc3-43af-b34d-092e476410a5")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
58
Client/Loader/RageCoop.Client.Loader.csproj
Normal file
58
Client/Loader/RageCoop.Client.Loader.csproj
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{FC8CBDBB-6DC3-43AF-B34D-092E476410A5}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>RageCoop.Client.Loader</RootNamespace>
|
||||||
|
<AssemblyName>RageCoop.Client.Loader</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<OutPutPath>..\..\bin\Debug\Client.Loader</OutPutPath>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<OutPutPath>..\..\bin\Release\Client.Loader</OutPutPath>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="ScriptHookVDotNet">
|
||||||
|
<HintPath>..\..\libs\ScriptHookVDotNet.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="ScriptHookVDotNet3">
|
||||||
|
<HintPath>..\..\libs\ScriptHookVDotNet3.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="LoaderContext.cs" />
|
||||||
|
<Compile Include="Main.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
@ -7,6 +7,7 @@ using System.Windows.Forms;
|
|||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
|
[ScriptAttributes(Author = "RageCoop", NoDefaultInstance = false, SupportURL = "https://github.com/RAGECOOP/RAGECOOP-V")]
|
||||||
internal class DevTool : Script
|
internal class DevTool : Script
|
||||||
{
|
{
|
||||||
public static Vehicle ToMark;
|
public static Vehicle ToMark;
|
||||||
@ -14,10 +15,14 @@ namespace RageCoop.Client
|
|||||||
public static int Current = 0;
|
public static int Current = 0;
|
||||||
public static int Secondary = 0;
|
public static int Secondary = 0;
|
||||||
public static MuzzleDir Direction = MuzzleDir.Forward;
|
public static MuzzleDir Direction = MuzzleDir.Forward;
|
||||||
|
public static Script Instance;
|
||||||
public DevTool()
|
public DevTool()
|
||||||
{
|
{
|
||||||
|
Util.StartUpCheck();
|
||||||
|
Instance = this;
|
||||||
Tick += OnTick;
|
Tick += OnTick;
|
||||||
KeyDown += OnKeyDown;
|
KeyDown += OnKeyDown;
|
||||||
|
Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnKeyDown(object sender, KeyEventArgs e)
|
private void OnKeyDown(object sender, KeyEventArgs e)
|
||||||
@ -73,7 +78,7 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
DevToolMenu.secondaryBoneIndexItem.AltTitle = Secondary.ToString();
|
DevToolMenu.secondaryBoneIndexItem.AltTitle = Secondary.ToString();
|
||||||
}
|
}
|
||||||
private static void OnTick(object sender, EventArgs e)
|
private void OnTick(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (ToMark == null || !ToMark.Exists()) { return; }
|
if (ToMark == null || !ToMark.Exists()) { return; }
|
||||||
Update();
|
Update();
|
@ -2,25 +2,28 @@
|
|||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
using RageCoop.Client.Menus;
|
using RageCoop.Client.Menus;
|
||||||
|
using RageCoop.Client.Scripting;
|
||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
|
using SHVDN;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Threading.Tasks;
|
using Console = GTA.Console;
|
||||||
using System.Threading;
|
using Script = GTA.Script;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Don't use it!
|
/// Don't use it!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[ScriptAttributes(Author = "RageCoop", NoDefaultInstance = false, SupportURL = "https://github.com/RAGECOOP/RAGECOOP-V")]
|
||||||
internal class Main : Script
|
internal class Main : Script
|
||||||
{
|
{
|
||||||
private bool _gameLoaded = false;
|
private static bool _gameLoaded = false;
|
||||||
internal static Version Version = typeof(Main).Assembly.GetName().Version;
|
internal static Version Version = typeof(Main).Assembly.GetName().Version;
|
||||||
|
|
||||||
internal static int LocalPlayerID = 0;
|
internal static int LocalPlayerID = 0;
|
||||||
@ -28,51 +31,79 @@ namespace RageCoop.Client
|
|||||||
internal static RelationshipGroup SyncedPedsGroup;
|
internal static RelationshipGroup SyncedPedsGroup;
|
||||||
|
|
||||||
internal static new Settings Settings = null;
|
internal static new Settings Settings = null;
|
||||||
internal static Scripting.BaseScript BaseScript = new Scripting.BaseScript();
|
|
||||||
|
|
||||||
#if !NON_INTERACTIVE
|
#if !NON_INTERACTIVE
|
||||||
#endif
|
#endif
|
||||||
internal static Chat MainChat = null;
|
internal static Chat MainChat = null;
|
||||||
internal static Stopwatch Counter = new Stopwatch();
|
internal static Stopwatch Counter = new Stopwatch();
|
||||||
internal static Logger Logger = null;
|
internal static Logger Logger = null;
|
||||||
|
|
||||||
internal static ulong Ticked = 0;
|
internal static ulong Ticked = 0;
|
||||||
internal static Vector3 PlayerPosition;
|
internal static Vector3 PlayerPosition;
|
||||||
internal static Scripting.Resources Resources = null;
|
internal static Resources Resources = null;
|
||||||
private static List<Func<bool>> QueuedActions = new List<Func<bool>>();
|
private static readonly ConcurrentQueue<Action> TaskQueue = new ConcurrentQueue<Action>();
|
||||||
public static Worker Worker;
|
public static string LogPath => $"{Settings.DataDirectory}\\RageCoop.Client.log";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Don't use it!
|
/// Don't use it!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Main()
|
public Main()
|
||||||
{
|
{
|
||||||
#if DEBUG_HIGH_PING
|
Util.StartUpCheck();
|
||||||
Networking.SimulatedLatency=0.3f;
|
Console.Info($"Starting {typeof(Main).FullName}, domain: {AppDomain.CurrentDomain.Id} {AppDomain.CurrentDomain.FriendlyName}");
|
||||||
#endif
|
|
||||||
Worker = new Worker("RageCoop.Client.Main.Worker", Logger);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Settings = Util.ReadSettings();
|
Settings = Util.ReadSettings();
|
||||||
|
if (Settings.DataDirectory.StartsWith("Scripts"))
|
||||||
|
{
|
||||||
|
var defaultDir = new Settings().DataDirectory;
|
||||||
|
Console.Warning("Data directory must be outside scripts folder, migrating to default direcoty: " + defaultDir);
|
||||||
|
if (Directory.Exists(Settings.DataDirectory))
|
||||||
|
{
|
||||||
|
CoreUtils.CopyFilesRecursively(new DirectoryInfo(Settings.DataDirectory), new DirectoryInfo(defaultDir));
|
||||||
|
Directory.Delete(Settings.DataDirectory, true);
|
||||||
|
}
|
||||||
|
Settings.DataDirectory = defaultDir;
|
||||||
|
Util.SaveSettings();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
GTA.UI.Notification.Show("Malformed configuration, overwriting with default values...");
|
// GTA.UI.Notification.Show("Malformed configuration, overwriting with default values...");
|
||||||
Settings = new Settings();
|
Settings = new Settings();
|
||||||
Util.SaveSettings();
|
Util.SaveSettings();
|
||||||
}
|
}
|
||||||
Directory.CreateDirectory(Settings.DataDirectory);
|
Directory.CreateDirectory(Settings.DataDirectory);
|
||||||
Logger = new Logger()
|
Logger = new Logger()
|
||||||
{
|
{
|
||||||
LogPath=$"{Settings.DataDirectory}\\RageCoop.Client.log",
|
Writers = new List<StreamWriter> { CoreUtils.OpenWriter(LogPath) },
|
||||||
UseConsole=false,
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
LogLevel = 0,
|
LogLevel = 0,
|
||||||
#else
|
#else
|
||||||
LogLevel = Settings.LogLevel,
|
LogLevel = Settings.LogLevel,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
Resources = new Scripting.Resources();
|
Logger.OnFlush += (line, formatted) =>
|
||||||
|
{
|
||||||
|
switch (line.LogLevel)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
// case LogLevel.Trace:
|
||||||
|
case LogLevel.Debug:
|
||||||
|
Console.Info(line.Message);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case LogLevel.Info:
|
||||||
|
Console.Info(line.Message);
|
||||||
|
break;
|
||||||
|
case LogLevel.Warning:
|
||||||
|
Console.Warning(line.Message);
|
||||||
|
break;
|
||||||
|
case LogLevel.Error:
|
||||||
|
Console.Error(line.Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ScriptDomain.CurrentDomain.Tick += DomainTick;
|
||||||
|
Resources = new Resources();
|
||||||
if (Game.Version < GameVersion.v1_0_1290_1_Steam)
|
if (Game.Version < GameVersion.v1_0_1290_1_Steam)
|
||||||
{
|
{
|
||||||
Tick += (object sender, EventArgs e) =>
|
Tick += (object sender, EventArgs e) =>
|
||||||
@ -95,41 +126,78 @@ namespace RageCoop.Client
|
|||||||
#if !NON_INTERACTIVE
|
#if !NON_INTERACTIVE
|
||||||
#endif
|
#endif
|
||||||
MainChat = new Chat();
|
MainChat = new Chat();
|
||||||
|
Aborted += OnAborted;
|
||||||
Tick += OnTick;
|
Tick += OnTick;
|
||||||
Tick += (s, e) => { Scripting.API.Events.InvokeTick(); };
|
|
||||||
KeyDown += OnKeyDown;
|
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();
|
|
||||||
|
|
||||||
Util.NativeMemory();
|
Util.NativeMemory();
|
||||||
Counter.Restart();
|
Counter.Restart();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnAborted(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
WorldThread.Instance?.Abort();
|
||||||
|
DevTool.Instance?.Abort();
|
||||||
|
ScriptDomain.CurrentDomain.Tick -= DomainTick;
|
||||||
|
Disconnected("Abort");
|
||||||
|
WorldThread.DoQueuedActions();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DomainTick()
|
||||||
|
{
|
||||||
|
while (TaskQueue.TryDequeue(out var task))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
task.Invoke();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Networking.IsOnServer)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
EntityPool.DoSync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue an action to main thread and wait for execution to complete, must be called from script thread.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task"></param>
|
||||||
|
internal static void QueueToMainThreadAndWait(Action task)
|
||||||
|
{
|
||||||
|
Exception e = null;
|
||||||
|
TaskQueue.Enqueue(() => { try { task(); } catch (Exception ex) { e = ex; } });
|
||||||
|
Yield();
|
||||||
|
if (e != null) { throw e; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Ped P;
|
public static Ped P;
|
||||||
public static float FPS;
|
public static float FPS;
|
||||||
private bool _lastDead;
|
private static bool _lastDead;
|
||||||
private void OnTick(object sender, EventArgs e)
|
private static 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;
|
P = Game.Player.Character;
|
||||||
PlayerPosition = P.ReadPosition();
|
PlayerPosition = P.ReadPosition();
|
||||||
FPS = Game.FPS;
|
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)
|
if (Game.IsLoading)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -146,7 +214,6 @@ namespace RageCoop.Client
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
DoQueuedActions();
|
|
||||||
if (!Networking.IsOnServer)
|
if (!Networking.IsOnServer)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -155,14 +222,6 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
Game.TimeScale = 1;
|
Game.TimeScale = 1;
|
||||||
}
|
}
|
||||||
try
|
|
||||||
{
|
|
||||||
EntityPool.DoSync();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Main.Logger.Error(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Networking.ShowNetworkInfo)
|
if (Networking.ShowNetworkInfo)
|
||||||
{
|
{
|
||||||
@ -173,7 +232,7 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
MainChat.Tick();
|
MainChat.Tick();
|
||||||
PlayerList.Tick();
|
PlayerList.Tick();
|
||||||
if (!Scripting.API.Config.EnableAutoRespawn)
|
if (!API.Config.EnableAutoRespawn)
|
||||||
{
|
{
|
||||||
Function.Call(Hash.PAUSE_DEATH_ARREST_RESTART, true);
|
Function.Call(Hash.PAUSE_DEATH_ARREST_RESTART, true);
|
||||||
Function.Call(Hash.IGNORE_NEXT_RESTART, true);
|
Function.Call(Hash.IGNORE_NEXT_RESTART, true);
|
||||||
@ -187,8 +246,8 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
P.Health = 1;
|
P.Health = 1;
|
||||||
Game.Player.WantedLevel = 0;
|
Game.Player.WantedLevel = 0;
|
||||||
Main.Logger.Debug("Player died.");
|
Logger.Debug("Player died.");
|
||||||
Scripting.API.Events.InvokePlayerDied();
|
API.Events.InvokePlayerDied();
|
||||||
}
|
}
|
||||||
GTA.UI.Screen.StopEffects();
|
GTA.UI.Screen.StopEffects();
|
||||||
}
|
}
|
||||||
@ -199,13 +258,13 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
else if (P.IsDead && !_lastDead)
|
else if (P.IsDead && !_lastDead)
|
||||||
{
|
{
|
||||||
Scripting.API.Events.InvokePlayerDied();
|
API.Events.InvokePlayerDied();
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastDead = P.IsDead;
|
_lastDead = P.IsDead;
|
||||||
Ticked++;
|
Ticked++;
|
||||||
}
|
}
|
||||||
private void OnKeyDown(object sender, KeyEventArgs e)
|
private static void OnKeyDown(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (MainChat.Focused)
|
if (MainChat.Focused)
|
||||||
{
|
{
|
||||||
@ -273,25 +332,6 @@ namespace RageCoop.Client
|
|||||||
PlayerList.Pressed = (currentTimestamp - PlayerList.Pressed) < 5000 ? (currentTimestamp - 6000) : currentTimestamp;
|
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)
|
else if (e.KeyCode == Settings.PassengerKey)
|
||||||
{
|
{
|
||||||
var P = Game.Player.Character;
|
var P = Game.Player.Character;
|
||||||
@ -309,76 +349,69 @@ namespace RageCoop.Client
|
|||||||
if (V != null)
|
if (V != null)
|
||||||
{
|
{
|
||||||
var seat = P.GetNearestSeat(V);
|
var seat = P.GetNearestSeat(V);
|
||||||
P.Task.EnterVehicle(V, seat);
|
var p = V.GetPedOnSeat(seat);
|
||||||
}
|
if (p != null && !p.IsDead)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static void CleanUp()
|
|
||||||
{
|
{
|
||||||
MainChat.Clear();
|
for (int i = -1; i < V.PassengerCapacity; i++)
|
||||||
Voice.ClearAll();
|
|
||||||
EntityPool.Cleanup();
|
|
||||||
PlayerList.Cleanup();
|
|
||||||
LocalPlayerID=default;
|
|
||||||
WorldThread.Traffic(true);
|
|
||||||
}
|
|
||||||
private static void DoQueuedActions()
|
|
||||||
{
|
{
|
||||||
lock (QueuedActions)
|
seat = (VehicleSeat)i;
|
||||||
|
p = V.GetPedOnSeat(seat);
|
||||||
|
if (p == null || p.IsDead)
|
||||||
{
|
{
|
||||||
foreach (var action in QueuedActions.ToArray())
|
break;
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (action())
|
|
||||||
{
|
|
||||||
QueuedActions.Remove(action);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
}
|
||||||
{
|
P.Task.EnterVehicle(V, seat, -1, 5, EnterVehicleFlags.None);
|
||||||
Logger.Error(ex);
|
|
||||||
QueuedActions.Remove(action);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a"> An action to be executed with a return value indicating whether the action can be removed after execution.</param>
|
|
||||||
internal static void QueueAction(Func<bool> a)
|
|
||||||
{
|
|
||||||
lock (QueuedActions)
|
|
||||||
{
|
|
||||||
QueuedActions.Add(a);
|
|
||||||
}
|
}
|
||||||
|
internal static void Connected()
|
||||||
|
{
|
||||||
|
Memory.ApplyPatches();
|
||||||
|
if (Settings.Voice && !Voice.WasInitialized())
|
||||||
|
{
|
||||||
|
Voice.Init();
|
||||||
}
|
}
|
||||||
internal static void QueueAction(Action a)
|
API.QueueAction(() =>
|
||||||
{
|
{
|
||||||
lock (QueuedActions)
|
WorldThread.Traffic(!Settings.DisableTraffic);
|
||||||
{
|
Function.Call(Hash.SET_ENABLE_VEHICLE_SLIPSTREAMING, true);
|
||||||
QueuedActions.Add(() => { a(); return true; });
|
CoopMenu.ConnectedMenuSetting();
|
||||||
}
|
MainChat.Init();
|
||||||
}
|
GTA.UI.Notification.Show("~g~Connected!");
|
||||||
/// <summary>
|
|
||||||
/// Clears all queued actions
|
|
||||||
/// </summary>
|
|
||||||
internal static void ClearQueuedActions()
|
|
||||||
{
|
|
||||||
lock (QueuedActions) { QueuedActions.Clear(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Delay(Action a, int time)
|
|
||||||
{
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
Thread.Sleep(time);
|
|
||||||
QueueAction(a);
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
Logger.Info(">> Connected <<");
|
||||||
|
}
|
||||||
|
public static void Disconnected(string reason)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
Logger.Info($">> Disconnected << reason: {reason}");
|
||||||
|
API.QueueAction(() =>
|
||||||
|
{
|
||||||
|
if (MainChat.Focused)
|
||||||
|
{
|
||||||
|
MainChat.Focused = false;
|
||||||
|
}
|
||||||
|
PlayerList.Cleanup();
|
||||||
|
MainChat.Clear();
|
||||||
|
EntityPool.Cleanup();
|
||||||
|
WorldThread.Traffic(true);
|
||||||
|
Function.Call(Hash.SET_ENABLE_VEHICLE_SLIPSTREAMING, false);
|
||||||
|
CoopMenu.DisconnectedMenuSetting();
|
||||||
|
GTA.UI.Notification.Show("~r~Disconnected: " + reason);
|
||||||
|
LocalPlayerID = default;
|
||||||
|
Resources.Unload();
|
||||||
|
});
|
||||||
|
Memory.RestorePatches();
|
||||||
|
DownloadManager.Cleanup();
|
||||||
|
Voice.ClearAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using GTA;
|
using GTA;
|
||||||
|
using GTA.Native;
|
||||||
using LemonUI;
|
using LemonUI;
|
||||||
using LemonUI.Menus;
|
using LemonUI.Menus;
|
||||||
using LemonUI.Scaleform;
|
using LemonUI.Scaleform;
|
||||||
@ -69,7 +70,6 @@ namespace RageCoop.Client.Menus
|
|||||||
Menu.AddSubMenu(DebugMenu.Menu);
|
Menu.AddSubMenu(DebugMenu.Menu);
|
||||||
Menu.AddSubMenu(UpdateMenu.Menu);
|
Menu.AddSubMenu(UpdateMenu.Menu);
|
||||||
|
|
||||||
|
|
||||||
MenuPool.Add(Menu);
|
MenuPool.Add(Menu);
|
||||||
MenuPool.Add(SettingsMenu.Menu);
|
MenuPool.Add(SettingsMenu.Menu);
|
||||||
MenuPool.Add(DevToolMenu.Menu);
|
MenuPool.Add(DevToolMenu.Menu);
|
||||||
@ -96,6 +96,16 @@ namespace RageCoop.Client.Menus
|
|||||||
{
|
{
|
||||||
Game.DisableAllControlsThisFrame();
|
Game.DisableAllControlsThisFrame();
|
||||||
MenuPool.Process();
|
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))
|
if (Game.IsControlJustPressed(Control.FrontendAccept))
|
||||||
{
|
{
|
||||||
PopUp.Visible = false;
|
PopUp.Visible = false;
|
||||||
@ -107,6 +117,8 @@ namespace RageCoop.Client.Menus
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Script.Yield();
|
Script.Yield();
|
||||||
|
Game.DisableAllControlsThisFrame();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void UsernameActivated(object a, System.EventArgs b)
|
public static void UsernameActivated(object a, System.EventArgs b)
|
@ -1,7 +1,7 @@
|
|||||||
using GTA;
|
using GTA;
|
||||||
using LemonUI.Menus;
|
using LemonUI.Menus;
|
||||||
using System.Drawing;
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
@ -17,7 +17,9 @@ namespace RageCoop.Client
|
|||||||
UseMouse = false,
|
UseMouse = false,
|
||||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||||
};
|
};
|
||||||
|
public static NativeItem ReloadItem = new NativeItem("Reload", "Reload RAGECOOP and associated scripts");
|
||||||
public static NativeItem SimulatedLatencyItem = new NativeItem("Simulated network latency", "Simulated network latency in ms (one way)", "0");
|
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);
|
private static readonly NativeCheckboxItem ShowNetworkInfoItem = new NativeCheckboxItem("Show Network Info", Networking.ShowNetworkInfo);
|
||||||
|
|
||||||
static DebugMenu()
|
static DebugMenu()
|
||||||
@ -44,12 +46,19 @@ namespace RageCoop.Client
|
|||||||
catch (Exception ex) { Main.Logger.Error(ex); }
|
catch (Exception ex) { Main.Logger.Error(ex); }
|
||||||
};
|
};
|
||||||
ShowNetworkInfoItem.CheckboxChanged += (s, e) => { Networking.ShowNetworkInfo = ShowNetworkInfoItem.Checked; };
|
ShowNetworkInfoItem.CheckboxChanged += (s, e) => { Networking.ShowNetworkInfo = ShowNetworkInfoItem.Checked; };
|
||||||
|
ShowOwnerItem.CheckboxChanged += (s, e) => { Main.Settings.ShowEntityOwnerName = ShowOwnerItem.Checked; Util.SaveSettings(); };
|
||||||
|
ReloadItem.Activated += ReloadDomain;
|
||||||
Menu.Add(SimulatedLatencyItem);
|
Menu.Add(SimulatedLatencyItem);
|
||||||
Menu.Add(ShowNetworkInfoItem);
|
Menu.Add(ShowNetworkInfoItem);
|
||||||
|
Menu.Add(ShowOwnerItem);
|
||||||
|
Menu.Add(ReloadItem);
|
||||||
Menu.AddSubMenu(DiagnosticMenu);
|
Menu.AddSubMenu(DiagnosticMenu);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ReloadDomain(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Loader.LoaderContext.RequestUnload();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,9 +12,9 @@ namespace RageCoop.Client
|
|||||||
UseMouse = false,
|
UseMouse = false,
|
||||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
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 boneIndexItem = new NativeItem("Current bone index");
|
||||||
public static NativeItem secondaryBoneIndexItem = new NativeItem("Secondary bone index");
|
public static NativeItem secondaryBoneIndexItem = new NativeItem("Secondary bone index");
|
||||||
public static NativeItem clipboardItem = new NativeItem("Copy to clipboard");
|
public static NativeItem clipboardItem = new NativeItem("Copy to clipboard");
|
||||||
@ -73,10 +73,12 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
if (enableItem.Checked)
|
if (enableItem.Checked)
|
||||||
{
|
{
|
||||||
|
DevTool.Instance.Resume();
|
||||||
DevTool.ToMark = Game.Player.Character.CurrentVehicle;
|
DevTool.ToMark = Game.Player.Character.CurrentVehicle;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
DevTool.Instance.Pause();
|
||||||
DevTool.ToMark = null;
|
DevTool.ToMark = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,12 +1,13 @@
|
|||||||
using LemonUI.Menus;
|
using GTA.UI;
|
||||||
|
using LemonUI.Menus;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using RageCoop.Client.Scripting;
|
||||||
|
using RageCoop.Core;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using RageCoop.Core;
|
|
||||||
using GTA.UI;
|
|
||||||
|
|
||||||
namespace RageCoop.Client.Menus
|
namespace RageCoop.Client.Menus
|
||||||
{
|
{
|
||||||
@ -60,7 +61,7 @@ namespace RageCoop.Client.Menus
|
|||||||
serverList = JsonConvert.DeserializeObject<List<ServerInfo>>(DownloadString(realUrl));
|
serverList = JsonConvert.DeserializeObject<List<ServerInfo>>(DownloadString(realUrl));
|
||||||
|
|
||||||
// Need to be processed in main thread
|
// Need to be processed in main thread
|
||||||
Main.QueueAction(() =>
|
API.QueueAction(() =>
|
||||||
{
|
{
|
||||||
if (serverList == null)
|
if (serverList == null)
|
||||||
{
|
{
|
||||||
@ -85,7 +86,7 @@ namespace RageCoop.Client.Menus
|
|||||||
if (server.useZT)
|
if (server.useZT)
|
||||||
{
|
{
|
||||||
address = $"{server.ztAddress}:{server.port}";
|
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)
|
if (ZeroTierHelper.Join(server.ztID) == null)
|
||||||
{
|
{
|
||||||
throw new Exception("Failed to obtain ZeroTier network IP");
|
throw new Exception("Failed to obtain ZeroTier network IP");
|
||||||
@ -127,7 +128,7 @@ namespace RageCoop.Client.Menus
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Main.QueueAction(() =>
|
API.QueueAction(() =>
|
||||||
{
|
{
|
||||||
ResultItem.Title = "Download failed!";
|
ResultItem.Title = "Download failed!";
|
||||||
ResultItem.Description = ex.Message;
|
ResultItem.Description = ex.Message;
|
@ -16,12 +16,12 @@ 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 _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 _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 _disableVoice = new NativeCheckboxItem("Enable voice", "Check your GTA:V settings to find the right key on your keyboard for PushToTalk and talk to your friends", Main.Settings.Voice);
|
private static readonly NativeCheckboxItem _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 readonly 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 readonly 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 _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());
|
||||||
|
|
||||||
static SettingsMenu()
|
static SettingsMenu()
|
||||||
{
|
{
|
||||||
@ -53,7 +53,9 @@ namespace RageCoop.Client.Menus
|
|||||||
{
|
{
|
||||||
Voice.Init();
|
Voice.Init();
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Voice.ClearAll();
|
Voice.ClearAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +110,7 @@ namespace RageCoop.Client.Menus
|
|||||||
|
|
||||||
public static void DisableTrafficCheckboxChanged(object a, System.EventArgs b)
|
public static void DisableTrafficCheckboxChanged(object a, System.EventArgs b)
|
||||||
{
|
{
|
||||||
|
WorldThread.Traffic(!_disableTrafficItem.Checked);
|
||||||
Main.Settings.DisableTraffic = _disableTrafficItem.Checked;
|
Main.Settings.DisableTraffic = _disableTrafficItem.Checked;
|
||||||
Util.SaveSettings();
|
Util.SaveSettings();
|
||||||
}
|
}
|
@ -1,5 +1,7 @@
|
|||||||
using ICSharpCode.SharpZipLib.Zip;
|
using ICSharpCode.SharpZipLib.Zip;
|
||||||
using LemonUI.Menus;
|
using LemonUI.Menus;
|
||||||
|
using RageCoop.Client.Scripting;
|
||||||
|
using RageCoop.Core;
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -11,10 +13,10 @@ namespace RageCoop.Client.Menus
|
|||||||
internal class UpdateMenu
|
internal class UpdateMenu
|
||||||
{
|
{
|
||||||
public static bool IsUpdating { get; private set; } = false;
|
public static bool IsUpdating { get; private set; } = false;
|
||||||
private static NativeItem _updatingItem = new NativeItem("Updating...");
|
private static readonly NativeItem _updatingItem = new NativeItem("Updating...");
|
||||||
private static NativeItem _downloadItem = new NativeItem("Download", "Download and update to latest nightly");
|
private static readonly NativeItem _downloadItem = new NativeItem("Download", "Download and update to latest nightly");
|
||||||
|
|
||||||
private static string _downloadPath = Path.Combine(Main.Settings.DataDirectory, "RageCoop.Client.zip");
|
private static readonly 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")
|
public static NativeMenu Menu = new NativeMenu("Update", "Update", "Download and install latest nightly build from GitHub")
|
||||||
{
|
{
|
||||||
UseMouse = false,
|
UseMouse = false,
|
||||||
@ -30,6 +32,11 @@ namespace RageCoop.Client.Menus
|
|||||||
|
|
||||||
private static void StartUpdate(object sender, EventArgs e)
|
private static void StartUpdate(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (CoreUtils.GetLatestVersion() < Main.Version)
|
||||||
|
{
|
||||||
|
GTA.UI.Notification.Show("Local version is newer than remote version, update can't continue");
|
||||||
|
return;
|
||||||
|
}
|
||||||
IsUpdating = true;
|
IsUpdating = true;
|
||||||
Menu.Clear();
|
Menu.Clear();
|
||||||
Menu.Add(_updatingItem);
|
Menu.Add(_updatingItem);
|
||||||
@ -45,7 +52,7 @@ namespace RageCoop.Client.Menus
|
|||||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
|
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
|
||||||
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||||
|
|
||||||
client.DownloadProgressChanged += (s, e1) => { Main.QueueAction(() => { _updatingItem.AltTitle=$"{e1.ProgressPercentage}%"; }); };
|
client.DownloadProgressChanged += (s, e1) => { API.QueueAction(() => { _updatingItem.AltTitle = $"{e1.ProgressPercentage}%"; }); };
|
||||||
client.DownloadFileCompleted += (s, e2) => { Install(); };
|
client.DownloadFileCompleted += (s, e2) => { Install(); };
|
||||||
client.DownloadFileAsync(new Uri("https://github.com/RAGECOOP/RAGECOOP-V/releases/download/nightly/RageCoop.Client.zip"), _downloadPath);
|
client.DownloadFileAsync(new Uri("https://github.com/RAGECOOP/RAGECOOP-V/releases/download/nightly/RageCoop.Client.zip"), _downloadPath);
|
||||||
}
|
}
|
||||||
@ -60,22 +67,22 @@ namespace RageCoop.Client.Menus
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Main.QueueAction(() =>
|
API.QueueAction(() =>
|
||||||
{
|
{
|
||||||
_updatingItem.AltTitle = "Installing...";
|
_updatingItem.AltTitle = "Installing...";
|
||||||
});
|
});
|
||||||
Directory.CreateDirectory(@"Scripts\RageCoop");
|
var insatllPath = @"RageCoop\Scripts";
|
||||||
foreach(var f in Directory.GetFiles(@"Scripts\RageCoop", "*.dll", SearchOption.AllDirectories))
|
Directory.CreateDirectory(insatllPath);
|
||||||
|
foreach (var f in Directory.GetFiles(insatllPath, "*.dll", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
try { File.Delete(f); }
|
try { File.Delete(f); }
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
new FastZip().ExtractZip(_downloadPath, "Scripts", FastZip.Overwrite.Always, null, null, null, true);
|
new FastZip().ExtractZip(_downloadPath, insatllPath, FastZip.Overwrite.Always, null, null, null, true);
|
||||||
Main.QueueAction(() =>
|
try { File.Delete(_downloadPath); } catch { }
|
||||||
{
|
try { File.Delete(Path.Combine(insatllPath, "RageCoop.Client.Installer.exe")); } catch { }
|
||||||
Util.Reload();
|
Loader.LoaderContext.RequestUnload();
|
||||||
IsUpdating = false;
|
IsUpdating = false;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
@ -16,7 +16,7 @@ namespace RageCoop.Client
|
|||||||
private bool CurrentFocused { get; set; }
|
private bool CurrentFocused { get; set; }
|
||||||
public bool Focused
|
public bool Focused
|
||||||
{
|
{
|
||||||
get { return CurrentFocused; }
|
get => CurrentFocused;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value && Hidden)
|
if (value && Hidden)
|
||||||
@ -35,7 +35,7 @@ namespace RageCoop.Client
|
|||||||
private bool CurrentHidden { get; set; }
|
private bool CurrentHidden { get; set; }
|
||||||
private bool Hidden
|
private bool Hidden
|
||||||
{
|
{
|
||||||
get { return CurrentHidden; }
|
get => CurrentHidden;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value)
|
if (value)
|
@ -49,7 +49,7 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Main.Logger.Error("Error occurred when loading server resource:");
|
Main.Logger.Error("Error occurred when loading server resource");
|
||||||
Main.Logger.Error(ex);
|
Main.Logger.Error(ex);
|
||||||
return new Packets.FileTransferResponse() { ID = 0, Response = FileResponse.LoadFailed };
|
return new Packets.FileTransferResponse() { ID = 0, Response = FileResponse.LoadFailed };
|
||||||
}
|
}
|
||||||
@ -122,8 +122,7 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
lock (InProgressDownloads)
|
lock (InProgressDownloads)
|
||||||
{
|
{
|
||||||
DownloadFile file;
|
if (InProgressDownloads.TryGetValue(id, out DownloadFile file))
|
||||||
if (InProgressDownloads.TryGetValue(id, out file))
|
|
||||||
{
|
{
|
||||||
|
|
||||||
file.Stream.Write(chunk, 0, chunk.Length);
|
file.Stream.Write(chunk, 0, chunk.Length);
|
||||||
@ -137,9 +136,8 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
public static void Complete(int id)
|
public static void Complete(int id)
|
||||||
{
|
{
|
||||||
DownloadFile f;
|
|
||||||
|
|
||||||
if (InProgressDownloads.TryGetValue(id, out f))
|
if (InProgressDownloads.TryGetValue(id, out DownloadFile f))
|
||||||
{
|
{
|
||||||
InProgressDownloads.Remove(id);
|
InProgressDownloads.Remove(id);
|
||||||
f.Dispose();
|
f.Dispose();
|
@ -1,12 +1,10 @@
|
|||||||
using System;
|
using Lidgren.Network;
|
||||||
|
using RageCoop.Core;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Timers;
|
|
||||||
using RageCoop.Core;
|
|
||||||
using Lidgren.Network;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Timers;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
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))
|
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();
|
var msg = Networking.Peer.CreateMessage();
|
||||||
new Packets.HolePunch
|
new Packets.HolePunch
|
||||||
{
|
{
|
||||||
@ -69,7 +67,7 @@ namespace RageCoop.Client
|
|||||||
puncher.HolePunchStatus = (byte)(p.Status + 1);
|
puncher.HolePunchStatus = (byte)(p.Status + 1);
|
||||||
if (p.Status >= 3)
|
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))
|
if (puncher.ConnectWhenPunched && (puncher.Connection == null || puncher.Connection.Status == NetConnectionStatus.Disconnected))
|
||||||
{
|
{
|
||||||
Main.Logger.Debug("Connecting to peer: " + from);
|
Main.Logger.Debug("Connecting to peer: " + from);
|
@ -1,12 +1,13 @@
|
|||||||
using Lidgren.Network;
|
using GTA.UI;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using RageCoop.Client.Scripting;
|
||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GTA.UI;
|
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
@ -17,14 +18,15 @@ namespace RageCoop.Client
|
|||||||
public static bool ShowNetworkInfo = false;
|
public static bool ShowNetworkInfo = false;
|
||||||
public static Security Security;
|
public static Security Security;
|
||||||
public static NetConnection ServerConnection;
|
public static NetConnection ServerConnection;
|
||||||
private static readonly Dictionary<int, Action<PacketType, byte[]>> PendingResponses = new Dictionary<int, Action<PacketType, byte[]>>();
|
private static readonly Dictionary<int, Action<PacketType, NetIncomingMessage>> PendingResponses = new Dictionary<int, Action<PacketType, NetIncomingMessage>>();
|
||||||
internal static readonly Dictionary<PacketType, Func<byte[], Packet>> RequestHandlers = new Dictionary<PacketType, Func<byte[], Packet>>();
|
internal static readonly Dictionary<PacketType, Func<NetIncomingMessage, Packet>> RequestHandlers = new Dictionary<PacketType, Func<NetIncomingMessage, Packet>>();
|
||||||
internal static float SimulatedLatency = 0;
|
internal static float SimulatedLatency = 0;
|
||||||
public static bool IsConnecting { get; private set; }
|
public static bool IsConnecting { get; private set; }
|
||||||
public static IPEndPoint _targetServerEP;
|
public static IPEndPoint _targetServerEP;
|
||||||
static Networking()
|
static Networking()
|
||||||
{
|
{
|
||||||
Security = new Security(Main.Logger);
|
Security = new Security(Main.Logger);
|
||||||
|
Packets.CustomEvent.ResolveHandle = _resolveHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ToggleConnection(string address, string username = null, string password = null, PublicKey publicKey = null)
|
public static void ToggleConnection(string address, string username = null, string password = null, PublicKey publicKey = null)
|
||||||
@ -35,7 +37,8 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
// ?
|
// ?
|
||||||
}
|
}
|
||||||
else if (IsConnecting) {
|
else if (IsConnecting)
|
||||||
|
{
|
||||||
_publicKeyReceived.Set();
|
_publicKeyReceived.Set();
|
||||||
IsConnecting = false;
|
IsConnecting = false;
|
||||||
Notification.Show("Connection has been canceled");
|
Notification.Show("Connection has been canceled");
|
||||||
@ -88,6 +91,8 @@ namespace RageCoop.Client
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_targetServerEP = CoreUtils.StringToEndPoint(address);
|
_targetServerEP = CoreUtils.StringToEndPoint(address);
|
||||||
|
|
||||||
|
// Ensure static constructor invocation
|
||||||
DownloadManager.Cleanup();
|
DownloadManager.Cleanup();
|
||||||
Peer = new CoopPeer(config);
|
Peer = new CoopPeer(config);
|
||||||
Peer.OnMessageReceived += (s, m) =>
|
Peer.OnMessageReceived += (s, m) =>
|
||||||
@ -95,17 +100,19 @@ namespace RageCoop.Client
|
|||||||
try { ProcessMessage(m); }
|
try { ProcessMessage(m); }
|
||||||
catch (Exception ex) { Main.Logger.Error(ex); }
|
catch (Exception ex) { Main.Logger.Error(ex); }
|
||||||
};
|
};
|
||||||
Main.QueueAction(() => { Notification.Show($"~y~Trying to connect..."); });
|
API.QueueAction(() => { Notification.Show($"~y~Trying to connect..."); });
|
||||||
Menus.CoopMenu._serverConnectItem.Enabled = false;
|
Menus.CoopMenu._serverConnectItem.Enabled = false;
|
||||||
Security.Regen();
|
Security.Regen();
|
||||||
if(publicKey==null){
|
if (publicKey == null)
|
||||||
|
{
|
||||||
if (!GetServerPublicKey(ip[0], int.Parse(ip[1])))
|
if (!GetServerPublicKey(ip[0], int.Parse(ip[1])))
|
||||||
{
|
{
|
||||||
Menus.CoopMenu._serverConnectItem.Enabled = true;
|
Menus.CoopMenu._serverConnectItem.Enabled = true;
|
||||||
throw new TimeoutException("Failed to retrive server's public key");
|
throw new TimeoutException("Failed to retrive server's public key");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else
|
||||||
|
{
|
||||||
Security.SetServerPublicKey(publicKey.Modulus, publicKey.Exponent);
|
Security.SetServerPublicKey(publicKey.Modulus, publicKey.Exponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,26 +135,26 @@ namespace RageCoop.Client
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Main.Logger.Error("Cannot connect to server: ", ex);
|
Main.Logger.Error("Cannot connect to server: ", ex);
|
||||||
Main.QueueAction(() => Notification.Show("Cannot connect to server: "+ex.Message));
|
API.QueueAction(() => Notification.Show("Cannot connect to server: " + ex.Message));
|
||||||
}
|
}
|
||||||
IsConnecting = false;
|
IsConnecting = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static bool IsOnServer { get => ServerConnection?.Status == NetConnectionStatus.Connected; }
|
public static bool IsOnServer => ServerConnection?.Status == NetConnectionStatus.Connected;
|
||||||
|
|
||||||
#region -- PLAYER --
|
#region -- PLAYER --
|
||||||
private static void PlayerConnect(Packets.PlayerConnect packet)
|
private static void PlayerConnect(Packets.PlayerConnect packet)
|
||||||
{
|
{
|
||||||
var p = new Player
|
var p = new Player
|
||||||
{
|
{
|
||||||
PedID = packet.PedID,
|
ID = packet.PedID,
|
||||||
Username = packet.Username,
|
Username = packet.Username,
|
||||||
};
|
};
|
||||||
PlayerList.SetPlayer(packet.PedID, packet.Username);
|
PlayerList.SetPlayer(packet.PedID, packet.Username);
|
||||||
|
|
||||||
Main.Logger.Debug($"player connected:{p.Username}");
|
Main.Logger.Debug($"player connected:{p.Username}");
|
||||||
Main.QueueAction(() =>
|
API.QueueAction(() =>
|
||||||
GTA.UI.Notification.Show($"~h~{p.Username}~h~ connected."));
|
GTA.UI.Notification.Show($"~h~{p.Username}~h~ connected."));
|
||||||
}
|
}
|
||||||
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
|
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
|
||||||
@ -155,7 +162,8 @@ namespace RageCoop.Client
|
|||||||
var player = PlayerList.GetPlayer(packet.PedID);
|
var player = PlayerList.GetPlayer(packet.PedID);
|
||||||
if (player == null) { return; }
|
if (player == null) { return; }
|
||||||
PlayerList.RemovePlayer(packet.PedID);
|
PlayerList.RemovePlayer(packet.PedID);
|
||||||
Main.QueueAction(() => {
|
API.QueueAction(() =>
|
||||||
|
{
|
||||||
EntityPool.RemoveAllFromPlayer(packet.PedID);
|
EntityPool.RemoveAllFromPlayer(packet.PedID);
|
||||||
GTA.UI.Notification.Show($"~h~{player.Username}~h~ left.");
|
GTA.UI.Notification.Show($"~h~{player.Username}~h~ left.");
|
||||||
});
|
});
|
@ -1,9 +1,10 @@
|
|||||||
using GTA;
|
using GTA;
|
||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
using RageCoop.Client.Menus;
|
using RageCoop.Client.Menus;
|
||||||
|
using RageCoop.Client.Scripting;
|
||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
|
using RageCoop.Core.Scripting;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
@ -14,7 +15,7 @@ namespace RageCoop.Client
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reduce GC pressure by reusing frequently used packets
|
/// Reduce GC pressure by reusing frequently used packets
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static class ReceivedPackets
|
private static class ReceivedPackets
|
||||||
{
|
{
|
||||||
public static Packets.PedSync PedPacket = new Packets.PedSync();
|
public static Packets.PedSync PedPacket = new Packets.PedSync();
|
||||||
public static Packets.VehicleSync VehicelPacket = new Packets.VehicleSync();
|
public static Packets.VehicleSync VehicelPacket = new Packets.VehicleSync();
|
||||||
@ -24,7 +25,7 @@ namespace RageCoop.Client
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to reslove entity handle in a <see cref="Packets.CustomEvent"/>
|
/// Used to reslove entity handle in a <see cref="Packets.CustomEvent"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly Func<byte, BitReader, object> _resolveHandle = (t, reader) =>
|
private static readonly Func<byte, NetIncomingMessage, object> _resolveHandle = (t, reader) =>
|
||||||
{
|
{
|
||||||
switch (t)
|
switch (t)
|
||||||
{
|
{
|
||||||
@ -41,10 +42,11 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
private static readonly AutoResetEvent _publicKeyReceived = new AutoResetEvent(false);
|
private static readonly AutoResetEvent _publicKeyReceived = new AutoResetEvent(false);
|
||||||
|
private static bool _recycle;
|
||||||
public static void ProcessMessage(NetIncomingMessage message)
|
public static void ProcessMessage(NetIncomingMessage message)
|
||||||
{
|
{
|
||||||
if (message == null) { return; }
|
if (message == null) { return; }
|
||||||
|
_recycle = true;
|
||||||
switch (message.MessageType)
|
switch (message.MessageType)
|
||||||
{
|
{
|
||||||
case NetIncomingMessageType.StatusChanged:
|
case NetIncomingMessageType.StatusChanged:
|
||||||
@ -61,30 +63,18 @@ namespace RageCoop.Client
|
|||||||
case NetConnectionStatus.Connected:
|
case NetConnectionStatus.Connected:
|
||||||
if (message.SenderConnection == ServerConnection)
|
if (message.SenderConnection == ServerConnection)
|
||||||
{
|
{
|
||||||
Memory.ApplyPatches();
|
|
||||||
var response = message.SenderConnection.RemoteHailMessage;
|
var response = message.SenderConnection.RemoteHailMessage;
|
||||||
if ((PacketType)response.ReadByte() != PacketType.HandshakeSuccess)
|
if ((PacketType)response.ReadByte() != PacketType.HandshakeSuccess)
|
||||||
{
|
{
|
||||||
throw new Exception("Invalid handshake response!");
|
throw new Exception("Invalid handshake response!");
|
||||||
}
|
}
|
||||||
var p = new Packets.HandshakeSuccess();
|
var p = new Packets.HandshakeSuccess();
|
||||||
p.Deserialize(response.ReadBytes(response.ReadInt32()));
|
p.Deserialize(response);
|
||||||
foreach (var player in p.Players)
|
foreach (var player in p.Players)
|
||||||
{
|
{
|
||||||
PlayerList.SetPlayer(player.ID, player.Username);
|
PlayerList.SetPlayer(player.ID, player.Username);
|
||||||
}
|
}
|
||||||
Main.QueueAction(() =>
|
Main.Connected();
|
||||||
{
|
|
||||||
CoopMenu.ConnectedMenuSetting();
|
|
||||||
Main.MainChat.Init();
|
|
||||||
if (Main.Settings.Voice && !Voice.WasInitialized())
|
|
||||||
{
|
|
||||||
Voice.Init();
|
|
||||||
}
|
|
||||||
GTA.UI.Notification.Show("~g~Connected!");
|
|
||||||
});
|
|
||||||
|
|
||||||
Main.Logger.Info(">> Connected <<");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -107,19 +97,7 @@ namespace RageCoop.Client
|
|||||||
case NetConnectionStatus.Disconnected:
|
case NetConnectionStatus.Disconnected:
|
||||||
if (message.SenderConnection == ServerConnection)
|
if (message.SenderConnection == ServerConnection)
|
||||||
{
|
{
|
||||||
Memory.RestorePatches();
|
Main.Disconnected(reason);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -139,7 +117,7 @@ namespace RageCoop.Client
|
|||||||
int id = message.ReadInt32();
|
int id = message.ReadInt32();
|
||||||
if (PendingResponses.TryGetValue(id, out var callback))
|
if (PendingResponses.TryGetValue(id, out var callback))
|
||||||
{
|
{
|
||||||
callback((PacketType)message.ReadByte(), message.ReadBytes(message.ReadInt32()));
|
callback((PacketType)message.ReadByte(), message);
|
||||||
PendingResponses.Remove(id);
|
PendingResponses.Remove(id);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -148,32 +126,34 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
int id = message.ReadInt32();
|
int id = message.ReadInt32();
|
||||||
var realType = (PacketType)message.ReadByte();
|
var realType = (PacketType)message.ReadByte();
|
||||||
int len = message.ReadInt32();
|
|
||||||
if (RequestHandlers.TryGetValue(realType, out var handler))
|
if (RequestHandlers.TryGetValue(realType, out var handler))
|
||||||
{
|
{
|
||||||
var response = Peer.CreateMessage();
|
var response = Peer.CreateMessage();
|
||||||
response.Write((byte)PacketType.Response);
|
response.Write((byte)PacketType.Response);
|
||||||
response.Write(id);
|
response.Write(id);
|
||||||
handler(message.ReadBytes(len)).Pack(response);
|
handler(message).Pack(response);
|
||||||
Peer.SendMessage(response, ServerConnection, NetDeliveryMethod.ReliableOrdered, message.SequenceChannel);
|
Peer.SendMessage(response, ServerConnection, NetDeliveryMethod.ReliableOrdered, message.SequenceChannel);
|
||||||
Peer.FlushSendQueue();
|
Peer.FlushSendQueue();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Main.Logger.Debug("Did not find a request handler of type: " + realType);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
byte[] data = message.ReadBytes(message.ReadInt32());
|
|
||||||
|
|
||||||
HandlePacket(packetType, data,message.SenderConnection);
|
HandlePacket(packetType, message, message.SenderConnection, ref _recycle);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Main.QueueAction(() =>
|
API.QueueAction(() =>
|
||||||
{
|
{
|
||||||
GTA.UI.Notification.Show("~r~~h~Packet Error");
|
GTA.UI.Notification.Show($"~r~~h~Packet Error {ex.Message}");
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
Main.Logger.Error($"[{packetType}] {ex.Message}");
|
Main.Logger.Error($"[{packetType}] {ex.Message}");
|
||||||
@ -185,20 +165,18 @@ namespace RageCoop.Client
|
|||||||
case NetIncomingMessageType.UnconnectedData:
|
case NetIncomingMessageType.UnconnectedData:
|
||||||
{
|
{
|
||||||
var packetType = (PacketType)message.ReadByte();
|
var packetType = (PacketType)message.ReadByte();
|
||||||
int len = message.ReadInt32();
|
|
||||||
byte[] data = message.ReadBytes(len);
|
|
||||||
switch (packetType)
|
switch (packetType)
|
||||||
{
|
{
|
||||||
|
|
||||||
case PacketType.HolePunch:
|
case PacketType.HolePunch:
|
||||||
{
|
{
|
||||||
HolePunch.Punched(data.GetPacket<Packets.HolePunch>(), message.SenderEndPoint);
|
HolePunch.Punched(message.GetPacket<Packets.HolePunch>(), message.SenderEndPoint);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PacketType.PublicKeyResponse:
|
case PacketType.PublicKeyResponse:
|
||||||
{
|
{
|
||||||
if (message.SenderEndPoint.ToString() != _targetServerEP.ToString() || !IsConnecting) { break; }
|
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);
|
Security.SetServerPublicKey(packet.Modulus, packet.Exponent);
|
||||||
_publicKeyReceived.Set();
|
_publicKeyReceived.Set();
|
||||||
break;
|
break;
|
||||||
@ -215,41 +193,42 @@ namespace RageCoop.Client
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (_recycle)
|
||||||
|
{
|
||||||
Peer.Recycle(message);
|
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)
|
switch (packetType)
|
||||||
{
|
{
|
||||||
case PacketType.HolePunchInit:
|
case PacketType.HolePunchInit:
|
||||||
HolePunch.Add(data.GetPacket<Packets.HolePunchInit>());
|
HolePunch.Add(msg.GetPacket<Packets.HolePunchInit>());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.PlayerConnect:
|
case PacketType.PlayerConnect:
|
||||||
PlayerConnect(data.GetPacket<Packets.PlayerConnect>());
|
PlayerConnect(msg.GetPacket<Packets.PlayerConnect>());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.PlayerDisconnect:
|
case PacketType.PlayerDisconnect:
|
||||||
PlayerDisconnect(data.GetPacket<Packets.PlayerDisconnect>());
|
PlayerDisconnect(msg.GetPacket<Packets.PlayerDisconnect>());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.PlayerInfoUpdate:
|
case PacketType.PlayerInfoUpdate:
|
||||||
PlayerList.UpdatePlayer(data.GetPacket<Packets.PlayerInfoUpdate>());
|
PlayerList.UpdatePlayer(msg.GetPacket<Packets.PlayerInfoUpdate>());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.VehicleSync:
|
case PacketType.VehicleSync:
|
||||||
ReceivedPackets.VehicelPacket.Deserialize(data);
|
ReceivedPackets.VehicelPacket.Deserialize(msg);
|
||||||
VehicleSync(ReceivedPackets.VehicelPacket);
|
VehicleSync(ReceivedPackets.VehicelPacket);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.PedSync:
|
case PacketType.PedSync:
|
||||||
ReceivedPackets.PedPacket.Deserialize(data);
|
ReceivedPackets.PedPacket.Deserialize(msg);
|
||||||
PedSync(ReceivedPackets.PedPacket);
|
PedSync(ReceivedPackets.PedPacket);
|
||||||
break;
|
break;
|
||||||
case PacketType.ProjectileSync:
|
case PacketType.ProjectileSync:
|
||||||
ReceivedPackets.ProjectilePacket.Deserialize(data);
|
ReceivedPackets.ProjectilePacket.Deserialize(msg);
|
||||||
ProjectileSync(ReceivedPackets.ProjectilePacket);
|
ProjectileSync(ReceivedPackets.ProjectilePacket);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -257,9 +236,9 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
|
|
||||||
Packets.ChatMessage packet = new Packets.ChatMessage((b) => Security.Decrypt(b));
|
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; });
|
API.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message); return true; });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -268,7 +247,7 @@ namespace RageCoop.Client
|
|||||||
if (Main.Settings.Voice)
|
if (Main.Settings.Voice)
|
||||||
{
|
{
|
||||||
Packets.Voice packet = new Packets.Voice();
|
Packets.Voice packet = new Packets.Voice();
|
||||||
packet.Deserialize(data);
|
packet.Deserialize(msg);
|
||||||
|
|
||||||
|
|
||||||
SyncedPed player = EntityPool.GetPedByID(packet.ID);
|
SyncedPed player = EntityPool.GetPedByID(packet.ID);
|
||||||
@ -282,27 +261,29 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
case PacketType.CustomEvent:
|
case PacketType.CustomEvent:
|
||||||
{
|
{
|
||||||
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
Packets.CustomEvent packet = new Packets.CustomEvent();
|
||||||
packet.Deserialize(data);
|
if (((CustomEventFlags)msg.PeekByte()).HasEventFlag(CustomEventFlags.Queued))
|
||||||
|
{
|
||||||
|
recycle = false;
|
||||||
|
API.QueueAction(() =>
|
||||||
|
{
|
||||||
|
packet.Deserialize(msg);
|
||||||
|
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
||||||
|
Peer.Recycle(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
packet.Deserialize(msg);
|
||||||
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case PacketType.CustomEventQueued:
|
|
||||||
{
|
|
||||||
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
|
||||||
Main.QueueAction(() =>
|
|
||||||
{
|
|
||||||
packet.Deserialize(data);
|
|
||||||
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PacketType.FileTransferChunk:
|
case PacketType.FileTransferChunk:
|
||||||
{
|
{
|
||||||
Packets.FileTransferChunk packet = new Packets.FileTransferChunk();
|
Packets.FileTransferChunk packet = new Packets.FileTransferChunk();
|
||||||
packet.Deserialize(data);
|
packet.Deserialize(msg);
|
||||||
DownloadManager.Write(packet.ID, packet.FileChunk);
|
DownloadManager.Write(packet.ID, packet.FileChunk);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -310,8 +291,9 @@ namespace RageCoop.Client
|
|||||||
default:
|
default:
|
||||||
if (packetType.IsSyncEvent())
|
if (packetType.IsSyncEvent())
|
||||||
{
|
{
|
||||||
|
recycle = false;
|
||||||
// Dispatch to script thread
|
// Dispatch to script thread
|
||||||
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, data); return true; });
|
API.QueueAction(() => { SyncEvents.HandleEvent(packetType, msg); Peer.Recycle(msg); return true; });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -335,6 +317,7 @@ namespace RageCoop.Client
|
|||||||
c.Flags = packet.Flags;
|
c.Flags = packet.Flags;
|
||||||
c.Heading = packet.Heading;
|
c.Heading = packet.Heading;
|
||||||
c.Position = packet.Position;
|
c.Position = packet.Position;
|
||||||
|
c.LastSyncedStopWatch.Restart();
|
||||||
if (c.IsRagdoll)
|
if (c.IsRagdoll)
|
||||||
{
|
{
|
||||||
c.HeadPosition = packet.HeadPosition;
|
c.HeadPosition = packet.HeadPosition;
|
||||||
@ -420,6 +403,7 @@ namespace RageCoop.Client
|
|||||||
p.Shooter = packet.Flags.HasProjDataFlag(ProjectileDataFlags.IsShotByVehicle) ?
|
p.Shooter = packet.Flags.HasProjDataFlag(ProjectileDataFlags.IsShotByVehicle) ?
|
||||||
(SyncedEntity)EntityPool.GetVehicleByID(packet.ShooterID) : EntityPool.GetPedByID(packet.ShooterID);
|
(SyncedEntity)EntityPool.GetVehicleByID(packet.ShooterID) : EntityPool.GetPedByID(packet.ShooterID);
|
||||||
p.LastSynced = Main.Ticked;
|
p.LastSynced = Main.Ticked;
|
||||||
|
p.LastSyncedStopWatch.Restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@
|
|||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
|
using RageCoop.Client.Scripting;
|
||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -13,7 +14,7 @@ namespace RageCoop.Client
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reduce GC pressure by reusing frequently used packets
|
/// Reduce GC pressure by reusing frequently used packets
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static class SendPackets
|
private static class SendPackets
|
||||||
{
|
{
|
||||||
public static Packets.PedSync PedPacket = new Packets.PedSync();
|
public static Packets.PedSync PedPacket = new Packets.PedSync();
|
||||||
public static Packets.VehicleSync VehicelPacket = new Packets.VehicleSync();
|
public static Packets.VehicleSync VehicelPacket = new Packets.VehicleSync();
|
||||||
@ -90,9 +91,9 @@ namespace RageCoop.Client
|
|||||||
Blip b;
|
Blip b;
|
||||||
if (sp.IsPlayer)
|
if (sp.IsPlayer)
|
||||||
{
|
{
|
||||||
p.BlipColor=Scripting.API.Config.BlipColor;
|
p.BlipColor = API.Config.BlipColor;
|
||||||
p.BlipSprite=Scripting.API.Config.BlipSprite;
|
p.BlipSprite = API.Config.BlipSprite;
|
||||||
p.BlipScale=Scripting.API.Config.BlipScale;
|
p.BlipScale = API.Config.BlipScale;
|
||||||
}
|
}
|
||||||
else if ((b = ped.AttachedBlip) != null)
|
else if ((b = ped.AttachedBlip) != null)
|
||||||
{
|
{
|
@ -1,11 +1,12 @@
|
|||||||
using GTA;
|
using GTA;
|
||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using RageCoop.Client.Scripting;
|
||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Lidgren.Network;
|
|
||||||
using System.Net;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
@ -54,7 +55,7 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
foreach (var player in Players.Values)
|
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");
|
_mainScaleform.CallFunction("SET_TITLE", "Player list", $"{Players.Count} players");
|
||||||
@ -63,16 +64,15 @@ namespace RageCoop.Client
|
|||||||
public static void SetPlayer(int id, string username, float latency = 0)
|
public static void SetPlayer(int id, string username, float latency = 0)
|
||||||
{
|
{
|
||||||
Main.Logger.Debug($"{id},{username},{latency}");
|
Main.Logger.Debug($"{id},{username},{latency}");
|
||||||
Player p;
|
if (Players.TryGetValue(id, out Player p))
|
||||||
if (Players.TryGetValue(id, out p))
|
|
||||||
{
|
{
|
||||||
p.Username = username;
|
p.Username = username;
|
||||||
p.PedID=id;
|
p.ID = id;
|
||||||
p._latencyToServer = latency;
|
p._latencyToServer = latency;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p = new Player { PedID=id, Username=username, _latencyToServer=latency };
|
p = new Player { ID = id, Username = username, _latencyToServer = latency };
|
||||||
Players.Add(id, p);
|
Players.Add(id, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,24 +83,24 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
p._latencyToServer = packet.Latency;
|
p._latencyToServer = packet.Latency;
|
||||||
p.Position = packet.Position;
|
p.Position = packet.Position;
|
||||||
|
p.IsHost = packet.IsHost;
|
||||||
Main.QueueAction(() =>
|
API.QueueAction(() =>
|
||||||
{
|
{
|
||||||
if (p.FakeBlip?.Exists() != true)
|
if (p.FakeBlip?.Exists() != true)
|
||||||
{
|
{
|
||||||
p.FakeBlip = World.CreateBlip(p.Position);
|
p.FakeBlip = World.CreateBlip(p.Position);
|
||||||
}
|
}
|
||||||
if (p.Position.DistanceTo(Main.PlayerPosition)>500)
|
if (EntityPool.PedExists(p.ID))
|
||||||
{
|
{
|
||||||
p.FakeBlip.Color=Scripting.API.Config.BlipColor;
|
p.FakeBlip.DisplayType = BlipDisplayType.NoDisplay;
|
||||||
p.FakeBlip.Scale=Scripting.API.Config.BlipScale;
|
|
||||||
p.FakeBlip.Sprite=Scripting.API.Config.BlipSprite;
|
|
||||||
p.FakeBlip.DisplayType=BlipDisplayType.Default;
|
|
||||||
p.FakeBlip.Position=p.Position;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p.FakeBlip.DisplayType=BlipDisplayType.NoDisplay;
|
p.FakeBlip.Color = API.Config.BlipColor;
|
||||||
|
p.FakeBlip.Scale = API.Config.BlipScale;
|
||||||
|
p.FakeBlip.Sprite = API.Config.BlipSprite;
|
||||||
|
p.FakeBlip.DisplayType = BlipDisplayType.Default;
|
||||||
|
p.FakeBlip.Position = p.Position;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -108,8 +108,7 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
public static Player GetPlayer(int id)
|
public static Player GetPlayer(int id)
|
||||||
{
|
{
|
||||||
Player p;
|
Players.TryGetValue(id, out Player p);
|
||||||
Players.TryGetValue(id, out p);
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
public static Player GetPlayer(SyncedPed p)
|
public static Player GetPlayer(SyncedPed p)
|
||||||
@ -126,7 +125,7 @@ namespace RageCoop.Client
|
|||||||
if (Players.TryGetValue(id, out var player))
|
if (Players.TryGetValue(id, out var player))
|
||||||
{
|
{
|
||||||
Players.Remove(id);
|
Players.Remove(id);
|
||||||
Main.QueueAction(() => player.FakeBlip?.Delete());
|
API.QueueAction(() => player.FakeBlip?.Delete());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void Cleanup()
|
public static void Cleanup()
|
||||||
@ -139,31 +138,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; }
|
public string Username { get; internal set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Universal character ID.
|
/// Universal ped ID.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int PedID
|
public int ID
|
||||||
{
|
{
|
||||||
get; internal set;
|
get; internal set;
|
||||||
}
|
}
|
||||||
public IPEndPoint InternalEndPoint { get; set; }
|
public IPEndPoint InternalEndPoint { get; internal set; }
|
||||||
public IPEndPoint ExternalEndPoint { get; set; }
|
public IPEndPoint ExternalEndPoint { get; internal set; }
|
||||||
public bool ConnectWhenPunched { get; set; }
|
internal bool ConnectWhenPunched { get; set; }
|
||||||
public Blip FakeBlip { get; set; }
|
public Blip FakeBlip { get; internal set; }
|
||||||
public Vector3 Position { get; set; }
|
public Vector3 Position { get; internal set; }
|
||||||
public SyncedPed Character { get; set; }
|
public SyncedPed Character { get; internal set; }
|
||||||
/// <summary>
|
/// <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>
|
/// </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 PacketTravelTime => HasDirectConnection ? Connection.AverageRoundtripTime / 2 : Networking.Latency + _latencyToServer;
|
||||||
public float _latencyToServer = 0;
|
internal float _latencyToServer = 0;
|
||||||
public bool DisplayNameTag { get; set; } = true;
|
public bool DisplayNameTag { get; set; } = true;
|
||||||
public NetConnection Connection { get; set; }
|
public NetConnection Connection { get; internal set; }
|
||||||
public bool HasDirectConnection => Connection?.Status == NetConnectionStatus.Connected;
|
public bool HasDirectConnection => Connection?.Status == NetConnectionStatus.Connected;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,7 +16,7 @@ using System.Resources;
|
|||||||
|
|
||||||
|
|
||||||
// Version informationr(
|
// Version informationr(
|
||||||
[assembly: AssemblyVersion("1.5.1.13")]
|
[assembly: AssemblyVersion("1.5.6.1")]
|
||||||
[assembly: AssemblyFileVersion("1.5.1.13")]
|
[assembly: AssemblyFileVersion("1.5.6.1")]
|
||||||
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
|
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
|
||||||
|
|
157
Client/Scripts/RageCoop.Client.csproj
Normal file
157
Client/Scripts/RageCoop.Client.csproj
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>RageCoop.Client</RootNamespace>
|
||||||
|
<AssemblyName>RageCoop.Client</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
<NuGetPackageImportStamp>
|
||||||
|
</NuGetPackageImportStamp>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
|
||||||
|
<OutPutPath>..\..\bin\Debug\Client</OutPutPath>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefineConstants>DEBUG</DefineConstants>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<NoWarn>1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||||
|
<OutPutPath>..\..\bin\Release\Client</OutPutPath>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Debug.cs" />
|
||||||
|
<Compile Include="DevTools\DevTool.cs" />
|
||||||
|
<Compile Include="Main.cs" />
|
||||||
|
<Compile Include="Menus\CoopMenu.cs" />
|
||||||
|
<Compile Include="Menus\Sub\DebugMenu.cs" />
|
||||||
|
<Compile Include="Menus\Sub\DevToolMenu.cs" />
|
||||||
|
<Compile Include="Menus\Sub\ServersMenu.cs" />
|
||||||
|
<Compile Include="Menus\Sub\SettingsMenu.cs" />
|
||||||
|
<Compile Include="Menus\Sub\UpdateMenu.cs" />
|
||||||
|
<Compile Include="Networking\Chat.cs" />
|
||||||
|
<Compile Include="Networking\DownloadManager.cs" />
|
||||||
|
<Compile Include="Networking\HolePunch.cs" />
|
||||||
|
<Compile Include="Networking\Networking.cs" />
|
||||||
|
<Compile Include="Networking\Receive.cs" />
|
||||||
|
<Compile Include="Networking\Send.cs" />
|
||||||
|
<Compile Include="Networking\Statistics.cs" />
|
||||||
|
<Compile Include="PlayerList.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>AssemblyInfo.tt</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Scripting\API.cs" />
|
||||||
|
<Compile Include="Scripting\BaseScript.cs" />
|
||||||
|
<Compile Include="Scripting\ClientScript.cs" />
|
||||||
|
<Compile Include="Scripting\Resources.cs" />
|
||||||
|
<Compile Include="Security.cs" />
|
||||||
|
<Compile Include="Settings.cs" />
|
||||||
|
<Compile Include="Sync\Entities\Ped\SyncedPed.Members.cs" />
|
||||||
|
<Compile Include="Sync\Entities\Ped\SyncedPed.Animations.cs" />
|
||||||
|
<Compile Include="Sync\Entities\SyncedEntity.cs" />
|
||||||
|
<Compile Include="Sync\Entities\Ped\SyncedPed.cs" />
|
||||||
|
<Compile Include="Sync\Entities\SyncedProjectile.cs" />
|
||||||
|
<Compile Include="Sync\Entities\SyncedProp.cs" />
|
||||||
|
<Compile Include="Sync\Entities\Vehicle\SyncedVehicle.cs" />
|
||||||
|
<Compile Include="Sync\Entities\Vehicle\SyncedVehicle.Members.cs" />
|
||||||
|
<Compile Include="Sync\EntityPool.cs" />
|
||||||
|
<Compile Include="Sync\SyncEvents.cs" />
|
||||||
|
<Compile Include="Sync\Voice.cs" />
|
||||||
|
<Compile Include="Util\AddOnDataProvider.cs" />
|
||||||
|
<Compile Include="Util\Memory.cs" />
|
||||||
|
<Compile Include="Util\NativeCaller.cs" />
|
||||||
|
<Compile Include="Util\PedConfigFlags.cs" />
|
||||||
|
<Compile Include="Util\PedExtensions.cs" />
|
||||||
|
<Compile Include="Util\TaskType.cs" />
|
||||||
|
<Compile Include="Util\Util.cs" />
|
||||||
|
<Compile Include="Util\VehicleExtensions.cs" />
|
||||||
|
<Compile Include="Util\WeaponUtil.cs" />
|
||||||
|
<Compile Include="WorldThread.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="ICSharpCode.SharpZipLib, Version=1.4.0.12, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\SharpZipLib.1.4.0\lib\netstandard2.0\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="LemonUI.SHVDN3">
|
||||||
|
<HintPath>..\..\libs\LemonUI.SHVDN3.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Lidgren.Network">
|
||||||
|
<HintPath>..\..\libs\Lidgren.Network.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="Microsoft.Extensions.ObjectPool, Version=6.0.8.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.Extensions.ObjectPool.6.0.8\lib\net461\Microsoft.Extensions.ObjectPool.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="NAudio, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\NAudio.2.1.0\lib\net472\NAudio.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="NAudio.Asio, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\NAudio.Asio.2.1.0\lib\netstandard2.0\NAudio.Asio.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="NAudio.Core, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\NAudio.Core.2.1.0\lib\netstandard2.0\NAudio.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="NAudio.Midi, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\NAudio.Midi.2.1.0\lib\netstandard2.0\NAudio.Midi.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="NAudio.Wasapi, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\NAudio.Wasapi.2.1.0\lib\netstandard2.0\NAudio.Wasapi.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="NAudio.WinForms, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\NAudio.WinForms.2.1.0\lib\net472\NAudio.WinForms.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="NAudio.WinMM, Version=2.1.0.0, Culture=neutral, PublicKeyToken=e279aa5131008a41, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\NAudio.WinMM.2.1.0\lib\netstandard2.0\NAudio.WinMM.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="ScriptHookVDotNet">
|
||||||
|
<HintPath>..\..\libs\ScriptHookVDotNet.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="ScriptHookVDotNet3">
|
||||||
|
<HintPath>..\..\libs\ScriptHookVDotNet3.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="app.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Properties\AssemblyInfo.tt">
|
||||||
|
<Generator>TextTemplatingFileGenerator</Generator>
|
||||||
|
<LastGenOutput>AssemblyInfo.cs</LastGenOutput>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Core\RageCoop.Core.csproj">
|
||||||
|
<Project>{cc2e8102-e568-4524-aa1f-f8e0f1cfe58a}</Project>
|
||||||
|
<Name>RageCoop.Core</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\Loader\RageCoop.Client.Loader.csproj">
|
||||||
|
<Project>{fc8cbdbb-6dc3-43af-b34d-092e476410a5}</Project>
|
||||||
|
<Name>RageCoop.Client.Loader</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<PropertyGroup Condition=" '$(DevEnvDir)' != '*Undefined*'">
|
||||||
|
<PostBuildEvent>"$(DevEnvDir)TextTransform.exe" -a !!BuildConfiguration!$(Configuration) "$(ProjectDir)Properties\AssemblyInfo.tt"</PostBuildEvent>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
@ -1,8 +1,12 @@
|
|||||||
#undef DEBUG
|
#undef DEBUG
|
||||||
using GTA;
|
using GTA;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
|
using RageCoop.Core.Scripting;
|
||||||
|
using SHVDN;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace RageCoop.Client.Scripting
|
namespace RageCoop.Client.Scripting
|
||||||
@ -24,7 +28,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides vital functionality to interact with RAGECOOP
|
/// Provides vital functionality to interact with RAGECOOP
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class API
|
public static class API
|
||||||
{
|
{
|
||||||
#region INTERNAL
|
#region INTERNAL
|
||||||
internal static Dictionary<int, List<Action<CustomEventReceivedArgs>>> CustomEventHandlers = new Dictionary<int, List<Action<CustomEventReceivedArgs>>>();
|
internal static Dictionary<int, List<Action<CustomEventReceivedArgs>>> CustomEventHandlers = new Dictionary<int, List<Action<CustomEventReceivedArgs>>>();
|
||||||
@ -39,7 +43,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string Username
|
public static string Username
|
||||||
{
|
{
|
||||||
get { return Main.Settings.Username; }
|
get => Main.Settings.Username;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Networking.IsOnServer || string.IsNullOrEmpty(value))
|
if (Networking.IsOnServer || string.IsNullOrEmpty(value))
|
||||||
@ -115,16 +119,22 @@ namespace RageCoop.Client.Scripting
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is equivalent of <see cref="GTA.Script.Tick"/>.
|
/// This is equivalent of <see cref="GTA.Script.Tick"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>Calling <see cref="GTA.Script.Yield"/> in the handler will interfer other scripts, subscribe to <see cref="GTA.Script.Tick"/> instead.</remarks>
|
||||||
|
[Obsolete]
|
||||||
public static event EmptyEvent OnTick;
|
public static event EmptyEvent OnTick;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is equivalent of <see cref="Script.KeyDown"/>
|
/// This is equivalent of <see cref="Script.KeyDown"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>Calling <see cref="GTA.Script.Yield"/> in the handler will interfer other scripts, subscribe to <see cref="GTA.Script.KeyDown"/> instead.</remarks>
|
||||||
|
[Obsolete]
|
||||||
public static KeyEventHandler OnKeyDown;
|
public static KeyEventHandler OnKeyDown;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is equivalent of <see cref="Script.KeyUp"/>
|
/// This is equivalent of <see cref="Script.KeyUp"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>Calling <see cref="GTA.Script.Yield"/> in the handler will interfer other scripts, subscribe to <see cref="GTA.Script.KeyUp"/> instead.</remarks>
|
||||||
|
[Obsolete]
|
||||||
public static KeyEventHandler OnKeyUp;
|
public static KeyEventHandler OnKeyUp;
|
||||||
|
|
||||||
#region INVOKE
|
#region INVOKE
|
||||||
@ -145,8 +155,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
|
|
||||||
// Main.Logger.Debug($"CustomEvent:\n"+args.Args.DumpWithType());
|
// Main.Logger.Debug($"CustomEvent:\n"+args.Args.DumpWithType());
|
||||||
|
|
||||||
List<Action<CustomEventReceivedArgs>> handlers;
|
if (CustomEventHandlers.TryGetValue(p.Hash, out List<Action<CustomEventReceivedArgs>> handlers))
|
||||||
if (CustomEventHandlers.TryGetValue(p.Hash, out handlers))
|
|
||||||
{
|
{
|
||||||
handlers.ForEach((x) => { x.Invoke(args); });
|
handlers.ForEach((x) => { x.Invoke(args); });
|
||||||
}
|
}
|
||||||
@ -160,65 +169,48 @@ namespace RageCoop.Client.Scripting
|
|||||||
/// Get the local player's ID
|
/// Get the local player's ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>PlayerID</returns>
|
/// <returns>PlayerID</returns>
|
||||||
public static int LocalPlayerID
|
public static int LocalPlayerID => Main.LocalPlayerID;
|
||||||
{
|
|
||||||
get { return Main.LocalPlayerID; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if player is connected to a server
|
/// Check if player is connected to a server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool IsOnServer { get { return Networking.IsOnServer; } }
|
public static bool IsOnServer => Networking.IsOnServer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get an <see cref="System.Net.IPEndPoint"/> that the player is currently connected to, or null if not connected to the server
|
/// Get an <see cref="System.Net.IPEndPoint"/> that the player is currently connected to, or null if not connected to the server
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// Check if a RAGECOOP menu is visible
|
/// Check if a RAGECOOP menu is visible
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool IsMenuVisible
|
public static bool IsMenuVisible => Menus.CoopMenu.MenuPool.AreAnyVisible;
|
||||||
{
|
|
||||||
get { return Menus.CoopMenu.MenuPool.AreAnyVisible; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if the RAGECOOP chat is visible
|
/// Check if the RAGECOOP chat is visible
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool IsChatFocused
|
public static bool IsChatFocused => Main.MainChat.Focused;
|
||||||
{
|
|
||||||
get { return Main.MainChat.Focused; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if the RAGECOOP list of players is visible
|
/// Check if the RAGECOOP list of players is visible
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool IsPlayerListVisible
|
public static bool IsPlayerListVisible => Util.GetTickCount64() - PlayerList.Pressed < 5000;
|
||||||
{
|
|
||||||
get { return Util.GetTickCount64() - PlayerList.Pressed < 5000; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the version of RAGECOOP
|
/// Get the version of RAGECOOP
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Version CurrentVersion
|
public static Version CurrentVersion => Main.Version;
|
||||||
{
|
|
||||||
get { return Main.Version; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a <see cref="Core.Logger"/> that RAGECOOP is currently using.
|
/// Get a <see cref="Core.Logger"/> that RAGECOOP is currently using.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static Logger Logger
|
public static Logger Logger => Main.Logger;
|
||||||
{
|
/// <summary>
|
||||||
get
|
/// Get all players indexed by their ID
|
||||||
{
|
/// </summary>
|
||||||
return Main.Logger;
|
public static Dictionary<int, Player> Players => new Dictionary<int, Player>(PlayerList.Players);
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region FUNCTIONS
|
#region FUNCTIONS
|
||||||
@ -245,6 +237,16 @@ namespace RageCoop.Client.Scripting
|
|||||||
Networking.ToggleConnection(null);
|
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>
|
/// <summary>
|
||||||
/// Send a local chat message to this player
|
/// Send a local chat message to this player
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -256,21 +258,12 @@ namespace RageCoop.Client.Scripting
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queue an action to be executed on next tick.
|
/// Send a chat message or command to server/other players
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="a"></param>
|
/// <param name="message"></param>
|
||||||
public static void QueueAction(Action a)
|
public static void SendChatMessage(string message)
|
||||||
{
|
{
|
||||||
Main.QueueAction(a);
|
Networking.SendChatMessage(message);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="a"> An <see cref="Func{T, TResult}"/> to be executed with a return value indicating whether it can be removed after execution.</param>
|
|
||||||
public static void QueueAction(Func<bool> a)
|
|
||||||
{
|
|
||||||
Main.QueueAction(a);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -278,7 +271,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="eventHash">An unique identifier of the event</param>
|
/// <param name="eventHash">An unique identifier of the event</param>
|
||||||
/// <param name="args">The objects conataing your data, see <see cref="CustomEventReceivedArgs"/> for a list of supported types</param>
|
/// <param name="args">The objects conataing your data, see <see cref="CustomEventReceivedArgs"/> for a list of supported types</param>
|
||||||
public static void SendCustomEvent(int eventHash, params object[] args)
|
public static void SendCustomEvent(CustomEventHash eventHash, params object[] args)
|
||||||
{
|
{
|
||||||
|
|
||||||
Networking.Peer.SendTo(new Packets.CustomEvent()
|
Networking.Peer.SendTo(new Packets.CustomEvent()
|
||||||
@ -287,13 +280,27 @@ namespace RageCoop.Client.Scripting
|
|||||||
Hash = eventHash
|
Hash = eventHash
|
||||||
}, Networking.ServerConnection, ConnectionChannel.Event, Lidgren.Network.NetDeliveryMethod.ReliableOrdered);
|
}, Networking.ServerConnection, ConnectionChannel.Event, Lidgren.Network.NetDeliveryMethod.ReliableOrdered);
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Send an event and data to the server
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="flags"></param>
|
||||||
|
/// <param name="eventHash">An unique identifier of the event</param>
|
||||||
|
/// <param name="args">The objects conataing your data, see <see cref="CustomEventReceivedArgs"/> for a list of supported types</param>
|
||||||
|
public static void SendCustomEvent(CustomEventFlags flags, CustomEventHash eventHash, params object[] args)
|
||||||
|
{
|
||||||
|
Networking.Peer.SendTo(new Packets.CustomEvent(flags)
|
||||||
|
{
|
||||||
|
Args = args,
|
||||||
|
Hash = eventHash
|
||||||
|
}, Networking.ServerConnection, ConnectionChannel.Event, Lidgren.Network.NetDeliveryMethod.ReliableOrdered);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register an handler to the specifed event hash, one event can have multiple handlers. This will be invoked from backgound thread, use <see cref="QueueAction(Action)"/> in the handler to dispatch code to script thread.
|
/// Register an handler to the specifed event hash, one event can have multiple handlers. This will be invoked from backgound thread, use <see cref="QueueAction(Action)"/> in the handler to dispatch code to script thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hash">An unique identifier of the event, you can hash your event name with <see cref="Core.Scripting.CustomEvents.Hash(string)"/></param>
|
/// <param name="hash">An unique identifier of the event, you can hash your event name with <see cref="Core.Scripting.CustomEvents.Hash(string)"/></param>
|
||||||
/// <param name="handler">An handler to be invoked when the event is received from the server. </param>
|
/// <param name="handler">An handler to be invoked when the event is received from the server. </param>
|
||||||
public static void RegisterCustomEventHandler(int hash, Action<CustomEventReceivedArgs> handler)
|
public static void RegisterCustomEventHandler(CustomEventHash hash, Action<CustomEventReceivedArgs> handler)
|
||||||
{
|
{
|
||||||
lock (CustomEventHandlers)
|
lock (CustomEventHandlers)
|
||||||
{
|
{
|
||||||
@ -333,5 +340,41 @@ namespace RageCoop.Client.Scripting
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue an action to be executed on next tick.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a"></param>
|
||||||
|
public static void QueueAction(Action a)
|
||||||
|
{
|
||||||
|
WorldThread.QueueAction(a);
|
||||||
|
}
|
||||||
|
public static void QueueActionAndWait(Action a, int timeout = 15000)
|
||||||
|
{
|
||||||
|
var done = new AutoResetEvent(false);
|
||||||
|
Exception e = null;
|
||||||
|
QueueAction(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
a();
|
||||||
|
done.Set();
|
||||||
|
}
|
||||||
|
catch (Exception ex) { e = ex; }
|
||||||
|
});
|
||||||
|
if (e != null) { throw e; }
|
||||||
|
else if (!done.WaitOne(timeout)) { throw new TimeoutException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a"> An <see cref="Func{T, TResult}"/> to be executed with a return value indicating whether it can be removed after execution.</param>
|
||||||
|
public static void QueueAction(Func<bool> a)
|
||||||
|
{
|
||||||
|
WorldThread.QueueAction(a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,10 +9,10 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace RageCoop.Client.Scripting
|
namespace RageCoop.Client.Scripting
|
||||||
{
|
{
|
||||||
internal class BaseScript : ClientScript
|
internal static class BaseScript
|
||||||
{
|
{
|
||||||
private bool _isHost = false;
|
private static bool _isHost = false;
|
||||||
public override void OnStart()
|
public static void OnStart()
|
||||||
{
|
{
|
||||||
API.Events.OnPedDeleted += (s, p) => { API.SendCustomEvent(CustomEvents.OnPedDeleted, p.ID); };
|
API.Events.OnPedDeleted += (s, p) => { API.SendCustomEvent(CustomEvents.OnPedDeleted, p.ID); };
|
||||||
API.Events.OnVehicleDeleted += (s, p) => { API.SendCustomEvent(CustomEvents.OnVehicleDeleted, p.ID); };
|
API.Events.OnVehicleDeleted += (s, p) => { API.SendCustomEvent(CustomEvents.OnVehicleDeleted, p.ID); };
|
||||||
@ -57,19 +57,19 @@ namespace RageCoop.Client.Scripting
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WeatherTimeSync(CustomEventReceivedArgs e)
|
private static void WeatherTimeSync(CustomEventReceivedArgs e)
|
||||||
{
|
{
|
||||||
World.CurrentTimeOfDay = new TimeSpan((int)e.Args[0], (int)e.Args[1], (int)e.Args[2]);
|
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_WEATHER_TYPE_TRANSITION, (int)e.Args[3], (int)e.Args[4], (float)e.Args[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetDisplayNameTag(CustomEventReceivedArgs e)
|
private static void SetDisplayNameTag(CustomEventReceivedArgs e)
|
||||||
{
|
{
|
||||||
var p = PlayerList.GetPlayer((int)e.Args[0]);
|
var p = PlayerList.GetPlayer((int)e.Args[0]);
|
||||||
if (p != null) { p.DisplayNameTag = (bool)e.Args[1]; }
|
if (p != null) { p.DisplayNameTag = (bool)e.Args[1]; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdatePedBlip(CustomEventReceivedArgs e)
|
private static void UpdatePedBlip(CustomEventReceivedArgs e)
|
||||||
{
|
{
|
||||||
var p = Entity.FromHandle((int)e.Args[0]);
|
var p = Entity.FromHandle((int)e.Args[0]);
|
||||||
if (p == null) { return; }
|
if (p == null) { return; }
|
||||||
@ -89,14 +89,13 @@ namespace RageCoop.Client.Scripting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateVehicle(CustomEventReceivedArgs e)
|
private static void CreateVehicle(CustomEventReceivedArgs e)
|
||||||
{
|
{
|
||||||
var vehicleModel = (Model)e.Args[1];
|
var vehicleModel = (Model)e.Args[1];
|
||||||
vehicleModel.Request(1000);
|
vehicleModel.Request(1000);
|
||||||
Vehicle veh = World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3]);
|
Vehicle veh;
|
||||||
while (veh==null)
|
while ((veh = World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3])) == null)
|
||||||
{
|
{
|
||||||
veh = World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3]);
|
|
||||||
Thread.Sleep(10);
|
Thread.Sleep(10);
|
||||||
}
|
}
|
||||||
veh.CanPretendOccupants = false;
|
veh.CanPretendOccupants = false;
|
||||||
@ -109,7 +108,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
EntityPool.Add(v);
|
EntityPool.Add(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteServerBlip(CustomEventReceivedArgs e)
|
private static void DeleteServerBlip(CustomEventReceivedArgs e)
|
||||||
{
|
{
|
||||||
if (EntityPool.ServerBlips.TryGetValue((int)e.Args[0], out var blip))
|
if (EntityPool.ServerBlips.TryGetValue((int)e.Args[0], out var blip))
|
||||||
{
|
{
|
||||||
@ -118,7 +117,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ServerBlipSync(CustomEventReceivedArgs obj)
|
private static void ServerBlipSync(CustomEventReceivedArgs obj)
|
||||||
{
|
{
|
||||||
int id = (int)obj.Args[0];
|
int id = (int)obj.Args[0];
|
||||||
var sprite = (BlipSprite)(ushort)obj.Args[1];
|
var sprite = (BlipSprite)(ushort)obj.Args[1];
|
||||||
@ -127,8 +126,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
var pos = (Vector3)obj.Args[4];
|
var pos = (Vector3)obj.Args[4];
|
||||||
int rot = (int)obj.Args[5];
|
int rot = (int)obj.Args[5];
|
||||||
var name = (string)obj.Args[6];
|
var name = (string)obj.Args[6];
|
||||||
Blip blip;
|
if (!EntityPool.ServerBlips.TryGetValue(id, out Blip blip))
|
||||||
if (!EntityPool.ServerBlips.TryGetValue(id, out blip))
|
|
||||||
{
|
{
|
||||||
EntityPool.ServerBlips.Add(id, blip = World.CreateBlip(pos));
|
EntityPool.ServerBlips.Add(id, blip = World.CreateBlip(pos));
|
||||||
}
|
}
|
||||||
@ -141,15 +139,12 @@ namespace RageCoop.Client.Scripting
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void DeleteEntity(CustomEventReceivedArgs e)
|
private static void DeleteEntity(CustomEventReceivedArgs e)
|
||||||
{
|
{
|
||||||
Entity.FromHandle((int)e.Args[0])?.Delete();
|
Entity.FromHandle((int)e.Args[0])?.Delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnStop()
|
private static void SetNameTag(CustomEventReceivedArgs e)
|
||||||
{
|
|
||||||
}
|
|
||||||
private void SetNameTag(CustomEventReceivedArgs e)
|
|
||||||
{
|
{
|
||||||
var p = PlayerList.GetPlayer((int)e.Args[0]);
|
var p = PlayerList.GetPlayer((int)e.Args[0]);
|
||||||
if (p != null)
|
if (p != null)
|
||||||
@ -157,11 +152,11 @@ namespace RageCoop.Client.Scripting
|
|||||||
p.DisplayNameTag = (bool)e.Args[1];
|
p.DisplayNameTag = (bool)e.Args[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void SetAutoRespawn(CustomEventReceivedArgs args)
|
private static void SetAutoRespawn(CustomEventReceivedArgs args)
|
||||||
{
|
{
|
||||||
API.Config.EnableAutoRespawn = (bool)args.Args[0];
|
API.Config.EnableAutoRespawn = (bool)args.Args[0];
|
||||||
}
|
}
|
||||||
private void DeleteServerProp(CustomEventReceivedArgs e)
|
private static void DeleteServerProp(CustomEventReceivedArgs e)
|
||||||
{
|
{
|
||||||
var id = (int)e.Args[0];
|
var id = (int)e.Args[0];
|
||||||
if (EntityPool.ServerProps.TryGetValue(id, out var prop))
|
if (EntityPool.ServerProps.TryGetValue(id, out var prop))
|
||||||
@ -171,7 +166,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
private void ServerObjectSync(CustomEventReceivedArgs e)
|
private static void ServerObjectSync(CustomEventReceivedArgs e)
|
||||||
{
|
{
|
||||||
SyncedProp prop;
|
SyncedProp prop;
|
||||||
var id = (int)e.Args[0];
|
var id = (int)e.Args[0];
|
||||||
@ -186,9 +181,10 @@ namespace RageCoop.Client.Scripting
|
|||||||
prop.Model = (Model)e.Args[1];
|
prop.Model = (Model)e.Args[1];
|
||||||
prop.Position = (Vector3)e.Args[2];
|
prop.Position = (Vector3)e.Args[2];
|
||||||
prop.Rotation = (Vector3)e.Args[3];
|
prop.Rotation = (Vector3)e.Args[3];
|
||||||
|
prop.Model.Request(1000);
|
||||||
prop.Update();
|
prop.Update();
|
||||||
}
|
}
|
||||||
private void NativeCall(CustomEventReceivedArgs e)
|
private static void NativeCall(CustomEventReceivedArgs e)
|
||||||
{
|
{
|
||||||
List<InputArgument> arguments = new List<InputArgument>();
|
List<InputArgument> arguments = new List<InputArgument>();
|
||||||
int i;
|
int i;
|
||||||
@ -272,7 +268,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
private InputArgument GetInputArgument(object obj)
|
private static InputArgument GetInputArgument(object obj)
|
||||||
{
|
{
|
||||||
// Implicit conversion
|
// Implicit conversion
|
||||||
switch (obj)
|
switch (obj)
|
@ -5,15 +5,16 @@ namespace RageCoop.Client.Scripting
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inherit from this class, constructor will be called automatically, but other scripts might have yet been loaded, you should use <see cref="OnStart"/>. to initiate your script.
|
/// Inherit from this class, constructor will be called automatically, but other scripts might have yet been loaded, you should use <see cref="OnStart"/>. to initiate your script.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class ClientScript
|
public abstract class ClientScript : GTA.Script
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This method would be called from background thread, call <see cref="API.QueueAction(System.Action)"/> to dispatch it to main thread.
|
/// This method would be called from main thread, right after all script constructors are invoked.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void OnStart();
|
public abstract void OnStart();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This method would be called from background thread when the client disconnected from the server, you MUST terminate all background jobs/threads in this method.
|
/// This method would be called from main thread right before the whole <see cref="System.AppDomain"/> is unloded but prior to <see cref="GTA.Script.Aborted"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void OnStop();
|
public abstract void OnStop();
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Eqivalent of <see cref="ClientResource.Logger"/> in <see cref="CurrentResource"/>
|
/// Eqivalent of <see cref="ClientResource.Logger"/> in <see cref="CurrentResource"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Core.Logger Logger { get { return CurrentResource.Logger; } }
|
public Core.Logger Logger => CurrentResource.Logger;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
190
Client/Scripts/Scripting/Resources.cs
Normal file
190
Client/Scripts/Scripting/Resources.cs
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
using ICSharpCode.SharpZipLib.Zip;
|
||||||
|
using RageCoop.Core;
|
||||||
|
using RageCoop.Core.Scripting;
|
||||||
|
using SHVDN;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace RageCoop.Client.Scripting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class ClientResource
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the resource
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Directory where the scripts is loaded from
|
||||||
|
/// </summary>
|
||||||
|
public string ScriptsDirectory { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// A resource-specific folder that can be used to store your files.
|
||||||
|
/// </summary>
|
||||||
|
public string DataFolder { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Get all <see cref="ClientScript"/> instance in this resource.
|
||||||
|
/// </summary>
|
||||||
|
public List<ClientScript> Scripts { get; internal set; } = new List<ClientScript>();
|
||||||
|
/// <summary>
|
||||||
|
/// Get the <see cref="ResourceFile"/> where this script is loaded from.
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, ResourceFile> Files { get; internal set; } = new Dictionary<string, ResourceFile>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="Core.Logger"/> instance that can be used to debug your resource.
|
||||||
|
/// </summary>
|
||||||
|
public Logger Logger { get; internal set; }
|
||||||
|
}
|
||||||
|
internal class Resources
|
||||||
|
{
|
||||||
|
internal readonly ConcurrentDictionary<string, ClientResource> LoadedResources = new ConcurrentDictionary<string, ClientResource>();
|
||||||
|
private Logger Logger { get; set; }
|
||||||
|
public Resources()
|
||||||
|
{
|
||||||
|
Logger = Main.Logger;
|
||||||
|
}
|
||||||
|
public void Load(string path, string[] zips)
|
||||||
|
{
|
||||||
|
LoadedResources.Clear();
|
||||||
|
foreach (var zip in zips)
|
||||||
|
{
|
||||||
|
var zipPath = Path.Combine(path, zip);
|
||||||
|
Logger?.Info($"Loading resource: {Path.GetFileNameWithoutExtension(zip)}");
|
||||||
|
Unpack(zipPath, Path.Combine(path, "Data"));
|
||||||
|
}
|
||||||
|
Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories).Where(x => x.CanBeIgnored()).ForEach(x => File.Delete(x));
|
||||||
|
|
||||||
|
// Load it in main thread
|
||||||
|
API.QueueActionAndWait(() =>
|
||||||
|
{
|
||||||
|
Main.QueueToMainThreadAndWait(() =>
|
||||||
|
{
|
||||||
|
Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories).ForEach(x => ScriptDomain.CurrentDomain.StartScripts(x));
|
||||||
|
SetupScripts();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public void Unload()
|
||||||
|
{
|
||||||
|
|
||||||
|
StopScripts();
|
||||||
|
LoadedResources.Clear();
|
||||||
|
Loader.LoaderContext.RequestUnload();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Unpack(string zipPath, string dataFolderRoot)
|
||||||
|
{
|
||||||
|
var r = new ClientResource()
|
||||||
|
{
|
||||||
|
Logger = API.Logger,
|
||||||
|
Scripts = new List<ClientScript>(),
|
||||||
|
Name = Path.GetFileNameWithoutExtension(zipPath),
|
||||||
|
DataFolder = Path.Combine(dataFolderRoot, Path.GetFileNameWithoutExtension(zipPath)),
|
||||||
|
ScriptsDirectory = Path.Combine(Directory.GetParent(zipPath).FullName, Path.GetFileNameWithoutExtension(zipPath))
|
||||||
|
};
|
||||||
|
Directory.CreateDirectory(r.DataFolder);
|
||||||
|
var scriptsDir = r.ScriptsDirectory;
|
||||||
|
if (Directory.Exists(scriptsDir)) { Directory.Delete(scriptsDir, true); }
|
||||||
|
else if (File.Exists(scriptsDir)) { File.Delete(scriptsDir); }
|
||||||
|
Directory.CreateDirectory(scriptsDir);
|
||||||
|
|
||||||
|
new FastZip().ExtractZip(zipPath, scriptsDir, null);
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var dir in Directory.GetDirectories(scriptsDir, "*", SearchOption.AllDirectories))
|
||||||
|
{
|
||||||
|
r.Files.Add(dir, new ResourceFile()
|
||||||
|
{
|
||||||
|
IsDirectory = true,
|
||||||
|
Name = dir.Substring(scriptsDir.Length + 1).Replace('\\', '/')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var assemblies = new Dictionary<ResourceFile, Assembly>();
|
||||||
|
foreach (var file in Directory.GetFiles(scriptsDir, "*", SearchOption.AllDirectories))
|
||||||
|
{
|
||||||
|
if (Path.GetFileName(file).CanBeIgnored())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
API.Logger.Warning($"Failed to delete API assembly: {file}. This may or may cause some unexpected behaviours.\n{ex}");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var relativeName = file.Substring(scriptsDir.Length + 1).Replace('\\', '/');
|
||||||
|
var rfile = new ResourceFile()
|
||||||
|
{
|
||||||
|
GetStream = () => { return new FileStream(file, FileMode.Open, FileAccess.Read); },
|
||||||
|
IsDirectory = false,
|
||||||
|
Name = relativeName
|
||||||
|
};
|
||||||
|
r.Files.Add(relativeName, rfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadedResources.TryAdd(r.Name, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupScripts()
|
||||||
|
{
|
||||||
|
foreach (var s in GetClientScripts())
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
API.Logger.Debug("Starting script: " + s.GetType().FullName);
|
||||||
|
var script = (ClientScript)s;
|
||||||
|
if (LoadedResources.TryGetValue(Directory.GetParent(script.Filename).Name, out var r))
|
||||||
|
{
|
||||||
|
script.CurrentResource = r;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
API.Logger.Warning("Failed to locate resource for script: " + script.Filename);
|
||||||
|
}
|
||||||
|
var res = script.CurrentResource;
|
||||||
|
script.CurrentFile = res?.Files.Values.Where(x => x.Name.ToLower() == script.Filename.Substring(res.ScriptsDirectory.Length + 1).Replace('\\', '/')).FirstOrDefault();
|
||||||
|
res?.Scripts.Add(script);
|
||||||
|
script.OnStart();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
API.Logger.Error($"Failed to start {s.GetType().FullName}", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
API.Logger.Debug("Started script: " + s.GetType().FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopScripts()
|
||||||
|
{
|
||||||
|
foreach (var s in GetClientScripts())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
API.Logger.Debug("Stopping script: " + s.GetType().FullName);
|
||||||
|
((ClientScript)s).OnStop();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
API.Logger.Error($"Failed to stop {s.GetType().FullName}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static object[] GetClientScripts()
|
||||||
|
{
|
||||||
|
return ScriptDomain.CurrentDomain.RunningScripts.Where(x =>
|
||||||
|
x.ScriptInstance.GetType().IsScript(typeof(ClientScript))).Select(x => x.ScriptInstance).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,7 +7,7 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
public RSA ServerRSA { get; set; }
|
public RSA ServerRSA { get; set; }
|
||||||
public Aes ClientAes { get; set; } = Aes.Create();
|
public Aes ClientAes { get; set; } = Aes.Create();
|
||||||
private Logger Logger;
|
private readonly Logger Logger;
|
||||||
public Security(Logger logger)
|
public Security(Logger logger)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
@ -36,7 +36,7 @@ namespace RageCoop.Client
|
|||||||
/// LogLevel for RageCoop.
|
/// LogLevel for RageCoop.
|
||||||
/// 0:Trace, 1:Debug, 2:Info, 3:Warning, 4:Error
|
/// 0:Trace, 1:Debug, 2:Info, 3:Warning, 4:Error
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int LogLevel = 2;
|
public int LogLevel = 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The key to open menu
|
/// The key to open menu
|
||||||
@ -70,6 +70,11 @@ namespace RageCoop.Client
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The directory where log and resources downloaded from server will be placed.
|
/// The directory where log and resources downloaded from server will be placed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string DataDirectory { get; set; } = "Scripts\\RageCoop\\Data";
|
public string DataDirectory { get; set; } = "RageCoop\\Data";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show the owner name of the entity you're aiming at
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowEntityOwnerName { get; set; } = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -40,8 +40,10 @@ namespace RageCoop.Client
|
|||||||
var flag = AnimationFlags.Loop;
|
var flag = AnimationFlags.Loop;
|
||||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed, animDict, ourAnim, 3))
|
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed, animDict, ourAnim, 3))
|
||||||
{
|
{
|
||||||
|
if (LoadAnim(animDict) == null) { return; }
|
||||||
|
|
||||||
MainPed.Task.ClearAll();
|
MainPed.Task.ClearAll();
|
||||||
Function.Call(Hash.TASK_PLAY_ANIM, MainPed, LoadAnim(animDict), ourAnim, 8f, 10f, -1, flag, -8f, 1, 1, 1);
|
Function.Call(Hash.TASK_PLAY_ANIM, MainPed, animDict, ourAnim, 8f, 10f, -1, flag, -8f, 1, 1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,10 +118,10 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
case unchecked((uint)-1357824103):
|
case unchecked((uint)-1357824103):
|
||||||
case unchecked((uint)-1074790547):
|
case unchecked((uint)-1074790547):
|
||||||
case unchecked((uint)2132975508):
|
case unchecked(2132975508):
|
||||||
case unchecked((uint)-2084633992):
|
case unchecked((uint)-2084633992):
|
||||||
case unchecked((uint)-952879014):
|
case unchecked((uint)-952879014):
|
||||||
case unchecked((uint)100416529):
|
case unchecked(100416529):
|
||||||
case unchecked((uint)WeaponHash.Gusenberg):
|
case unchecked((uint)WeaponHash.Gusenberg):
|
||||||
case unchecked((uint)WeaponHash.MG):
|
case unchecked((uint)WeaponHash.MG):
|
||||||
case unchecked((uint)WeaponHash.CombatMG):
|
case unchecked((uint)WeaponHash.CombatMG):
|
||||||
@ -143,18 +145,11 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
private string LoadAnim(string anim)
|
private string LoadAnim(string anim)
|
||||||
{
|
{
|
||||||
ulong startTime = Util.GetTickCount64();
|
if (!Function.Call<bool>(Hash.HAS_ANIM_DICT_LOADED, anim))
|
||||||
|
|
||||||
while (!Function.Call<bool>(Hash.HAS_ANIM_DICT_LOADED, anim))
|
|
||||||
{
|
{
|
||||||
Script.Yield();
|
|
||||||
Function.Call(Hash.REQUEST_ANIM_DICT, anim);
|
Function.Call(Hash.REQUEST_ANIM_DICT, anim);
|
||||||
if (Util.GetTickCount64() - startTime >= 1000)
|
return null;
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return anim;
|
return anim;
|
||||||
}
|
}
|
||||||
}
|
}
|
81
Client/Scripts/Sync/Entities/Ped/SyncedPed.Members.cs
Normal file
81
Client/Scripts/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>
|
/// </summary>
|
||||||
public partial class SyncedPed : SyncedEntity
|
public partial class SyncedPed : SyncedEntity
|
||||||
{
|
{
|
||||||
#region CONSTRUCTORS
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a local entity (outgoing sync)
|
/// Create a local entity (outgoing sync)
|
||||||
@ -43,79 +42,10 @@ namespace RageCoop.Client
|
|||||||
ID = id;
|
ID = id;
|
||||||
LastSynced = Main.Ticked;
|
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()
|
internal override void Update()
|
||||||
{
|
{
|
||||||
if (Owner==null) { return; }
|
if (Owner == null) { OwnerID = OwnerID; return; }
|
||||||
if (IsPlayer)
|
if (IsPlayer)
|
||||||
{
|
{
|
||||||
RenderNameTag();
|
RenderNameTag();
|
||||||
@ -155,11 +85,7 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
PedBlip = MainPed.AddBlip();
|
PedBlip = MainPed.AddBlip();
|
||||||
|
|
||||||
if (IsPlayer)
|
|
||||||
{
|
|
||||||
// Main.Logger.Debug("blip:"+Player.Username);
|
|
||||||
Main.QueueAction(() => { PedBlip.Name=Owner.Username; });
|
|
||||||
}
|
|
||||||
PedBlip.Color = BlipColor;
|
PedBlip.Color = BlipColor;
|
||||||
PedBlip.Sprite = BlipSprite;
|
PedBlip.Sprite = BlipSprite;
|
||||||
PedBlip.Scale = BlipScale;
|
PedBlip.Scale = BlipScale;
|
||||||
@ -174,12 +100,18 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
PedBlip.Sprite = BlipSprite;
|
PedBlip.Sprite = BlipSprite;
|
||||||
}
|
}
|
||||||
|
if (IsPlayer)
|
||||||
|
{
|
||||||
|
PedBlip.Name = Owner.Username;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Clothes.SequenceEqual(_lastClothes))
|
if (!Clothes.SequenceEqual(_lastClothes))
|
||||||
{
|
{
|
||||||
SetClothes();
|
SetClothes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheckCurrentWeapon();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MainPed.IsDead)
|
if (MainPed.IsDead)
|
||||||
@ -207,13 +139,14 @@ namespace RageCoop.Client
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Speed >= 4)
|
if (Speed >= 4)
|
||||||
{
|
{
|
||||||
DisplayInVehicle();
|
DisplayInVehicle();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (MainPed.IsInVehicle()) { MainPed.Task.LeaveVehicle(LeaveVehicleFlags.WarpOut); }
|
if (MainPed.IsInVehicle()) { MainPed.Task.LeaveVehicle(LeaveVehicleFlags.WarpOut); return; }
|
||||||
DisplayOnFoot();
|
DisplayOnFoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,13 +273,9 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#region ONFOOT
|
|
||||||
private string[] _currentAnimation = new string[2] { "", "" };
|
|
||||||
|
|
||||||
private void DisplayOnFoot()
|
private void DisplayOnFoot()
|
||||||
{
|
{
|
||||||
|
|
||||||
CheckCurrentWeapon();
|
|
||||||
if (IsInParachuteFreeFall)
|
if (IsInParachuteFreeFall)
|
||||||
{
|
{
|
||||||
MainPed.PositionNoOffset = Vector3.Lerp(MainPed.ReadPosition(), Position + Velocity, 0.5f);
|
MainPed.PositionNoOffset = Vector3.Lerp(MainPed.ReadPosition(), Position + Velocity, 0.5f);
|
||||||
@ -354,7 +283,10 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "skydive@base", "free_idle", 3))
|
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "skydive@base", "free_idle", 3))
|
||||||
{
|
{
|
||||||
Function.Call(Hash.TASK_PLAY_ANIM, MainPed.Handle, LoadAnim("skydive@base"), "free_idle", 8f, 10f, -1, 0, -8f, 1, 1, 1);
|
// Skip update if animation is not loaded
|
||||||
|
var dict = LoadAnim("skydive@base");
|
||||||
|
if (dict == null) { return; }
|
||||||
|
Function.Call(Hash.TASK_PLAY_ANIM, MainPed.Handle, dict, "free_idle", 8f, 10f, -1, 0, -8f, 1, 1, 1);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -383,7 +315,9 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "skydive@parachute@first_person", "chute_idle_right", 3))
|
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "skydive@parachute@first_person", "chute_idle_right", 3))
|
||||||
{
|
{
|
||||||
Function.Call(Hash.TASK_PLAY_ANIM, MainPed, LoadAnim("skydive@parachute@first_person"), "chute_idle_right", 8f, 10f, -1, 0, -8f, 1, 1, 1);
|
var dict = LoadAnim("skydive@parachute@first_person");
|
||||||
|
if (dict == null) { return; }
|
||||||
|
Function.Call(Hash.TASK_PLAY_ANIM, MainPed, dict, "chute_idle_right", 8f, 10f, -1, 0, -8f, 1, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -504,8 +438,6 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (MainPed.IsRagdoll)
|
if (MainPed.IsRagdoll)
|
||||||
{
|
{
|
||||||
if (Speed == 0)
|
if (Speed == 0)
|
||||||
@ -516,10 +448,8 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
MainPed.Task.ClearAllImmediately();
|
MainPed.Task.ClearAllImmediately();
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_lastRagdoll = false;
|
_lastRagdoll = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsReloading)
|
if (IsReloading)
|
||||||
@ -579,17 +509,15 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region WEAPON
|
|
||||||
private void CheckCurrentWeapon()
|
private void CheckCurrentWeapon()
|
||||||
{
|
{
|
||||||
if (!WeaponAsset.IsLoaded) { WeaponAsset.Request(); }
|
if (MainPed.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || !WeaponComponents.Compare(_lastWeaponComponents) || (Speed <= 3 && _weaponObj?.IsVisible != true))
|
||||||
if (MainPed.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || !WeaponComponents.Compare(_lastWeaponComponents))
|
|
||||||
{
|
{
|
||||||
if (WeaponAsset!=null) { WeaponAsset.MarkAsNoLongerNeeded(); }
|
new WeaponAsset(CurrentWeaponHash).Request();
|
||||||
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);
|
|
||||||
|
|
||||||
|
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 (CurrentWeaponHash != (uint)WeaponHash.Unarmed)
|
||||||
{
|
{
|
||||||
if (WeaponComponents != null && WeaponComponents.Count != 0)
|
if (WeaponComponents != null && WeaponComponents.Count != 0)
|
||||||
@ -598,11 +526,11 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
if (comp.Value)
|
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;
|
_lastWeaponComponents = WeaponComponents;
|
||||||
}
|
}
|
||||||
@ -627,14 +555,12 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
SmoothTransition();
|
SmoothTransition();
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
|
||||||
private bool LastMoving;
|
|
||||||
private void WalkTo()
|
private void WalkTo()
|
||||||
{
|
{
|
||||||
MainPed.Task.ClearAll();
|
MainPed.Task.ClearAll();
|
||||||
Function.Call(Hash.SET_PED_STEALTH_MOVEMENT, MainPed, IsInStealthMode, 0);
|
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());
|
float range = predictPosition.DistanceToSquared(MainPed.ReadPosition());
|
||||||
|
|
||||||
switch (Speed)
|
switch (Speed)
|
||||||
@ -684,19 +610,25 @@ namespace RageCoop.Client
|
|||||||
private void SmoothTransition()
|
private void SmoothTransition()
|
||||||
{
|
{
|
||||||
var localRagdoll = MainPed.IsRagdoll;
|
var localRagdoll = MainPed.IsRagdoll;
|
||||||
var dist = Position.DistanceTo(MainPed.ReadPosition());
|
var predicted = Predict(Position);
|
||||||
if (dist>3)
|
var dist = predicted.DistanceTo(MainPed.ReadPosition());
|
||||||
|
if (IsOff(dist))
|
||||||
{
|
{
|
||||||
MainPed.PositionNoOffset=Position;
|
MainPed.PositionNoOffset = predicted;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(localRagdoll || MainPed.IsDead))
|
if (!(localRagdoll || MainPed.IsDead))
|
||||||
{
|
{
|
||||||
if (!IsAiming && !MainPed.IsGettingUp)
|
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)
|
else if (Main.Ticked - _lastRagdollTime < 10)
|
||||||
{
|
{
|
||||||
@ -708,44 +640,49 @@ namespace RageCoop.Client
|
|||||||
var head = MainPed.Bones[Bone.SkelHead];
|
var head = MainPed.Bones[Bone.SkelHead];
|
||||||
var rightFoot = MainPed.Bones[Bone.SkelRightFoot];
|
var rightFoot = MainPed.Bones[Bone.SkelRightFoot];
|
||||||
var leftFoot = MainPed.Bones[Bone.SkelLeftFoot];
|
var leftFoot = MainPed.Bones[Bone.SkelLeftFoot];
|
||||||
|
Vector3 amount;
|
||||||
// 20:head, 3:left foot, 6:right foot, 17:right hand,
|
// 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.EqualizeAmount = 1;
|
||||||
helper.PartIndex = 20;
|
helper.PartIndex = 20;
|
||||||
helper.Impulse=20*(HeadPosition-head.Position);
|
helper.Impulse = amount;
|
||||||
helper.Start();
|
helper.Start();
|
||||||
helper.Stop();
|
helper.Stop();
|
||||||
|
|
||||||
|
amount = 20 * (Predict(RightFootPosition) - rightFoot.Position);
|
||||||
|
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
|
||||||
helper.EqualizeAmount = 1;
|
helper.EqualizeAmount = 1;
|
||||||
helper.PartIndex = 6;
|
helper.PartIndex = 6;
|
||||||
helper.Impulse=20*(RightFootPosition-rightFoot.Position);
|
helper.Impulse = amount;
|
||||||
helper.Start();
|
helper.Start();
|
||||||
helper.Stop();
|
helper.Stop();
|
||||||
|
|
||||||
|
amount = 20 * (Predict(LeftFootPosition) - leftFoot.Position);
|
||||||
|
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
|
||||||
helper.EqualizeAmount = 1;
|
helper.EqualizeAmount = 1;
|
||||||
helper.PartIndex = 3;
|
helper.PartIndex = 3;
|
||||||
helper.Impulse=20*(LeftFootPosition-leftFoot.Position);
|
helper.Impulse = amount;
|
||||||
helper.Start();
|
helper.Start();
|
||||||
helper.Stop();
|
helper.Stop();
|
||||||
}
|
}
|
||||||
else
|
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()
|
private void DisplayInVehicle()
|
||||||
{
|
{
|
||||||
if (CurrentVehicle==null || CurrentVehicle.MainVehicle==null) { Main.Logger.Error("Veh not found"); return; }
|
if (CurrentVehicle?.MainVehicle == null) { return; }
|
||||||
switch (Speed)
|
switch (Speed)
|
||||||
{
|
{
|
||||||
case 4:
|
case 4:
|
||||||
if (MainPed.CurrentVehicle!=CurrentVehicle.MainVehicle)
|
if (MainPed.CurrentVehicle != CurrentVehicle.MainVehicle || MainPed.SeatIndex != Seat || (!MainPed.IsSittingInVehicle() && !MainPed.IsBeingJacked))
|
||||||
{
|
{
|
||||||
MainPed.SetIntoVehicle(CurrentVehicle.MainVehicle, Seat);
|
MainPed.SetIntoVehicle(CurrentVehicle.MainVehicle, Seat);
|
||||||
}
|
}
|
||||||
@ -757,7 +694,6 @@ namespace RageCoop.Client
|
|||||||
if (MainPed.VehicleWeapon == VehicleWeaponHash.Invalid)
|
if (MainPed.VehicleWeapon == VehicleWeaponHash.Invalid)
|
||||||
{
|
{
|
||||||
// World.DrawMarker(MarkerType.DebugSphere,AimCoords,default,default,new Vector3(0.2f,0.2f,0.2f),Color.AliceBlue);
|
// World.DrawMarker(MarkerType.DebugSphere,AimCoords,default,default,new Vector3(0.2f,0.2f,0.2f),Color.AliceBlue);
|
||||||
CheckCurrentWeapon();
|
|
||||||
if (IsAiming)
|
if (IsAiming)
|
||||||
{
|
{
|
||||||
Function.Call(Hash.SET_DRIVEBY_TASK_TARGET, MainPed, 0, 0, AimCoords.X, AimCoords.Y, AimCoords.Z);
|
Function.Call(Hash.SET_DRIVEBY_TASK_TARGET, MainPed, 0, 0, AimCoords.X, AimCoords.Y, AimCoords.Z);
|
@ -36,6 +36,10 @@ namespace RageCoop.Client
|
|||||||
if (value == _ownerID && Owner != null) { return; }
|
if (value == _ownerID && Owner != null) { return; }
|
||||||
_ownerID = value;
|
_ownerID = value;
|
||||||
Owner = PlayerList.GetPlayer(value);
|
Owner = PlayerList.GetPlayer(value);
|
||||||
|
if (this is SyncedPed && Owner != null)
|
||||||
|
{
|
||||||
|
Owner.Character = ((SyncedPed)this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,16 +84,33 @@ namespace RageCoop.Client
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal protected bool _lastFrozen = false;
|
protected internal bool _lastFrozen = false;
|
||||||
internal Model Model { get; set; }
|
internal Model Model { get; set; }
|
||||||
internal Vector3 Position { get; set; }
|
internal Vector3 Position { get; set; }
|
||||||
internal Vector3 Rotation { get; set; }
|
internal Vector3 Rotation { get; set; }
|
||||||
internal Quaternion Quaternion { get; set; }
|
internal Quaternion Quaternion { get; set; }
|
||||||
internal Vector3 Velocity { get; set; }
|
internal Vector3 Velocity { get; set; }
|
||||||
|
public Stopwatch LastSyncedStopWatch = new Stopwatch();
|
||||||
internal abstract void Update();
|
internal abstract void Update();
|
||||||
internal void PauseUpdate(ulong frames)
|
internal void PauseUpdate(ulong frames)
|
||||||
{
|
{
|
||||||
LastUpdated = Main.Ticked + frames;
|
LastUpdated = Main.Ticked + frames;
|
||||||
}
|
}
|
||||||
|
protected Vector3 Predict(Vector3 input)
|
||||||
|
{
|
||||||
|
return (Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds) * Velocity + input;
|
||||||
|
}
|
||||||
|
private float _accumulatedOff = 0;
|
||||||
|
protected bool IsOff(float thisOff, float tolerance = 3, float limit = 30)
|
||||||
|
{
|
||||||
|
_accumulatedOff += thisOff - tolerance;
|
||||||
|
if (_accumulatedOff < 0) { _accumulatedOff = 0; }
|
||||||
|
else if (_accumulatedOff >= limit)
|
||||||
|
{
|
||||||
|
_accumulatedOff = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
using GTA;
|
using GTA;
|
||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using RageCoop.Core;
|
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
|
using RageCoop.Core;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
@ -19,12 +19,11 @@ namespace RageCoop.Client
|
|||||||
public SyncedEntity Shooter { get; set; }
|
public SyncedEntity Shooter { get; set; }
|
||||||
public bool Exploded => Flags.HasProjDataFlag(ProjectileDataFlags.Exploded);
|
public bool Exploded => Flags.HasProjDataFlag(ProjectileDataFlags.Exploded);
|
||||||
|
|
||||||
|
internal override Player Owner => Shooter.Owner;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalid property for projectile.
|
/// Invalid property for projectile.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private new int OwnerID { set { } }
|
private new int OwnerID { set { } }
|
||||||
|
|
||||||
internal override Player Owner => Shooter.Owner;
|
|
||||||
public WeaponHash WeaponHash { get; set; }
|
public WeaponHash WeaponHash { get; set; }
|
||||||
private WeaponAsset Asset { get; set; }
|
private WeaponAsset Asset { get; set; }
|
||||||
public void ExtractData(ref Packets.ProjectileSync p)
|
public void ExtractData(ref Packets.ProjectileSync p)
|
||||||
@ -101,7 +100,7 @@ namespace RageCoop.Client
|
|||||||
CreateProjectile();
|
CreateProjectile();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MainProjectile.Velocity=Velocity+(Position+Shooter.Owner.PacketTravelTime*Velocity-MainProjectile.Position);
|
MainProjectile.Velocity = Velocity + 10 * (Predict(Position) - MainProjectile.Position);
|
||||||
MainProjectile.Rotation = Rotation;
|
MainProjectile.Rotation = Rotation;
|
||||||
LastUpdated = Main.Ticked;
|
LastUpdated = Main.Ticked;
|
||||||
}
|
}
|
||||||
@ -113,15 +112,14 @@ namespace RageCoop.Client
|
|||||||
if (Shooter == null) { return; }
|
if (Shooter == null) { return; }
|
||||||
Entity owner;
|
Entity owner;
|
||||||
owner = (Shooter as SyncedPed)?.MainPed ?? (Entity)(Shooter as SyncedVehicle)?.MainVehicle;
|
owner = (Shooter as SyncedPed)?.MainPed ?? (Entity)(Shooter as SyncedVehicle)?.MainVehicle;
|
||||||
|
Position = (Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds) * Shooter.Velocity + Position;
|
||||||
var end = Position + Velocity;
|
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();
|
var ps = World.GetAllProjectiles();
|
||||||
MainProjectile = ps[ps.Length - 1];
|
MainProjectile = ps[ps.Length - 1];
|
||||||
MainProjectile.IsCollisionEnabled=false;
|
|
||||||
MainProjectile.Position = Position;
|
MainProjectile.Position = Position;
|
||||||
MainProjectile.Rotation = Rotation;
|
MainProjectile.Rotation = Rotation;
|
||||||
MainProjectile.Velocity = Velocity;
|
MainProjectile.Velocity = Velocity;
|
||||||
Main.Delay(()=>MainProjectile.IsCollisionEnabled=true, 100);
|
|
||||||
EntityPool.Add(this);
|
EntityPool.Add(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,6 +27,7 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
|
|
||||||
if (!NeedUpdate) { return; }
|
if (!NeedUpdate) { return; }
|
||||||
|
if (!Model.IsLoaded) { Model.Request(); return; }
|
||||||
if (MainProp == null || !MainProp.Exists())
|
if (MainProp == null || !MainProp.Exists())
|
||||||
{
|
{
|
||||||
MainProp = World.CreateProp(Model, Position, Rotation, false, false);
|
MainProp = World.CreateProp(Model, Position, Rotation, false, false);
|
@ -1,15 +1,13 @@
|
|||||||
using System;
|
|
||||||
using RageCoop.Core;
|
|
||||||
using GTA;
|
using GTA;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using GTA.Native;
|
using RageCoop.Core;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace RageCoop.Client{
|
namespace RageCoop.Client
|
||||||
public partial class SyncedVehicle{
|
{
|
||||||
|
public partial class SyncedVehicle
|
||||||
|
{
|
||||||
public Vehicle MainVehicle { get; internal set; }
|
public Vehicle MainVehicle { get; internal set; }
|
||||||
public Stopwatch LastSyncedStopWatch = new Stopwatch();
|
|
||||||
|
|
||||||
|
|
||||||
#region -- SYNC DATA --
|
#region -- SYNC DATA --
|
||||||
@ -69,11 +67,9 @@ namespace RageCoop.Client{
|
|||||||
private bool _lastHornActive = false;
|
private bool _lastHornActive = false;
|
||||||
private bool _lastTransformed = false;
|
private bool _lastTransformed = false;
|
||||||
internal int _lastLivery = -1;
|
internal int _lastLivery = -1;
|
||||||
List<Vector3> _predictedTrace = new List<Vector3>();
|
private readonly List<Vector3> _predictedTrace = new List<Vector3>();
|
||||||
List<Vector3> _orgTrace = new List<Vector3>();
|
private readonly List<Vector3> _orgTrace = new List<Vector3>();
|
||||||
private Vector3 _predictedPosition;
|
private Vector3 _predictedPosition;
|
||||||
|
|
||||||
float _elapsed;
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region OUTGOING
|
#region OUTGOING
|
@ -4,8 +4,6 @@ using GTA.Native;
|
|||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Drawing;
|
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
@ -31,7 +29,9 @@ namespace RageCoop.Client
|
|||||||
SetUpFixedData();
|
SetUpFixedData();
|
||||||
|
|
||||||
}
|
}
|
||||||
private void SetUpFixedData(){
|
internal void SetUpFixedData()
|
||||||
|
{
|
||||||
|
if (MainVehicle == null) { return; }
|
||||||
|
|
||||||
IsAircraft = MainVehicle.IsAircraft;
|
IsAircraft = MainVehicle.IsAircraft;
|
||||||
IsMotorcycle = MainVehicle.IsMotorcycle;
|
IsMotorcycle = MainVehicle.IsMotorcycle;
|
||||||
@ -85,6 +85,8 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DisplayVehicle();
|
||||||
// Skip update if no new sync message has arrived.
|
// Skip update if no new sync message has arrived.
|
||||||
if (!NeedUpdate)
|
if (!NeedUpdate)
|
||||||
{
|
{
|
||||||
@ -97,8 +99,6 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
MainVehicle.ThrottlePower = ThrottlePower;
|
MainVehicle.ThrottlePower = ThrottlePower;
|
||||||
MainVehicle.BrakePower = BrakePower;
|
MainVehicle.BrakePower = BrakePower;
|
||||||
var v = Main.P.CurrentVehicle;
|
|
||||||
DisplayVehicle(v != null && MainVehicle.IsTouching(v));
|
|
||||||
|
|
||||||
if (IsDead)
|
if (IsDead)
|
||||||
{
|
{
|
||||||
@ -113,7 +113,7 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
if (MainVehicle.IsDead)
|
if (MainVehicle.IsDead)
|
||||||
{
|
{
|
||||||
Main.Delay(() =>
|
WorldThread.Delay(() =>
|
||||||
{
|
{
|
||||||
if (MainVehicle.IsDead && !IsDead)
|
if (MainVehicle.IsDead && !IsDead)
|
||||||
{
|
{
|
||||||
@ -149,8 +149,6 @@ namespace RageCoop.Client
|
|||||||
MainVehicle.AreHighBeamsOn = HighBeamsOn;
|
MainVehicle.AreHighBeamsOn = HighBeamsOn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (IsAircraft)
|
if (IsAircraft)
|
||||||
{
|
{
|
||||||
if (LandingGear != (byte)MainVehicle.LandingGearState)
|
if (LandingGear != (byte)MainVehicle.LandingGearState)
|
||||||
@ -184,10 +182,12 @@ namespace RageCoop.Client
|
|||||||
MainVehicle.RoofState = RoofState;
|
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));
|
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));
|
MainVehicle.SetParachuteActive(Flags.HasFlag(VehicleDataFlags.IsParachuteActive));
|
||||||
}
|
}
|
||||||
if (IsSubmarineCar)
|
if (IsSubmarineCar)
|
||||||
@ -206,22 +206,23 @@ namespace RageCoop.Client
|
|||||||
Function.Call(Hash._TRANSFORM_SUBMARINE_TO_VEHICLE, MainVehicle.Handle, false);
|
Function.Call(Hash._TRANSFORM_SUBMARINE_TO_VEHICLE, MainVehicle.Handle, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(IsDeluxo && IsDeluxoHovering!=MainVehicle.IsDeluxoHovering()){
|
else if (IsDeluxo)
|
||||||
|
{
|
||||||
MainVehicle.SetDeluxoHoverState(IsDeluxoHovering);
|
MainVehicle.SetDeluxoHoverState(IsDeluxoHovering);
|
||||||
if(IsDeluxoHovering){
|
if (IsDeluxoHovering)
|
||||||
|
{
|
||||||
MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
|
MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
|
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
|
||||||
MainVehicle.SetDamageModel(DamageModel);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
MainVehicle.LockStatus = LockStatus;
|
MainVehicle.LockStatus = LockStatus;
|
||||||
|
|
||||||
if (LastFullSynced >= LastUpdated)
|
if (LastFullSynced >= LastUpdated)
|
||||||
{
|
{
|
||||||
#region -- SYNC STATE --
|
|
||||||
if (Flags.HasVehFlag(VehicleDataFlags.Repaired))
|
if (Flags.HasVehFlag(VehicleDataFlags.Repaired))
|
||||||
{
|
{
|
||||||
MainVehicle.Repair();
|
MainVehicle.Repair();
|
||||||
@ -255,14 +256,14 @@ namespace RageCoop.Client
|
|||||||
Function.Call(Hash.SET_VEHICLE_LIVERY, MainVehicle, Livery);
|
Function.Call(Hash.SET_VEHICLE_LIVERY, MainVehicle, Livery);
|
||||||
_lastLivery = Livery;
|
_lastLivery = Livery;
|
||||||
}
|
}
|
||||||
#endregion
|
MainVehicle.SetDamageModel(DamageModel);
|
||||||
}
|
}
|
||||||
LastUpdated = Main.Ticked;
|
LastUpdated = Main.Ticked;
|
||||||
}
|
}
|
||||||
void DisplayVehicle(bool touching)
|
|
||||||
|
private void DisplayVehicle()
|
||||||
{
|
{
|
||||||
_elapsed = Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds;
|
_predictedPosition = Predict(Position);
|
||||||
_predictedPosition = Position + _elapsed * Velocity;
|
|
||||||
var current = MainVehicle.ReadPosition();
|
var current = MainVehicle.ReadPosition();
|
||||||
var dist = current.DistanceTo(_predictedPosition);
|
var dist = current.DistanceTo(_predictedPosition);
|
||||||
var cali = dist * (_predictedPosition - current);
|
var cali = dist * (_predictedPosition - current);
|
||||||
@ -274,41 +275,20 @@ namespace RageCoop.Client
|
|||||||
MainVehicle.Quaternion = Quaternion;
|
MainVehicle.Quaternion = Quaternion;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (dist > 0.03)
|
||||||
|
{
|
||||||
MainVehicle.Velocity = Velocity + cali;
|
MainVehicle.Velocity = Velocity + cali;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsFlipped)
|
Vector3 calirot;
|
||||||
|
if (IsFlipped || (calirot = GetCalibrationRotation()).Length() > 50)
|
||||||
{
|
{
|
||||||
MainVehicle.Quaternion = Quaternion.Slerp(MainVehicle.ReadQuaternion(), Quaternion, 0.5f);
|
MainVehicle.Quaternion = Quaternion.Slerp(MainVehicle.ReadQuaternion(), Quaternion, 0.5f);
|
||||||
MainVehicle.RotationVelocity = RotationVelocity;
|
MainVehicle.RotationVelocity = RotationVelocity;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 calirot = GetCalibrationRotation();
|
|
||||||
if (calirot.Length() < 50)
|
|
||||||
{
|
|
||||||
MainVehicle.RotationVelocity = RotationVelocity + calirot * 0.2f;
|
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()
|
private Vector3 GetCalibrationRotation()
|
||||||
{
|
{
|
||||||
var rot = Quaternion.LookRotation(Quaternion * Vector3.RelativeFront, Quaternion * Vector3.RelativeTop).ToEulerAngles();
|
var rot = Quaternion.LookRotation(Quaternion * Vector3.RelativeFront, Quaternion * Vector3.RelativeTop).ToEulerAngles();
|
||||||
@ -334,7 +314,7 @@ namespace RageCoop.Client
|
|||||||
// GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
|
// GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (MainVehicle==null)
|
if (MainVehicle == null)
|
||||||
{
|
{
|
||||||
Model.Request();
|
Model.Request();
|
||||||
return false;
|
return false;
|
||||||
@ -393,7 +373,5 @@ namespace RageCoop.Client
|
|||||||
MainVehicle.Driver.Task.ClearAnimation(PedalingAnimDict(), PedalingAnimName(fast));
|
MainVehicle.Driver.Task.ClearAnimation(PedalingAnimDict(), PedalingAnimName(fast));
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,17 @@
|
|||||||
using GTA;
|
using GTA;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
|
using Lidgren.Network;
|
||||||
using RageCoop.Client.Scripting;
|
using RageCoop.Client.Scripting;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using Lidgren.Network;
|
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
internal class EntityPool
|
internal class EntityPool
|
||||||
{
|
{
|
||||||
public static object PedsLock = new object();
|
public static object PedsLock = new object();
|
||||||
public static int CharactersCount { get { return PedsByID.Count; } }
|
|
||||||
#if BENCHMARK
|
#if BENCHMARK
|
||||||
private static Stopwatch PerfCounter=new Stopwatch();
|
private static Stopwatch PerfCounter=new Stopwatch();
|
||||||
private static Stopwatch PerfCounter2=Stopwatch.StartNew();
|
private static Stopwatch PerfCounter2=Stopwatch.StartNew();
|
||||||
@ -44,10 +43,10 @@ namespace RageCoop.Client
|
|||||||
#endregion
|
#endregion
|
||||||
public static void Cleanup(bool keepPlayer = true, bool keepMine = true)
|
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)
|
||||||
{
|
{
|
||||||
if (keepPlayer && (id==Main.LocalPlayerID)|| keepMine && (PedsByID[id].OwnerID == Main.LocalPlayerID)) { continue; }
|
if ((keepPlayer && (ped.ID == Main.LocalPlayerID)) || (keepMine && (ped.OwnerID == Main.LocalPlayerID))) { continue; }
|
||||||
RemovePed(id);
|
RemovePed(ped.ID);
|
||||||
}
|
}
|
||||||
PedsByID.Clear();
|
PedsByID.Clear();
|
||||||
PedsByHandle.Clear();
|
PedsByHandle.Clear();
|
||||||
@ -93,6 +92,8 @@ namespace RageCoop.Client
|
|||||||
public static bool AddPlayer()
|
public static bool AddPlayer()
|
||||||
{
|
{
|
||||||
Ped p = Game.Player.Character;
|
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);
|
SyncedPed player = GetPedByID(Main.LocalPlayerID);
|
||||||
if (player == null)
|
if (player == null)
|
||||||
{
|
{
|
||||||
@ -287,11 +288,11 @@ namespace RageCoop.Client
|
|||||||
public static bool VehicleExists(int id) => VehiclesByID.ContainsKey(id);
|
public static bool VehicleExists(int id) => VehiclesByID.ContainsKey(id);
|
||||||
public static bool ProjectileExists(int id) => ProjectilesByID.ContainsKey(id);
|
public static bool ProjectileExists(int id) => ProjectilesByID.ContainsKey(id);
|
||||||
#endregion
|
#endregion
|
||||||
static int vehStateIndex;
|
private static int vehStateIndex;
|
||||||
static int pedStateIndex;
|
private static int pedStateIndex;
|
||||||
static int vehStatesPerFrame;
|
private static int vehStatesPerFrame;
|
||||||
static int pedStatesPerFrame;
|
private static int pedStatesPerFrame;
|
||||||
static int i;
|
private static int i;
|
||||||
public static Ped[] allPeds = new Ped[0];
|
public static Ped[] allPeds = new Ped[0];
|
||||||
public static Vehicle[] allVehicles = new Vehicle[0];
|
public static Vehicle[] allVehicles = new Vehicle[0];
|
||||||
public static Projectile[] allProjectiles = new Projectile[0];
|
public static Projectile[] allProjectiles = new Projectile[0];
|
||||||
@ -308,17 +309,6 @@ namespace RageCoop.Client
|
|||||||
allProjectiles = World.GetAllProjectiles();
|
allProjectiles = World.GetAllProjectiles();
|
||||||
vehStatesPerFrame = allVehicles.Length * 2 / (int)Game.FPS + 1;
|
vehStatesPerFrame = allVehicles.Length * 2 / (int)Game.FPS + 1;
|
||||||
pedStatesPerFrame = allPeds.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
|
#if BENCHMARK
|
||||||
|
|
||||||
Debug.TimeStamps[TimeStamp.GetAllEntities]=PerfCounter.ElapsedTicks;
|
Debug.TimeStamps[TimeStamp.GetAllEntities]=PerfCounter.ElapsedTicks;
|
||||||
@ -343,7 +333,7 @@ namespace RageCoop.Client
|
|||||||
if (p.MainProjectile.AttachedEntity == null)
|
if (p.MainProjectile.AttachedEntity == null)
|
||||||
{
|
{
|
||||||
// Prevent projectiles from exploding next to vehicle
|
// 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;
|
continue;
|
||||||
}
|
}
|
||||||
@ -368,14 +358,14 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
lock (PedsLock)
|
lock (PedsLock)
|
||||||
{
|
{
|
||||||
EntityPool.AddPlayer();
|
AddPlayer();
|
||||||
|
|
||||||
foreach (Ped p in allPeds)
|
foreach (Ped p in allPeds)
|
||||||
{
|
{
|
||||||
SyncedPed c = EntityPool.GetPedByHandle(p.Handle);
|
SyncedPed c = GetPedByHandle(p.Handle);
|
||||||
if (c == null && (p != Game.Player.Character))
|
if (c == null && (p != Game.Player.Character))
|
||||||
{
|
{
|
||||||
if (allPeds.Length>Main.Settings.WorldPedSoftLimit && p.PopulationType != EntityPopulationType.RandomAmbient)
|
if (allPeds.Length > Main.Settings.WorldPedSoftLimit && p.PopulationType == EntityPopulationType.RandomAmbient)
|
||||||
{
|
{
|
||||||
p.Delete();
|
p.Delete();
|
||||||
continue;
|
continue;
|
||||||
@ -383,7 +373,7 @@ namespace RageCoop.Client
|
|||||||
// Main.Logger.Trace($"Creating SyncEntity for ped, handle:{p.Handle}");
|
// Main.Logger.Trace($"Creating SyncEntity for ped, handle:{p.Handle}");
|
||||||
c = new SyncedPed(p);
|
c = new SyncedPed(p);
|
||||||
|
|
||||||
EntityPool.Add(c);
|
Add(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if BENCHMARK
|
#if BENCHMARK
|
||||||
@ -402,7 +392,7 @@ namespace RageCoop.Client
|
|||||||
i++;
|
i++;
|
||||||
if ((c.MainPed != null) && (!c.MainPed.Exists()))
|
if ((c.MainPed != null) && (!c.MainPed.Exists()))
|
||||||
{
|
{
|
||||||
EntityPool.RemovePed(c.ID, "non-existent");
|
RemovePed(c.ID, "non-existent");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,9 +429,8 @@ namespace RageCoop.Client
|
|||||||
Debug.TimeStamps[TimeStamp.PedTotal]=PerfCounter.ElapsedTicks;
|
Debug.TimeStamps[TimeStamp.PedTotal]=PerfCounter.ElapsedTicks;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
var check = Main.Ticked % 100 == 0;
|
||||||
i = -1;
|
i = -1;
|
||||||
|
|
||||||
lock (VehiclesLock)
|
lock (VehiclesLock)
|
||||||
{
|
{
|
||||||
foreach (Vehicle veh in allVehicles)
|
foreach (Vehicle veh in allVehicles)
|
||||||
@ -456,10 +445,10 @@ namespace RageCoop.Client
|
|||||||
foreach (var p in veh.Occupants)
|
foreach (var p in veh.Occupants)
|
||||||
{
|
{
|
||||||
p.Delete();
|
p.Delete();
|
||||||
var c = EntityPool.GetPedByHandle(p.Handle);
|
var c = GetPedByHandle(p.Handle);
|
||||||
if (c != null)
|
if (c != null)
|
||||||
{
|
{
|
||||||
EntityPool.RemovePed(c.ID, "ThrottleTraffic");
|
RemovePed(c.ID, "ThrottleTraffic");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
veh.Delete();
|
veh.Delete();
|
||||||
@ -486,10 +475,13 @@ namespace RageCoop.Client
|
|||||||
i++;
|
i++;
|
||||||
if ((v.MainVehicle != null) && (!v.MainVehicle.Exists()))
|
if ((v.MainVehicle != null) && (!v.MainVehicle.Exists()))
|
||||||
{
|
{
|
||||||
EntityPool.RemoveVehicle(v.ID, "non-existent");
|
RemoveVehicle(v.ID, "non-existent");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (check)
|
||||||
|
{
|
||||||
|
v.SetUpFixedData();
|
||||||
|
}
|
||||||
// Outgoing sync
|
// Outgoing sync
|
||||||
if (v.IsLocal)
|
if (v.IsLocal)
|
||||||
{
|
{
|
||||||
@ -514,7 +506,8 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
Networking.Peer.FlushSendQueue();
|
Networking.Peer.FlushSendQueue();
|
||||||
}
|
}
|
||||||
static void UpdateTargets()
|
|
||||||
|
private static void UpdateTargets()
|
||||||
{
|
{
|
||||||
Networking.Targets = new List<NetConnection>(PlayerList.Players.Count) { Networking.ServerConnection };
|
Networking.Targets = new List<NetConnection>(PlayerList.Players.Count) { Networking.ServerConnection };
|
||||||
foreach (var p in PlayerList.Players.Values.ToArray())
|
foreach (var p in PlayerList.Players.Values.ToArray())
|
||||||
@ -579,21 +572,21 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
public static void Add(SyncedVehicle v)
|
public static void Add(SyncedVehicle v)
|
||||||
{
|
{
|
||||||
lock (EntityPool.VehiclesLock)
|
lock (VehiclesLock)
|
||||||
{
|
{
|
||||||
EntityPool.Add(v);
|
EntityPool.Add(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void Add(SyncedPed p)
|
public static void Add(SyncedPed p)
|
||||||
{
|
{
|
||||||
lock (EntityPool.PedsLock)
|
lock (PedsLock)
|
||||||
{
|
{
|
||||||
EntityPool.Add(p);
|
EntityPool.Add(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void Add(SyncedProjectile sp)
|
public static void Add(SyncedProjectile sp)
|
||||||
{
|
{
|
||||||
lock (EntityPool.ProjectilesLock)
|
lock (ProjectilesLock)
|
||||||
{
|
{
|
||||||
EntityPool.Add(sp);
|
EntityPool.Add(sp);
|
||||||
}
|
}
|
@ -1,15 +1,14 @@
|
|||||||
using GTA;
|
using GTA;
|
||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
|
using Lidgren.Network;
|
||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Lidgren.Network;
|
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
internal static class SyncEvents
|
internal static class SyncEvents
|
||||||
{
|
{
|
||||||
|
|
||||||
#region TRIGGER
|
#region TRIGGER
|
||||||
public static void TriggerPedKilled(SyncedPed victim)
|
public static void TriggerPedKilled(SyncedPed victim)
|
||||||
{
|
{
|
||||||
@ -73,9 +72,8 @@ namespace RageCoop.Client
|
|||||||
#region HANDLE
|
#region HANDLE
|
||||||
|
|
||||||
public static ParticleEffectAsset CorePFXAsset = new ParticleEffectAsset("core");
|
public static ParticleEffectAsset CorePFXAsset = new ParticleEffectAsset("core");
|
||||||
|
private static WeaponAsset _weaponAsset = default;
|
||||||
static WeaponAsset _weaponAsset = default;
|
private static uint _lastWeaponHash;
|
||||||
static uint _lastWeaponHash;
|
|
||||||
|
|
||||||
private static void HandlePedKilled(Packets.PedKilled p)
|
private static void HandlePedKilled(Packets.PedKilled p)
|
||||||
{
|
{
|
||||||
@ -162,44 +160,39 @@ namespace RageCoop.Client
|
|||||||
WeaponUtil.GetFlashFX((WeaponHash)p.WeaponHash),
|
WeaponUtil.GetFlashFX((WeaponHash)p.WeaponHash),
|
||||||
b.Position, b.ForwardVector.ToEulerRotation(v.Bones[35].UpVector), 1);
|
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)
|
switch (type)
|
||||||
{
|
{
|
||||||
case PacketType.BulletShot:
|
case PacketType.BulletShot:
|
||||||
{
|
{
|
||||||
Packets.BulletShot p = new Packets.BulletShot();
|
Packets.BulletShot p = new Packets.BulletShot();
|
||||||
p.Deserialize(data);
|
p.Deserialize(msg);
|
||||||
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
|
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PacketType.VehicleBulletShot:
|
case PacketType.VehicleBulletShot:
|
||||||
{
|
{
|
||||||
HandleVehicleBulletShot(data.GetPacket<Packets.VehicleBulletShot>());
|
HandleVehicleBulletShot(msg.GetPacket<Packets.VehicleBulletShot>());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PacketType.OwnerChanged:
|
case PacketType.OwnerChanged:
|
||||||
{
|
{
|
||||||
Packets.OwnerChanged packet = new Packets.OwnerChanged();
|
HandleOwnerChanged(msg.GetPacket<Packets.OwnerChanged>());
|
||||||
packet.Deserialize(data);
|
|
||||||
HandleOwnerChanged(packet);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PacketType.PedKilled:
|
case PacketType.PedKilled:
|
||||||
{
|
{
|
||||||
var packet = new Packets.PedKilled();
|
HandlePedKilled(msg.GetPacket<Packets.PedKilled>());
|
||||||
packet.Deserialize(data);
|
|
||||||
HandlePedKilled(packet);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PacketType.NozzleTransform:
|
case PacketType.NozzleTransform:
|
||||||
{
|
{
|
||||||
var packet = new Packets.NozzleTransform();
|
HandleNozzleTransform(msg.GetPacket<Packets.NozzleTransform>());
|
||||||
packet.Deserialize(data);
|
|
||||||
HandleNozzleTransform(packet);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Networking.Peer.Recycle(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -264,7 +257,7 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
if (!getBulletImpact())
|
if (!getBulletImpact())
|
||||||
{
|
{
|
||||||
Main.QueueAction(getBulletImpact);
|
Scripting.API.QueueAction(getBulletImpact);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (subject.VehicleWeapon == VehicleWeaponHash.Tank && subject.LastWeaponImpactPosition != default)
|
else if (subject.VehicleWeapon == VehicleWeaponHash.Tank && subject.LastWeaponImpactPosition != default)
|
@ -1,6 +1,5 @@
|
|||||||
using System.Threading;
|
using NAudio.Wave;
|
||||||
|
using System.Threading;
|
||||||
using NAudio.Wave;
|
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
59
Client/Scripts/Util/AddOnDataProvider.cs
Normal file
59
Client/Scripts/Util/AddOnDataProvider.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using GTA;
|
||||||
|
|
||||||
|
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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using GTA.Math;
|
|
||||||
using GTA;
|
|
||||||
using SHVDN;
|
|
||||||
using RageCoop.Core;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
internal unsafe class MemPatch{
|
internal unsafe class MemPatch
|
||||||
private byte[] _data;
|
{
|
||||||
private byte[] _orginal;
|
private readonly byte[] _data;
|
||||||
private IntPtr _address;
|
private readonly byte[] _orginal;
|
||||||
|
private readonly IntPtr _address;
|
||||||
public MemPatch(byte* address, byte[] data)
|
public MemPatch(byte* address, byte[] data)
|
||||||
{
|
{
|
||||||
_data = data;
|
_data = data;
|
||||||
@ -68,8 +69,8 @@ internal static unsafe class Memory
|
|||||||
public const int MatrixOffset = 96;
|
public const int MatrixOffset = 96;
|
||||||
#endregion
|
#endregion
|
||||||
#region OPCODE
|
#region OPCODE
|
||||||
const byte XOR_32_64 = 0x31;
|
private const byte XOR_32_64 = 0x31;
|
||||||
const byte RET = 0xC3;
|
private const byte RET = 0xC3;
|
||||||
#endregion
|
#endregion
|
||||||
public static Vector3 ReadPosition(this Entity e) => ReadVector3(e.MemoryAddress + PositionOffset);
|
public static Vector3 ReadPosition(this Entity e) => ReadVector3(e.MemoryAddress + PositionOffset);
|
||||||
public static Quaternion ReadQuaternion(this Entity e) => Quaternion.RotationMatrix(e.Matrix);
|
public static Quaternion ReadQuaternion(this Entity e) => Quaternion.RotationMatrix(e.Matrix);
|
145
Client/Scripts/Util/NativeCaller.cs
Normal file
145
Client/Scripts/Util/NativeCaller.cs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
using GTA.Math;
|
||||||
|
using GTA.Native;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace RageCoop.Client
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = 80)]
|
||||||
|
public struct HeadBlendData
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public int ShapeFirst;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public int ShapeSecond;
|
||||||
|
|
||||||
|
[FieldOffset(16)]
|
||||||
|
public int ShapeThird;
|
||||||
|
|
||||||
|
[FieldOffset(24)]
|
||||||
|
public int SkinFirst;
|
||||||
|
|
||||||
|
[FieldOffset(32)]
|
||||||
|
public int SkinSecond;
|
||||||
|
|
||||||
|
[FieldOffset(40)]
|
||||||
|
public int SkinThird;
|
||||||
|
|
||||||
|
[FieldOffset(48)]
|
||||||
|
public float ShapeMix;
|
||||||
|
|
||||||
|
[FieldOffset(56)]
|
||||||
|
public float SkinMix;
|
||||||
|
|
||||||
|
[FieldOffset(64)]
|
||||||
|
public float ThirdMix;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = 24)]
|
||||||
|
public struct NativeVector3
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public float X;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public float Y;
|
||||||
|
|
||||||
|
[FieldOffset(16)]
|
||||||
|
public float Z;
|
||||||
|
|
||||||
|
public static implicit operator Vector3(NativeVector3 vec)
|
||||||
|
{
|
||||||
|
return new Vector3() { X = vec.X, Y = vec.Y, Z = vec.Z };
|
||||||
|
}
|
||||||
|
public static implicit operator NativeVector3(Vector3 vec)
|
||||||
|
{
|
||||||
|
return new NativeVector3() { X = vec.X, Y = vec.Y, Z = vec.Z };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class NativeCaller
|
||||||
|
{
|
||||||
|
// These are borrowed from ScriptHookVDotNet's
|
||||||
|
[DllImport("ScriptHookV.dll", ExactSpelling = true, EntryPoint = "?nativeInit@@YAX_K@Z")]
|
||||||
|
private static extern void NativeInit(ulong hash);
|
||||||
|
|
||||||
|
[DllImport("ScriptHookV.dll", ExactSpelling = true, EntryPoint = "?nativePush64@@YAX_K@Z")]
|
||||||
|
private static extern void NativePush64(ulong val);
|
||||||
|
|
||||||
|
[DllImport("ScriptHookV.dll", ExactSpelling = true, EntryPoint = "?nativeCall@@YAPEA_KXZ")]
|
||||||
|
private static extern unsafe ulong* NativeCall();
|
||||||
|
|
||||||
|
// These are from ScriptHookV's nativeCaller.h
|
||||||
|
private static unsafe void NativePush<T>(T val) where T : unmanaged
|
||||||
|
{
|
||||||
|
ulong val64 = 0;
|
||||||
|
*(T*)(&val64) = val;
|
||||||
|
NativePush64(val64);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe R Invoke<R>(ulong hash) where R : unmanaged
|
||||||
|
{
|
||||||
|
NativeInit(hash);
|
||||||
|
return *(R*)(NativeCall());
|
||||||
|
}
|
||||||
|
public static unsafe R Invoke<R>(Hash hash, params object[] args)
|
||||||
|
where R : unmanaged
|
||||||
|
{
|
||||||
|
NativeInit((ulong)hash);
|
||||||
|
var arguments = ConvertPrimitiveArguments(args);
|
||||||
|
foreach (var arg in arguments)
|
||||||
|
NativePush(arg);
|
||||||
|
|
||||||
|
return *(R*)(NativeCall());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper function that converts an array of primitive values to a native stack.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static unsafe ulong[] ConvertPrimitiveArguments(object[] args)
|
||||||
|
{
|
||||||
|
var result = new ulong[args.Length];
|
||||||
|
for (int i = 0; i < args.Length; ++i)
|
||||||
|
{
|
||||||
|
if (args[i] is bool valueBool)
|
||||||
|
{
|
||||||
|
result[i] = valueBool ? 1ul : 0ul;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[i] is byte valueByte)
|
||||||
|
{
|
||||||
|
result[i] = valueByte;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[i] is int valueInt32)
|
||||||
|
{
|
||||||
|
result[i] = (ulong)valueInt32;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[i] is ulong valueUInt64)
|
||||||
|
{
|
||||||
|
result[i] = valueUInt64;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[i] is float valueFloat)
|
||||||
|
{
|
||||||
|
result[i] = *(ulong*)&valueFloat;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (args[i] is IntPtr valueIntPtr)
|
||||||
|
{
|
||||||
|
result[i] = (ulong)valueIntPtr.ToInt64();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException("Unknown primitive type in native argument list", nameof(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,8 +2,8 @@
|
|||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
@ -146,7 +146,8 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
flags |= PedDataFlags.IsInCover;
|
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;
|
flags |= PedDataFlags.IsInLowCover;
|
||||||
}
|
}
|
||||||
if (ped.IsTaskActive(TaskType.CTaskAimGunBlindFire))
|
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))
|
if (Function.Call<bool>(Hash.GET_PED_STEALTH_MOVEMENT, ped))
|
||||||
{
|
{
|
||||||
flags |= PedDataFlags.IsInStealthMode;
|
flags |= PedDataFlags.IsInStealthMode;
|
@ -1,22 +1,32 @@
|
|||||||
using GTA;
|
using GTA;
|
||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
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
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
internal static class Util
|
internal static class Util
|
||||||
{
|
{
|
||||||
|
public static void StartUpCheck()
|
||||||
|
{
|
||||||
|
if (AppDomain.CurrentDomain.GetData("RageCoop.Client.LoaderContext") == null)
|
||||||
|
{
|
||||||
|
var error = $"Client not loaded with loader, please re-install using the installer to fix this issue";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
GTA.UI.Notification.Show("~r~" + error);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
throw new Exception(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
public static SizeF ResolutionMaintainRatio
|
public static SizeF ResolutionMaintainRatio
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -111,53 +121,40 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
public static string SettingsPath = "Scripts\\RageCoop\\Data\\RageCoop.Client.Settings.xml";
|
public static string SettingsPath = "RageCoop\\Settings.json";
|
||||||
public static Settings ReadSettings()
|
public static Settings ReadSettings(string path = null)
|
||||||
{
|
{
|
||||||
XmlSerializer ser = new XmlSerializer(typeof(Settings));
|
path = path ?? SettingsPath;
|
||||||
|
|
||||||
string path = SettingsPath;
|
|
||||||
Directory.CreateDirectory(Directory.GetParent(path).FullName);
|
Directory.CreateDirectory(Directory.GetParent(path).FullName);
|
||||||
Settings settings = null;
|
Settings settings;
|
||||||
|
try
|
||||||
if (File.Exists(path))
|
|
||||||
{
|
{
|
||||||
using (FileStream stream = File.OpenRead(path))
|
settings = JsonConvert.DeserializeObject<Settings>(File.ReadAllText(path));
|
||||||
{
|
|
||||||
settings = (RageCoop.Client.Settings)ser.Deserialize(stream);
|
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
using (FileStream stream = new FileStream(path, FileMode.Truncate, FileAccess.ReadWrite))
|
|
||||||
{
|
{
|
||||||
ser.Serialize(stream, settings);
|
Main.Logger?.Error(ex);
|
||||||
}
|
File.WriteAllText(path, JsonConvert.SerializeObject(settings = new Settings(), Formatting.Indented));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
using (FileStream stream = File.OpenWrite(path))
|
|
||||||
{
|
|
||||||
ser.Serialize(stream, settings = new Settings());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
public static void SaveSettings()
|
public static bool SaveSettings(string path = null, Settings settings = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string path = SettingsPath;
|
path = path ?? SettingsPath;
|
||||||
|
settings = settings ?? Main.Settings;
|
||||||
Directory.CreateDirectory(Directory.GetParent(path).FullName);
|
Directory.CreateDirectory(Directory.GetParent(path).FullName);
|
||||||
|
|
||||||
using (FileStream stream = new FileStream(path, File.Exists(path) ? FileMode.Truncate : FileMode.Create, FileAccess.ReadWrite))
|
File.WriteAllText(path, JsonConvert.SerializeObject(settings, Formatting.Indented));
|
||||||
{
|
return true;
|
||||||
XmlSerializer ser = new XmlSerializer(typeof(Settings));
|
|
||||||
ser.Serialize(stream, Main.Settings);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
GTA.UI.Notification.Show("Error saving player settings: " + ex.Message);
|
Main.Logger?.Error(ex);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,62 +214,8 @@ namespace RageCoop.Client
|
|||||||
Function.Call(Hash.SET_RADIO_TO_STATION_INDEX, index);
|
Function.Call(Hash.SET_RADIO_TO_STATION_INDEX, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region WIN32
|
|
||||||
|
|
||||||
const UInt32 WM_KEYDOWN = 0x0100;
|
|
||||||
public static void Reload()
|
|
||||||
{
|
|
||||||
string reloadKey = "None";
|
|
||||||
var lines = File.ReadAllLines("ScriptHookVDotNet.ini");
|
|
||||||
foreach (var l in lines)
|
|
||||||
{
|
|
||||||
var ss = l.Split('=');
|
|
||||||
if (ss.Length > 0 && ss[0]=="ReloadKey")
|
|
||||||
{
|
|
||||||
reloadKey = ss[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var lineList = lines.ToList();
|
|
||||||
if (reloadKey=="None")
|
|
||||||
{
|
|
||||||
foreach (var l in lines)
|
|
||||||
{
|
|
||||||
var ss = l.Split('=');
|
|
||||||
if (ss.Length > 0 && ss[0]=="ReloadKey")
|
|
||||||
{
|
|
||||||
reloadKey = ss[1];
|
|
||||||
lineList.Remove(l);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lineList.Add("ReloadKey=Insert");
|
|
||||||
File.WriteAllLines("ScriptHookVDotNet.ini", lineList.ToArray());
|
|
||||||
GTA.UI.Notification.Show("Reload cannot be performed automatically, please type \"Reload()\" manually in the SHVDN console.");
|
|
||||||
}
|
|
||||||
Keys key = (Keys)Enum.Parse(typeof(Keys), reloadKey, true);
|
|
||||||
|
|
||||||
// Move log file so it doesn't get deleted
|
|
||||||
Main.Logger.Dispose();
|
|
||||||
|
|
||||||
var path = Main.Logger.LogPath+".last.log";
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (File.Exists(path)) { File.Delete(path); }
|
|
||||||
if (File.Exists(Main.Logger.LogPath)) { File.Move(Main.Logger.LogPath, path); }
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
GTA.UI.Notification.Show(ex.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
PostMessage(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle, WM_KEYDOWN, (int)key, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
|
|
||||||
|
|
||||||
|
|
||||||
[DllImport("kernel32.dll")]
|
[DllImport("kernel32.dll")]
|
||||||
public static extern ulong GetTickCount64();
|
public static extern ulong GetTickCount64();
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -54,38 +54,45 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
flags |= VehicleDataFlags.IsTransformed;
|
flags |= VehicleDataFlags.IsTransformed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v.IsAircraft)
|
if (v.IsAircraft)
|
||||||
{
|
{
|
||||||
flags |= VehicleDataFlags.IsAircraft;
|
flags |= VehicleDataFlags.IsAircraft;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v.IsDeluxo && veh.IsDeluxoHovering())
|
if (v.IsDeluxo && veh.IsDeluxoHovering())
|
||||||
{
|
{
|
||||||
flags |= VehicleDataFlags.IsDeluxoHovering;
|
flags |= VehicleDataFlags.IsDeluxoHovering;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v.HasRoof)
|
if (v.HasRoof)
|
||||||
{
|
{
|
||||||
flags |= VehicleDataFlags.HasRoof;
|
flags |= VehicleDataFlags.HasRoof;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v.HasRocketBoost && veh.IsRocketBoostActive())
|
if (v.HasRocketBoost && veh.IsRocketBoostActive())
|
||||||
{
|
{
|
||||||
flags |= VehicleDataFlags.IsRocketBoostActive;
|
flags |= VehicleDataFlags.IsRocketBoostActive;
|
||||||
}
|
}
|
||||||
if(v.HasParachute && veh.IsParachuteActive()){
|
|
||||||
|
if (v.HasParachute && veh.IsParachuteActive())
|
||||||
|
{
|
||||||
flags |= VehicleDataFlags.IsParachuteActive;
|
flags |= VehicleDataFlags.IsParachuteActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (veh.IsOnFire)
|
if (veh.IsOnFire)
|
||||||
{
|
{
|
||||||
flags |= VehicleDataFlags.IsOnFire;
|
flags |= VehicleDataFlags.IsOnFire;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
public static bool IsRocketBoostActive(this Vehicle veh)
|
public static bool IsRocketBoostActive(this Vehicle veh)
|
||||||
{
|
{
|
||||||
return Function.Call<bool>(Hash._IS_VEHICLE_ROCKET_BOOST_ACTIVE, veh);
|
return Function.Call<bool>(Hash._IS_VEHICLE_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);
|
return Function.Call<bool>((Hash)0x3DE51E9C80B116CF, veh);
|
||||||
}
|
}
|
||||||
public static void SetRocketBoostActive(this Vehicle veh, bool toggle)
|
public static void SetRocketBoostActive(this Vehicle veh, bool toggle)
|
||||||
@ -133,7 +140,6 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Bursted tires
|
// Bursted tires
|
||||||
short burstedTires = 0;
|
short burstedTires = 0;
|
||||||
foreach (VehicleWheel wheel in veh.Wheels.GetAllWheels())
|
foreach (VehicleWheel wheel in veh.Wheels.GetAllWheels())
|
||||||
@ -228,13 +234,12 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
if (p.IsSittingInVehicle())
|
if (p.IsSittingInVehicle())
|
||||||
{
|
{
|
||||||
ps.Add((int)p.SeatIndex, (int)p.GetSyncEntity().ID);
|
ps.Add((int)p.SeatIndex, p.GetSyncEntity().ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ps;
|
return ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void SetDeluxoHoverState(this Vehicle deluxo, bool hover)
|
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_VEHICLE_HOVER_TRANSFORM_PERCENTAGE, deluxo, hover ? 1f : 0f);
|
||||||
@ -283,8 +288,6 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
Function.Call(Hash.SET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane, ratio);
|
Function.Call(Hash.SET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane, ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,6 @@
|
|||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml;
|
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
@ -46,7 +45,8 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
return p.Bones[Bone.SkelRightHand].Position;
|
return p.Bones[Bone.SkelRightHand].Position;
|
||||||
}
|
}
|
||||||
static long BulletsShot = 0;
|
|
||||||
|
private static long BulletsShot = 0;
|
||||||
|
|
||||||
public static float GetWeaponDamage(this Ped P, uint hash)
|
public static float GetWeaponDamage(this Ped P, uint hash)
|
||||||
{
|
{
|
||||||
@ -362,7 +362,7 @@ namespace RageCoop.Client
|
|||||||
return 30;
|
return 30;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -1;
|
return AddOnDataProvider.GetMuzzleIndex(v.Model.Hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static bool IsUsingProjectileWeapon(this Ped p)
|
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);
|
var type = Function.Call<int>(Hash.GET_WEAPON_DAMAGE_TYPE, vp);
|
||||||
if (vp != VehicleWeaponHash.Invalid)
|
if (vp != VehicleWeaponHash.Invalid)
|
||||||
{
|
{
|
||||||
if (type==3)
|
return type == 3 ? false : VehicleProjectileWeapons.Contains(vp) || (type == 5 && !ExplosiveBullets.Contains((uint)vp));
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return VehicleProjectileWeapons.Contains(vp) || (type==5 && !ExplosiveBullets.Contains((uint)vp));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var w = p.Weapons.Current;
|
var w = p.Weapons.Current;
|
||||||
return w.Group == WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
|
return w.Group == WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly HashSet<uint> ExplosiveBullets = new HashSet<uint>
|
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> {
|
public static readonly HashSet<WeaponHash> ProjectileWeapons = new HashSet<WeaponHash> {
|
||||||
WeaponHash.HomingLauncher,
|
WeaponHash.HomingLauncher,
|
||||||
WeaponHash.RPG,
|
WeaponHash.RPG,
|
@ -1,61 +1,80 @@
|
|||||||
using GTA;
|
using GTA;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Don't use it!
|
/// Don't use it!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WorldThread : Script
|
[ScriptAttributes(Author = "RageCoop", NoDefaultInstance = false, SupportURL = "https://github.com/RAGECOOP/RAGECOOP-V")]
|
||||||
|
internal class WorldThread : Script
|
||||||
{
|
{
|
||||||
private static bool _lastDisableTraffic = false;
|
public static Script Instance;
|
||||||
|
private static readonly List<Func<bool>> QueuedActions = new List<Func<bool>>();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Don't use it!
|
/// Don't use it!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public WorldThread()
|
public WorldThread()
|
||||||
{
|
{
|
||||||
|
Util.StartUpCheck();
|
||||||
|
Instance = this;
|
||||||
Tick += OnTick;
|
Tick += OnTick;
|
||||||
Aborted += (sender, e) =>
|
Aborted += (sender, e) =>
|
||||||
{
|
{
|
||||||
if (_lastDisableTraffic)
|
ChangeTraffic(true);
|
||||||
{
|
|
||||||
Traffic(true);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool _trafficEnabled;
|
||||||
private void OnTick(object sender, EventArgs e)
|
private void OnTick(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
DoQueuedActions();
|
||||||
if (Game.IsLoading || !Networking.IsOnServer)
|
if (Game.IsLoading || !Networking.IsOnServer)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game.DisableControlThisFrame(Control.FrontendPause);
|
Game.DisableControlThisFrame(Control.FrontendPause);
|
||||||
Game.DisableControlThisFrame(Control.VehicleExit);
|
|
||||||
Game.DisableControlThisFrame(Control.Enter);
|
|
||||||
|
|
||||||
if (Main.Settings.DisableAlternatePause)
|
if (Main.Settings.DisableAlternatePause)
|
||||||
{
|
{
|
||||||
Game.DisableControlThisFrame(Control.FrontendPauseAlternate);
|
Game.DisableControlThisFrame(Control.FrontendPauseAlternate);
|
||||||
}
|
}
|
||||||
var P = Game.Player.Character;
|
|
||||||
|
|
||||||
// Sets a value that determines how aggressive the ocean waves will be.
|
// 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.
|
// 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_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.ShowEntityOwnerName)
|
||||||
if (Main.Settings==null) { return; }
|
|
||||||
if (Main.Settings.DisableTraffic)
|
|
||||||
{
|
{
|
||||||
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_VEHICLE_POPULATION_BUDGET, 0);
|
||||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
|
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
|
||||||
Function.Call(Hash.SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
|
Function.Call(Hash.SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
|
||||||
@ -64,15 +83,13 @@ namespace RageCoop.Client
|
|||||||
Function.Call(Hash.SUPPRESS_SHOCKING_EVENTS_NEXT_FRAME);
|
Function.Call(Hash.SUPPRESS_SHOCKING_EVENTS_NEXT_FRAME);
|
||||||
Function.Call(Hash.SUPPRESS_AGITATION_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)
|
public static void Traffic(bool enable)
|
||||||
|
{
|
||||||
|
ChangeTraffic(enable);
|
||||||
|
_trafficEnabled = enable;
|
||||||
|
}
|
||||||
|
private static void ChangeTraffic(bool enable)
|
||||||
{
|
{
|
||||||
if (enable)
|
if (enable)
|
||||||
{
|
{
|
||||||
@ -81,15 +98,15 @@ namespace RageCoop.Client
|
|||||||
Function.Call(Hash.SET_RANDOM_TRAINS, true);
|
Function.Call(Hash.SET_RANDOM_TRAINS, true);
|
||||||
Function.Call(Hash.SET_RANDOM_BOATS, true);
|
Function.Call(Hash.SET_RANDOM_BOATS, true);
|
||||||
Function.Call(Hash.SET_GARBAGE_TRUCKS, true);
|
Function.Call(Hash.SET_GARBAGE_TRUCKS, true);
|
||||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 1); // 0 - 3
|
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 3); // 0 - 3
|
||||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 1); // 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_VEHICLE_GENERATORS_ACTIVE);
|
||||||
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, true);
|
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, true);
|
||||||
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, -1);
|
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, -1);
|
||||||
Function.Call(Hash.SET_DISTANT_CARS_ENABLED, true);
|
Function.Call(Hash.SET_DISTANT_CARS_ENABLED, true);
|
||||||
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, false);
|
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.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);
|
Function.Call(Hash.SET_CREATE_RANDOM_COPS, false);
|
||||||
@ -97,34 +114,31 @@ namespace RageCoop.Client
|
|||||||
Function.Call(Hash.SET_RANDOM_BOATS, false);
|
Function.Call(Hash.SET_RANDOM_BOATS, false);
|
||||||
Function.Call(Hash.SET_GARBAGE_TRUCKS, false);
|
Function.Call(Hash.SET_GARBAGE_TRUCKS, false);
|
||||||
Function.Call(Hash.DELETE_ALL_TRAINS);
|
Function.Call(Hash.DELETE_ALL_TRAINS);
|
||||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 3);
|
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
|
||||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 3);
|
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 0);
|
||||||
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, false);
|
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, false);
|
||||||
Function.Call(Hash.SET_FAR_DRAW_VEHICLES, false);
|
Function.Call(Hash.SET_FAR_DRAW_VEHICLES, false);
|
||||||
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, 0);
|
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, 0);
|
||||||
Function.Call(Hash.SET_DISTANT_CARS_ENABLED, false);
|
Function.Call(Hash.SET_DISTANT_CARS_ENABLED, false);
|
||||||
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, true);
|
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, true);
|
||||||
|
|
||||||
|
|
||||||
foreach (Ped ped in World.GetAllPeds())
|
foreach (Ped ped in World.GetAllPeds())
|
||||||
{
|
{
|
||||||
|
if (ped == Game.Player.Character) { continue; }
|
||||||
SyncedPed c = EntityPool.GetPedByHandle(ped.Handle);
|
SyncedPed c = EntityPool.GetPedByHandle(ped.Handle);
|
||||||
if ((c == null) || (c.IsLocal && (ped.Handle != Game.Player.Character.Handle) && ped.PopulationType != EntityPopulationType.Mission))
|
if ((c == null) || (c.IsLocal && (ped.Handle != Game.Player.Character.Handle) && ped.PopulationType != EntityPopulationType.Mission))
|
||||||
{
|
{
|
||||||
if (ped.Handle==Game.Player.Character.Handle) { continue; }
|
|
||||||
|
|
||||||
// Main.Logger.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
|
Main.Logger.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
|
||||||
ped.CurrentVehicle?.Delete();
|
ped.CurrentVehicle?.Delete();
|
||||||
ped.Kill();
|
ped.Kill();
|
||||||
ped.Delete();
|
ped.Delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Vehicle veh in World.GetAllVehicles())
|
foreach (Vehicle veh in World.GetAllVehicles())
|
||||||
{
|
{
|
||||||
SyncedVehicle v = veh.GetSyncEntity();
|
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
|
// Don't delete player's vehicle
|
||||||
continue;
|
continue;
|
||||||
@ -138,5 +152,61 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Delay(Action a, int time)
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
Thread.Sleep(time);
|
||||||
|
QueueAction(a);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
internal static void DoQueuedActions()
|
||||||
|
{
|
||||||
|
lock (QueuedActions)
|
||||||
|
{
|
||||||
|
foreach (var action in QueuedActions.ToArray())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (action())
|
||||||
|
{
|
||||||
|
QueuedActions.Remove(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Main.Logger.Error(ex);
|
||||||
|
QueuedActions.Remove(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a"> An action to be executed with a return value indicating whether the action can be removed after execution.</param>
|
||||||
|
internal static void QueueAction(Func<bool> a)
|
||||||
|
{
|
||||||
|
lock (QueuedActions)
|
||||||
|
{
|
||||||
|
QueuedActions.Add(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static void QueueAction(Action a)
|
||||||
|
{
|
||||||
|
lock (QueuedActions)
|
||||||
|
{
|
||||||
|
QueuedActions.Add(() => { a(); return true; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Clears all queued actions
|
||||||
|
/// </summary>
|
||||||
|
internal static void ClearQueuedActions()
|
||||||
|
{
|
||||||
|
lock (QueuedActions) { QueuedActions.Clear(); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
11
Client/Scripts/app.config
Normal file
11
Client/Scripts/app.config
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<runtime>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
</runtime>
|
||||||
|
</configuration>
|
@ -1,21 +1,21 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="Costura.Fody" version="5.7.0" targetFramework="net48" developmentDependency="true" />
|
|
||||||
<package id="Fody" version="6.6.3" targetFramework="net48" developmentDependency="true" />
|
|
||||||
<package id="Microsoft.Extensions.ObjectPool" version="6.0.8" targetFramework="net48" />
|
<package id="Microsoft.Extensions.ObjectPool" version="6.0.8" targetFramework="net48" />
|
||||||
<package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net48" />
|
<package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net48" />
|
||||||
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net48" />
|
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="Microsoft.Win32.Registry" version="4.7.0" targetFramework="net481" />
|
<package id="Microsoft.Win32.Registry" version="4.7.0" targetFramework="net481" />
|
||||||
<package id="NAudio" version="2.1.0" targetFramework="net481" />
|
<package id="NAudio" version="2.1.0" targetFramework="net48" />
|
||||||
<package id="NAudio.Asio" version="2.1.0" targetFramework="net481" />
|
<package id="NAudio.Asio" version="2.1.0" targetFramework="net48" />
|
||||||
<package id="NAudio.Core" version="2.1.0" targetFramework="net481" />
|
<package id="NAudio.Core" version="2.1.0" targetFramework="net48" />
|
||||||
<package id="NAudio.Midi" version="2.1.0" targetFramework="net481" />
|
<package id="NAudio.Midi" version="2.1.0" targetFramework="net48" />
|
||||||
<package id="NAudio.Wasapi" version="2.1.0" targetFramework="net481" />
|
<package id="NAudio.Wasapi" version="2.1.0" targetFramework="net48" />
|
||||||
<package id="NAudio.WinForms" version="2.1.0" targetFramework="net481" />
|
<package id="NAudio.WinForms" version="2.1.0" targetFramework="net48" />
|
||||||
<package id="NAudio.WinMM" version="2.1.0" targetFramework="net481" />
|
<package id="NAudio.WinMM" version="2.1.0" targetFramework="net48" />
|
||||||
<package id="NETStandard.Library" version="1.6.1" targetFramework="net48" />
|
<package id="NETStandard.Library" version="1.6.1" targetFramework="net48" />
|
||||||
<package id="SharpZipLib" version="1.3.3" targetFramework="net48" />
|
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
|
||||||
|
<package id="SharpZipLib" version="1.4.0" targetFramework="net48" />
|
||||||
<package id="System.AppContext" version="4.3.0" targetFramework="net48" />
|
<package id="System.AppContext" version="4.3.0" targetFramework="net48" />
|
||||||
|
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
|
||||||
<package id="System.Collections" version="4.3.0" targetFramework="net48" />
|
<package id="System.Collections" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net48" />
|
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Console" version="4.3.0" targetFramework="net48" />
|
<package id="System.Console" version="4.3.0" targetFramework="net48" />
|
||||||
@ -32,15 +32,18 @@
|
|||||||
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net48" />
|
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Linq" version="4.3.0" targetFramework="net48" />
|
<package id="System.Linq" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net48" />
|
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net48" />
|
||||||
|
<package id="System.Memory" version="4.5.4" targetFramework="net48" />
|
||||||
<package id="System.Net.Http" version="4.3.0" targetFramework="net48" />
|
<package id="System.Net.Http" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Net.Primitives" version="4.3.0" targetFramework="net48" />
|
<package id="System.Net.Primitives" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Net.Sockets" version="4.3.0" targetFramework="net48" />
|
<package id="System.Net.Sockets" version="4.3.0" targetFramework="net48" />
|
||||||
|
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
|
||||||
<package id="System.ObjectModel" version="4.3.0" targetFramework="net48" />
|
<package id="System.ObjectModel" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Reflection" version="4.3.0" targetFramework="net48" />
|
<package id="System.Reflection" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net48" />
|
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net48" />
|
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net48" />
|
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Runtime" version="4.3.0" targetFramework="net48" />
|
<package id="System.Runtime" version="4.3.0" targetFramework="net48" />
|
||||||
|
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net48" />
|
||||||
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net48" />
|
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Runtime.Handles" version="4.3.0" targetFramework="net48" />
|
<package id="System.Runtime.Handles" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net48" />
|
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net48" />
|
||||||
@ -57,6 +60,7 @@
|
|||||||
<package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net48" />
|
<package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Threading" version="4.3.0" targetFramework="net48" />
|
<package id="System.Threading" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net48" />
|
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net48" />
|
||||||
|
<package id="System.Threading.Tasks.Extensions" version="4.5.2" targetFramework="net48" />
|
||||||
<package id="System.Threading.Timer" version="4.3.0" targetFramework="net48" />
|
<package id="System.Threading.Timer" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net48" />
|
<package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net48" />
|
||||||
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net48" />
|
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net48" />
|
@ -1,8 +1,6 @@
|
|||||||
using System;
|
using GTA.Math;
|
||||||
using System.Text;
|
|
||||||
using System.Linq;
|
|
||||||
using GTA.Math;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
{
|
{
|
@ -1,73 +1,113 @@
|
|||||||
using System;
|
using GTA.Math;
|
||||||
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 Lidgren.Network;
|
using Lidgren.Network;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using RageCoop.Core.Scripting;
|
||||||
|
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.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("RageCoop.Server")]
|
[assembly: InternalsVisibleTo("RageCoop.Server")]
|
||||||
[assembly: InternalsVisibleTo("RageCoop.Client")]
|
[assembly: InternalsVisibleTo("RageCoop.Client")]
|
||||||
|
[assembly: InternalsVisibleTo("RageCoop.Client.Installer")]
|
||||||
|
[assembly: InternalsVisibleTo("RageCoop.ResourceBuilder")]
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
{
|
{
|
||||||
internal static class CoreUtils
|
internal static class CoreUtils
|
||||||
{
|
{
|
||||||
private static readonly HashSet<string> ToIgnore = new HashSet<string>()
|
private static readonly HashSet<string> ToIgnore = new HashSet<string>()
|
||||||
{
|
{
|
||||||
"RageCoop.Client.dll",
|
"RageCoop.Client",
|
||||||
"RageCoop.Core.dll",
|
"RageCoop.Client.Loader",
|
||||||
"RageCoop.Server.dll",
|
"RageCoop.Client.Installer",
|
||||||
"ScriptHookVDotNet3.dll",
|
"RageCoop.Core",
|
||||||
"ScriptHookVDotNet.dll"
|
"RageCoop.Server",
|
||||||
|
"ScriptHookVDotNet2",
|
||||||
|
"ScriptHookVDotNet3",
|
||||||
|
"ScriptHookVDotNet"
|
||||||
};
|
};
|
||||||
|
public static void GetDependencies(Assembly assembly, ref HashSet<string> existing)
|
||||||
|
{
|
||||||
|
if (assembly.FullName.StartsWith("System")) { return; }
|
||||||
|
foreach(var name in assembly.GetReferencedAssemblies())
|
||||||
|
{
|
||||||
|
if (name.FullName.StartsWith("System")) { continue; }
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var asm = Assembly.Load(name);
|
||||||
|
GetDependencies(asm,ref existing);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
if (!existing.Contains(assembly.FullName))
|
||||||
|
{
|
||||||
|
Console.WriteLine(assembly.FullName);
|
||||||
|
existing.Add(assembly.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static Version GetLatestVersion(string branch = "dev-nightly")
|
||||||
|
{
|
||||||
|
var url = $"https://raw.githubusercontent.com/RAGECOOP/RAGECOOP-V/{branch}/RageCoop.Server/Properties/AssemblyInfo.cs";
|
||||||
|
var versionLine = HttpHelper.DownloadString(url).Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries).Where(x => x.Contains("[assembly: AssemblyVersion(")).First();
|
||||||
|
var start = versionLine.IndexOf('\"') + 1;
|
||||||
|
var end = versionLine.LastIndexOf('\"');
|
||||||
|
return Version.Parse(versionLine.Substring(start, end - start));
|
||||||
|
}
|
||||||
public static bool CanBeIgnored(this string name)
|
public static bool CanBeIgnored(this string name)
|
||||||
{
|
{
|
||||||
return ToIgnore.Contains(name);
|
return ToIgnore.Contains(Path.GetFileNameWithoutExtension(name));
|
||||||
}
|
}
|
||||||
public static (byte, byte[]) GetBytesFromObject(object obj)
|
public static string ToFullPath(this string path)
|
||||||
|
{
|
||||||
|
return Path.GetFullPath(path);
|
||||||
|
}
|
||||||
|
public static void GetBytesFromObject(object obj, NetOutgoingMessage m)
|
||||||
{
|
{
|
||||||
switch (obj)
|
switch (obj)
|
||||||
{
|
{
|
||||||
case byte _:
|
case byte value:
|
||||||
return (0x01, new byte[] { (byte)obj });
|
m.Write((byte)0x01); m.Write(value); break;
|
||||||
case short _:
|
case short value:
|
||||||
return (0x02, BitConverter.GetBytes((short)obj));
|
m.Write((byte)0x02); m.Write(value); break;
|
||||||
case ushort _:
|
case ushort value:
|
||||||
return (0x03, BitConverter.GetBytes((ushort)obj));
|
m.Write((byte)0x03); m.Write(value); break;
|
||||||
case int _:
|
case int value:
|
||||||
return (0x04, BitConverter.GetBytes((int)obj));
|
m.Write((byte)0x04); m.Write(value); break;
|
||||||
case uint _:
|
case uint value:
|
||||||
return (0x05, BitConverter.GetBytes((uint)obj));
|
m.Write((byte)0x05); m.Write(value); break;
|
||||||
case long _:
|
case long value:
|
||||||
return (0x06, BitConverter.GetBytes((long)obj));
|
m.Write((byte)0x06); m.Write(value); break;
|
||||||
case ulong _:
|
case ulong value:
|
||||||
return (0x07, BitConverter.GetBytes((ulong)obj));
|
m.Write((byte)0x07); m.Write(value); break;
|
||||||
case float _:
|
case float value:
|
||||||
return (0x08, BitConverter.GetBytes((float)obj));
|
m.Write((byte)0x08); m.Write(value); break;
|
||||||
case bool _:
|
case bool value:
|
||||||
return (0x09, BitConverter.GetBytes((bool)obj));
|
m.Write((byte)0x09); m.Write(value); break;
|
||||||
case string _:
|
case string value:
|
||||||
return (0x10, ((string)obj).GetBytesWithLength());
|
m.Write((byte)0x10); m.Write(value); break;
|
||||||
case Vector3 _:
|
case Vector3 value:
|
||||||
return (0x11,((Vector3)obj).GetBytes());
|
m.Write((byte)0x11); m.Write(value); break;
|
||||||
case Quaternion _:
|
case Quaternion value:
|
||||||
return (0x12, ((Quaternion)obj).GetBytes());
|
m.Write((byte)0x12); m.Write(value); break;
|
||||||
case GTA.Model _:
|
case GTA.Model value:
|
||||||
return (0x13, BitConverter.GetBytes((GTA.Model)obj));
|
m.Write((byte)0x13); m.Write(value); break;
|
||||||
case Vector2 _:
|
case Vector2 value:
|
||||||
return (0x14, ((Vector2)obj).GetBytes());
|
m.Write((byte)0x14); m.Write(value); break;
|
||||||
case Tuple<byte, byte[]> _:
|
case byte[] value:
|
||||||
var tup = (Tuple<byte, byte[]>)obj;
|
m.Write((byte)0x15); m.WriteByteArray(value); break;
|
||||||
return (tup.Item1, tup.Item2);
|
case Tuple<byte, byte[]> value:
|
||||||
|
m.Write(value.Item1); m.Write(value.Item2); break;
|
||||||
default:
|
default:
|
||||||
return (0x0, null);
|
throw new Exception("Unsupported object type: " + obj.GetType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static IPEndPoint StringToEndPoint(string endpointstring)
|
public static IPEndPoint StringToEndPoint(string endpointstring)
|
||||||
@ -134,9 +174,8 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
private static int getPort(string p)
|
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.MinPort
|
||||||
|| port > IPEndPoint.MaxPort)
|
|| port > IPEndPoint.MaxPort)
|
||||||
{
|
{
|
||||||
@ -181,10 +220,54 @@ namespace RageCoop.Core
|
|||||||
return JsonConvert.DeserializeObject<IpInfo>(content);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StreamWriter OpenWriter(string path, FileMode mode = FileMode.Create, FileAccess access = FileAccess.Write, FileShare share = FileShare.ReadWrite)
|
||||||
|
{
|
||||||
|
return new StreamWriter(File.Open(path, mode, access, share));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal class IpInfo
|
||||||
{
|
{
|
||||||
[JsonProperty("ip")]
|
[JsonProperty("ip")]
|
||||||
public string Address { get; set; }
|
public string Address { get; set; }
|
||||||
@ -194,74 +277,10 @@ namespace RageCoop.Core
|
|||||||
}
|
}
|
||||||
internal static class Extensions
|
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)
|
public static byte[] GetBytes(this string s)
|
||||||
{
|
{
|
||||||
return Encoding.UTF8.GetBytes(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)
|
public static string GetString(this byte[] data)
|
||||||
{
|
{
|
||||||
return Encoding.UTF8.GetString(data);
|
return Encoding.UTF8.GetString(data);
|
||||||
@ -288,35 +307,33 @@ namespace RageCoop.Core
|
|||||||
// 16 bytes
|
// 16 bytes
|
||||||
return new List<byte[]>() { BitConverter.GetBytes(qua.X), BitConverter.GetBytes(qua.Y), BitConverter.GetBytes(qua.Z), BitConverter.GetBytes(qua.W) }.Join(4);
|
return new List<byte[]>() { BitConverter.GetBytes(qua.X), BitConverter.GetBytes(qua.Y), BitConverter.GetBytes(qua.Z), BitConverter.GetBytes(qua.W) }.Join(4);
|
||||||
}
|
}
|
||||||
|
public static T GetPacket<T>(this NetIncomingMessage msg) where T : Packet, new()
|
||||||
|
|
||||||
public static T GetPacket<T>(this NetIncomingMessage msg, T existingPacket = null) where T : Packet, new()
|
|
||||||
{
|
{
|
||||||
msg.ReadByte();
|
var p = new T();
|
||||||
return GetPacket<T>(msg.ReadBytes(msg.ReadInt32()),existingPacket);
|
p.Deserialize(msg);
|
||||||
}
|
|
||||||
public static T GetPacket<T>(this byte[] data, T existingPacket=null) where T : Packet, new()
|
|
||||||
{
|
|
||||||
var p = existingPacket??new T();
|
|
||||||
p.Deserialize(data);
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
public static bool HasPedFlag(this PedDataFlags flagToCheck, PedDataFlags flag)
|
public static bool HasPedFlag(this PedDataFlags flags, PedDataFlags flag)
|
||||||
{
|
{
|
||||||
return (flagToCheck & flag)!=0;
|
return (flags & flag) != 0;
|
||||||
}
|
}
|
||||||
public static bool HasProjDataFlag(this ProjectileDataFlags flagToCheck, ProjectileDataFlags flag)
|
public static bool HasProjDataFlag(this ProjectileDataFlags flags, ProjectileDataFlags flag)
|
||||||
{
|
{
|
||||||
return (flagToCheck & flag)!=0;
|
return (flags & flag) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasVehFlag(this VehicleDataFlags flagToCheck, VehicleDataFlags flag)
|
public static bool HasVehFlag(this VehicleDataFlags flags, VehicleDataFlags flag)
|
||||||
{
|
{
|
||||||
return (flagToCheck & flag)!=0;
|
return (flags & flag) != 0;
|
||||||
}
|
}
|
||||||
public static bool HasConfigFlag(this PlayerConfigFlags flagToCheck, PlayerConfigFlags flag)
|
public static bool HasConfigFlag(this PlayerConfigFlags flags, PlayerConfigFlags flag)
|
||||||
{
|
{
|
||||||
return (flagToCheck & flag)!=0;
|
return (flags & flag) != 0;
|
||||||
|
}
|
||||||
|
public static bool HasEventFlag(this CustomEventFlags flags, CustomEventFlags flag)
|
||||||
|
{
|
||||||
|
return (flags & flag) != 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
public static Type GetActualType(this TypeCode code)
|
public static Type GetActualType(this TypeCode code)
|
||||||
{
|
{
|
||||||
@ -391,7 +408,7 @@ namespace RageCoop.Core
|
|||||||
}
|
}
|
||||||
public static string Dump<T>(this IEnumerable<T> objects)
|
public static string Dump<T>(this IEnumerable<T> objects)
|
||||||
{
|
{
|
||||||
return "{"+string.Join(",",objects)+"}";
|
return $"{{{string.Join(",", objects)}}}";
|
||||||
}
|
}
|
||||||
public static void ForEach<T>(this IEnumerable<T> objects, Action<T> action)
|
public static void ForEach<T>(this IEnumerable<T> objects, Action<T> action)
|
||||||
{
|
{
|
||||||
@ -411,6 +428,12 @@ namespace RageCoop.Core
|
|||||||
return memoryStream.ToArray();
|
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)
|
public static byte[] Join(this List<byte[]> arrays, int lengthPerArray = -1)
|
||||||
{
|
{
|
||||||
if (arrays.Count == 1) { return arrays[0]; }
|
if (arrays.Count == 1) { return arrays[0]; }
|
||||||
@ -424,13 +447,11 @@ namespace RageCoop.Core
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsSubclassOf(this Type type, string baseTypeName)
|
public static bool IsScript(this Type type, Type scriptType)
|
||||||
{
|
{
|
||||||
for (Type t = type.BaseType; t != null; t = t.BaseType)
|
return !type.IsAbstract && type.IsSubclassOf(scriptType);
|
||||||
if (t.FullName == baseTypeName)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -468,5 +489,6 @@ namespace RageCoop.Core
|
|||||||
{
|
{
|
||||||
return IPAddress.Parse(ip);
|
return IPAddress.Parse(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
176
Core/Logger.cs
Normal file
176
Core/Logger.cs
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
public enum LogLevel
|
||||||
|
{
|
||||||
|
Trace = 0,
|
||||||
|
Debug = 1,
|
||||||
|
Info = 2,
|
||||||
|
Warning = 3,
|
||||||
|
Error = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class Logger : MarshalByRefObject, IDisposable
|
||||||
|
{
|
||||||
|
public class LogLine
|
||||||
|
{
|
||||||
|
internal LogLine() { }
|
||||||
|
public DateTime TimeStamp;
|
||||||
|
public LogLevel LogLevel;
|
||||||
|
public string Message;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 0:Trace, 1:Debug, 2:Info, 3:Warning, 4:Error
|
||||||
|
/// </summary>
|
||||||
|
public int LogLevel = 0;
|
||||||
|
/// <summary>
|
||||||
|
/// Name of this logger
|
||||||
|
/// </summary>
|
||||||
|
public string Name = "Logger";
|
||||||
|
public readonly string DateTimeFormat = "HH:mm:ss";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to use UTC time for timestamping the log
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool UseUtc = false;
|
||||||
|
public List<StreamWriter> Writers = new List<StreamWriter> { new StreamWriter(Console.OpenStandardOutput()) };
|
||||||
|
public int FlushInterval = 1000;
|
||||||
|
public event FlushDelegate OnFlush;
|
||||||
|
public bool FlushImmediately = false;
|
||||||
|
public delegate void FlushDelegate(LogLine line, string fomatted);
|
||||||
|
|
||||||
|
private readonly Thread LoggerThread;
|
||||||
|
private bool Stopping = false;
|
||||||
|
private readonly ConcurrentQueue<LogLine> _queuedLines = new ConcurrentQueue<LogLine>();
|
||||||
|
internal Logger()
|
||||||
|
{
|
||||||
|
Name = Process.GetCurrentProcess().Id.ToString();
|
||||||
|
if (!FlushImmediately)
|
||||||
|
{
|
||||||
|
LoggerThread = new Thread(() =>
|
||||||
|
{
|
||||||
|
while (!Stopping)
|
||||||
|
{
|
||||||
|
Flush();
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
}
|
||||||
|
Flush();
|
||||||
|
});
|
||||||
|
LoggerThread.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
public void Info(string message)
|
||||||
|
{
|
||||||
|
Enqueue(2, message);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
public void Warning(string message)
|
||||||
|
{
|
||||||
|
Enqueue(3, message);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
public void Error(string message)
|
||||||
|
{
|
||||||
|
Enqueue(4, message);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="error"></param>
|
||||||
|
public void Error(string message, Exception error)
|
||||||
|
{
|
||||||
|
Enqueue(4, $"{message}:\n {error}");
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ex"></param>
|
||||||
|
public void Error(Exception ex)
|
||||||
|
{
|
||||||
|
Enqueue(4, ex.ToString());
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
public void Debug(string message)
|
||||||
|
{
|
||||||
|
Enqueue(1, message);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
public void Trace(string message)
|
||||||
|
{
|
||||||
|
Enqueue(0, message);
|
||||||
|
}
|
||||||
|
public void Enqueue(int level, string message)
|
||||||
|
{
|
||||||
|
if (level < LogLevel) { return; }
|
||||||
|
_queuedLines.Enqueue(new LogLine()
|
||||||
|
{
|
||||||
|
Message = message,
|
||||||
|
TimeStamp = UseUtc ? DateTime.UtcNow : DateTime.Now,
|
||||||
|
LogLevel = (LogLevel)level
|
||||||
|
});
|
||||||
|
if (FlushImmediately)
|
||||||
|
{
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Format(LogLine line)
|
||||||
|
{
|
||||||
|
return string.Format("[{0}][{2}] [{3}] {1}", line.TimeStamp.ToString(DateTimeFormat), line.Message, Name, line.LogLevel.ToString());
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public void Flush()
|
||||||
|
{
|
||||||
|
lock (_queuedLines)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (_queuedLines.TryDequeue(out var line))
|
||||||
|
{
|
||||||
|
var formatted = Format(line);
|
||||||
|
Writers.ForEach(x => { x.WriteLine(formatted); x.Flush(); });
|
||||||
|
OnFlush?.Invoke(line, formatted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Stop backdround thread and flush all pending messages.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Stopping = true;
|
||||||
|
LoggerThread?.Join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,8 @@
|
|||||||
using System;
|
using GTA.Math;
|
||||||
using GTA.Math;
|
using System;
|
||||||
|
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
{
|
{
|
||||||
|
|
||||||
internal static class MathExtensions
|
internal static class MathExtensions
|
||||||
{
|
{
|
||||||
public const float Deg2Rad = (float)(Math.PI * 2) / 360;
|
public const float Deg2Rad = (float)(Math.PI * 2) / 360;
|
||||||
@ -82,14 +81,14 @@ namespace RageCoop.Core
|
|||||||
vect = vect.ToRadians();
|
vect = vect.ToRadians();
|
||||||
|
|
||||||
float rollOver2 = vect.Z * 0.5f;
|
float rollOver2 = vect.Z * 0.5f;
|
||||||
float sinRollOver2 = (float)Math.Sin((double)rollOver2);
|
float sinRollOver2 = (float)Math.Sin(rollOver2);
|
||||||
float cosRollOver2 = (float)Math.Cos((double)rollOver2);
|
float cosRollOver2 = (float)Math.Cos(rollOver2);
|
||||||
float pitchOver2 = vect.Y * 0.5f;
|
float pitchOver2 = vect.Y * 0.5f;
|
||||||
float sinPitchOver2 = (float)Math.Sin((double)pitchOver2);
|
float sinPitchOver2 = (float)Math.Sin(pitchOver2);
|
||||||
float cosPitchOver2 = (float)Math.Cos((double)pitchOver2);
|
float cosPitchOver2 = (float)Math.Cos(pitchOver2);
|
||||||
float yawOver2 = vect.X * 0.5f; // pitch
|
float yawOver2 = vect.X * 0.5f; // pitch
|
||||||
float sinYawOver2 = (float)Math.Sin((double)yawOver2);
|
float sinYawOver2 = (float)Math.Sin(yawOver2);
|
||||||
float cosYawOver2 = (float)Math.Cos((double)yawOver2);
|
float cosYawOver2 = (float)Math.Cos(yawOver2);
|
||||||
Quaternion result = new Quaternion()
|
Quaternion result = new Quaternion()
|
||||||
{
|
{
|
||||||
X = cosYawOver2 * cosPitchOver2 * cosRollOver2 + sinYawOver2 * sinPitchOver2 * sinRollOver2,
|
X = cosYawOver2 * cosPitchOver2 * cosRollOver2 + sinYawOver2 * sinPitchOver2 * sinRollOver2,
|
||||||
@ -146,16 +145,12 @@ namespace RageCoop.Core
|
|||||||
}
|
}
|
||||||
private static float CopySign(double x, double y)
|
private static float CopySign(double x, double y)
|
||||||
{
|
{
|
||||||
bool isPositive = y>=0;
|
if (y >= 0)
|
||||||
if (isPositive)
|
|
||||||
{
|
{
|
||||||
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)
|
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)
|
public static float GetCosTheta(this Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
|
|
||||||
return Vector3.Dot(v1, v2) / (v1.Length() * v2.Length());
|
return Vector3.Dot(v1, v2) / (v1.Length() * v2.Length());
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using Lidgren.Network;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
|
||||||
using Lidgren.Network;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
@ -57,6 +56,5 @@ namespace RageCoop.Core
|
|||||||
p.Pack(outgoingMessage);
|
p.Pack(outgoingMessage);
|
||||||
SendMessage(outgoingMessage, cons, method, (int)channel);
|
SendMessage(outgoingMessage, cons, method, (int)channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
42
Core/Networking/HttpHelper.cs
Normal file
42
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
Core/Networking/PublicKey.cs
Normal file
22
Core/Networking/PublicKey.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal class PublicKey
|
||||||
|
{
|
||||||
|
public PublicKey()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public static PublicKey FromServerInfo(ServerInfo info)
|
||||||
|
{
|
||||||
|
return new PublicKey
|
||||||
|
{
|
||||||
|
Modulus = Convert.FromBase64String(info.publicKeyModulus),
|
||||||
|
Exponent = Convert.FromBase64String(info.publicKeyExponent)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public byte[] Modulus;
|
||||||
|
public byte[] Exponent;
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
internal class ServerInfo
|
/// A json object representing a server's information as annouced to master server.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class ServerInfo
|
||||||
{
|
{
|
||||||
|
#pragma warning disable 1591
|
||||||
public string address { get; set; }
|
public string address { get; set; }
|
||||||
public string port { get; set; }
|
public string port { get; set; }
|
||||||
public string name { get; set; }
|
public string name { get; set; }
|
@ -1,11 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.IO;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Net;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
@ -93,7 +91,8 @@ namespace RageCoop.Core
|
|||||||
}
|
}
|
||||||
public static Dictionary<string, ZeroTierNetwork> Networks
|
public static Dictionary<string, ZeroTierNetwork> Networks
|
||||||
{
|
{
|
||||||
get {
|
get
|
||||||
|
{
|
||||||
Dictionary<string, ZeroTierNetwork> networks = new Dictionary<string, ZeroTierNetwork>();
|
Dictionary<string, ZeroTierNetwork> networks = new Dictionary<string, ZeroTierNetwork>();
|
||||||
var p = Run("listnetworks");
|
var p = Run("listnetworks");
|
||||||
var lines = Regex.Split(p.StandardOutput.ReadToEnd(), "\n").Skip(1);
|
var lines = Regex.Split(p.StandardOutput.ReadToEnd(), "\n").Skip(1);
|
||||||
@ -131,5 +130,9 @@ namespace RageCoop.Core
|
|||||||
var p = Run(command);
|
var p = Run(command);
|
||||||
return p.StandardOutput.ReadToEnd() + p.StandardError.ReadToEnd();
|
return p.StandardOutput.ReadToEnd() + p.StandardError.ReadToEnd();
|
||||||
}
|
}
|
||||||
|
public static void Check()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
68
Core/PacketExtensions.cs
Normal file
68
Core/PacketExtensions.cs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
using GTA.Math;
|
||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
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 Lidgren.Network;
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
using Lidgren.Network;
|
|
||||||
|
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
{
|
{
|
||||||
@ -11,8 +10,8 @@ namespace RageCoop.Core
|
|||||||
internal class ChatMessage : Packet
|
internal class ChatMessage : Packet
|
||||||
{
|
{
|
||||||
public override PacketType Type => PacketType.ChatMessage;
|
public override PacketType Type => PacketType.ChatMessage;
|
||||||
private Func<string, byte[]> crypt;
|
private readonly Func<string, byte[]> crypt;
|
||||||
private Func<byte[], byte[]> decrypt;
|
private readonly Func<byte[], byte[]> decrypt;
|
||||||
public ChatMessage(Func<string, byte[]> crypter)
|
public ChatMessage(Func<string, byte[]> crypter)
|
||||||
{
|
{
|
||||||
crypt = crypter;
|
crypt = crypter;
|
||||||
@ -25,33 +24,31 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
|
|
||||||
public override byte[] Serialize()
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
{
|
{
|
||||||
|
|
||||||
List<byte> byteArray = new List<byte>();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Write Username
|
// Write Username
|
||||||
byteArray.AddString(Username);
|
m.Write(Username);
|
||||||
|
|
||||||
|
|
||||||
// Write Message
|
// Write Message
|
||||||
byteArray.AddArray(crypt(Message));
|
m.WriteByteArray(crypt(Message));
|
||||||
|
|
||||||
return byteArray.ToArray();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Deserialize(byte[] array)
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
{
|
{
|
||||||
#region NetIncomingMessageToPacket
|
#region NetIncomingMessageToPacket
|
||||||
BitReader reader = new BitReader(array);
|
|
||||||
|
|
||||||
// Read username
|
// Read username
|
||||||
Username = reader.ReadString();
|
Username = m.ReadString();
|
||||||
|
|
||||||
Message = decrypt(reader.ReadByteArray()).GetString();
|
Message = decrypt(m.ReadByteArray()).GetString();
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
88
Core/Packets/CustomEvent.cs
Normal file
88
Core/Packets/CustomEvent.cs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
using Lidgren.Network;
|
||||||
|
using RageCoop.Core.Scripting;
|
||||||
|
using System;
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class CustomEvent : Packet
|
||||||
|
{
|
||||||
|
public static Func<byte, NetIncomingMessage, object> ResolveHandle = null;
|
||||||
|
public CustomEventFlags Flags;
|
||||||
|
public override PacketType Type => PacketType.CustomEvent;
|
||||||
|
public CustomEvent(CustomEventFlags flags = CustomEventFlags.None)
|
||||||
|
{
|
||||||
|
Flags = flags;
|
||||||
|
}
|
||||||
|
public int Hash { get; set; }
|
||||||
|
public object[] Args { get; set; }
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
Args = Args ?? new object[] { };
|
||||||
|
m.Write((byte)Flags);
|
||||||
|
m.Write(Hash);
|
||||||
|
m.Write(Args.Length);
|
||||||
|
foreach (var arg in Args)
|
||||||
|
{
|
||||||
|
CoreUtils.GetBytesFromObject(arg, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
Flags = (CustomEventFlags)m.ReadByte();
|
||||||
|
Hash = m.ReadInt32();
|
||||||
|
Args = new object[m.ReadInt32()];
|
||||||
|
for (int i = 0; i < Args.Length; i++)
|
||||||
|
{
|
||||||
|
byte type = m.ReadByte();
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case 0x01:
|
||||||
|
Args[i] = m.ReadByte(); break;
|
||||||
|
case 0x02:
|
||||||
|
Args[i] = m.ReadInt32(); break;
|
||||||
|
case 0x03:
|
||||||
|
Args[i] = m.ReadUInt16(); break;
|
||||||
|
case 0x04:
|
||||||
|
Args[i] = m.ReadInt32(); break;
|
||||||
|
case 0x05:
|
||||||
|
Args[i] = m.ReadUInt32(); break;
|
||||||
|
case 0x06:
|
||||||
|
Args[i] = m.ReadInt64(); break;
|
||||||
|
case 0x07:
|
||||||
|
Args[i] = m.ReadUInt64(); break;
|
||||||
|
case 0x08:
|
||||||
|
Args[i] = m.ReadFloat(); break;
|
||||||
|
case 0x09:
|
||||||
|
Args[i] = m.ReadBoolean(); break;
|
||||||
|
case 0x10:
|
||||||
|
Args[i] = m.ReadString(); break;
|
||||||
|
case 0x11:
|
||||||
|
Args[i] = m.ReadVector3(); break;
|
||||||
|
case 0x12:
|
||||||
|
Args[i] = m.ReadQuaternion(); break;
|
||||||
|
case 0x13:
|
||||||
|
Args[i] = (GTA.Model)m.ReadInt32(); break;
|
||||||
|
case 0x14:
|
||||||
|
Args[i] = m.ReadVector2(); break;
|
||||||
|
case 0x15:
|
||||||
|
Args[i] = m.ReadByteArray(); break;
|
||||||
|
default:
|
||||||
|
if (ResolveHandle == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Unexpected type: {type}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Args[i] = ResolveHandle(type, m); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
127
Core/Packets/FilePackets.cs
Normal file
127
Core/Packets/FilePackets.cs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
|
||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal enum FileResponse : byte
|
||||||
|
{
|
||||||
|
NeedToDownload = 0,
|
||||||
|
AlreadyExists = 1,
|
||||||
|
Completed = 2,
|
||||||
|
Loaded = 3,
|
||||||
|
LoadFailed = 4,
|
||||||
|
}
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
internal class FileTransferRequest : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.FileTransferRequest;
|
||||||
|
public int ID { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public long FileLength { get; set; }
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// The ID from the download
|
||||||
|
m.Write(ID);
|
||||||
|
|
||||||
|
|
||||||
|
// The name of the file
|
||||||
|
m.Write(Name);
|
||||||
|
|
||||||
|
// The length of the file
|
||||||
|
m.Write(FileLength);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
ID = m.ReadInt32();
|
||||||
|
Name = m.ReadString();
|
||||||
|
FileLength = m.ReadInt64();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class FileTransferResponse : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.FileTransferResponse;
|
||||||
|
public int ID { get; set; }
|
||||||
|
public FileResponse Response { get; set; }
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
// The ID from the download
|
||||||
|
m.Write(ID);
|
||||||
|
|
||||||
|
m.Write((byte)Response);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
ID = m.ReadInt32();
|
||||||
|
Response = (FileResponse)m.ReadByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class FileTransferChunk : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.FileTransferChunk;
|
||||||
|
public int ID { get; set; }
|
||||||
|
|
||||||
|
public byte[] FileChunk { get; set; }
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// The ID from the download
|
||||||
|
m.Write(ID);
|
||||||
|
m.WriteByteArray(FileChunk);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
ID = m.ReadInt32();
|
||||||
|
FileChunk = m.ReadByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class FileTransferComplete : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.FileTransferComplete;
|
||||||
|
public int ID { get; set; }
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// The ID for the download
|
||||||
|
m.Write(ID);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
ID = m.ReadInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal class AllResourcesSent : Packet
|
||||||
|
{
|
||||||
|
|
||||||
|
public override PacketType Type => PacketType.AllResourcesSent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
Core/Packets/HolePunch.cs
Normal file
67
Core/Packets/HolePunch.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class HolePunchInit : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.HolePunchInit;
|
||||||
|
public int TargetID { get; set; }
|
||||||
|
public string TargetInternal { get; set; }
|
||||||
|
public string TargetExternal { get; set; }
|
||||||
|
public bool Connect { get; set; }
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
m.Write(TargetID);
|
||||||
|
m.Write(TargetInternal);
|
||||||
|
m.Write(TargetExternal);
|
||||||
|
m.Write(Connect);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
TargetID = m.ReadInt32();
|
||||||
|
TargetInternal = m.ReadString();
|
||||||
|
TargetExternal = m.ReadString();
|
||||||
|
Connect = m.ReadBoolean();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal class HolePunch : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.HolePunch;
|
||||||
|
public int Puncher { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1:initial, 2:acknowledged, 3:confirmed
|
||||||
|
/// </summary>
|
||||||
|
public byte Status { get; set; }
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
m.Write(Puncher);
|
||||||
|
m.Write(Status);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
Puncher = m.ReadInt32();
|
||||||
|
Status = m.ReadByte();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using Lidgren.Network;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
@ -12,16 +12,15 @@ namespace RageCoop.Core
|
|||||||
{
|
{
|
||||||
public int TargetID { get; set; }
|
public int TargetID { get; set; }
|
||||||
public override PacketType Type => PacketType.ConnectionRequest;
|
public override PacketType Type => PacketType.ConnectionRequest;
|
||||||
public override byte[] Serialize()
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
{
|
{
|
||||||
var data = new List<byte>(10);
|
var data = new List<byte>(10);
|
||||||
data.AddInt(TargetID);
|
m.Write(TargetID);
|
||||||
return data.ToArray();
|
|
||||||
}
|
}
|
||||||
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 int ID { get; set; }
|
||||||
public override PacketType Type => PacketType.P2PConnect;
|
public override PacketType Type => PacketType.P2PConnect;
|
||||||
public override byte[] Serialize()
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
{
|
{
|
||||||
var data = new List<byte>(10);
|
var data = new List<byte>(10);
|
||||||
data.AddInt(ID);
|
m.Write(ID);
|
||||||
return data.ToArray();
|
|
||||||
}
|
}
|
||||||
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 Lidgren.Network;
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
using System.Text;
|
|
||||||
using Lidgren.Network;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using GTA.Math;
|
|
||||||
|
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
{
|
{
|
||||||
@ -28,7 +24,6 @@ namespace RageCoop.Core
|
|||||||
AllResourcesSent = 15,
|
AllResourcesSent = 15,
|
||||||
|
|
||||||
CustomEvent = 16,
|
CustomEvent = 16,
|
||||||
CustomEventQueued = 17,
|
|
||||||
|
|
||||||
ConnectionRequest = 18,
|
ConnectionRequest = 18,
|
||||||
P2PConnect = 19,
|
P2PConnect = 19,
|
||||||
@ -55,14 +50,6 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
Unknown = 255
|
Unknown = 255
|
||||||
}
|
}
|
||||||
internal static class PacketExtensions
|
|
||||||
{
|
|
||||||
internal static bool IsSyncEvent(this PacketType p)
|
|
||||||
{
|
|
||||||
return (30<=(byte)p)&&((byte)p<=40);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal enum ConnectionChannel
|
internal enum ConnectionChannel
|
||||||
{
|
{
|
||||||
Default = 0,
|
Default = 0,
|
||||||
@ -98,6 +85,7 @@ namespace RageCoop.Core
|
|||||||
IsInLowCover = 1 << 11,
|
IsInLowCover = 1 << 11,
|
||||||
IsInCoverFacingLeft = 1 << 12,
|
IsInCoverFacingLeft = 1 << 12,
|
||||||
IsBlindFiring = 1 << 13,
|
IsBlindFiring = 1 << 13,
|
||||||
|
IsInvincible = 1 << 14,
|
||||||
IsFullSync = 1 << 15,
|
IsFullSync = 1 << 15,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,25 +140,19 @@ namespace RageCoop.Core
|
|||||||
internal interface IPacket
|
internal interface IPacket
|
||||||
{
|
{
|
||||||
PacketType Type { get; }
|
PacketType Type { get; }
|
||||||
byte[] Serialize();
|
|
||||||
|
|
||||||
void Deserialize(byte[] data);
|
void Deserialize(NetIncomingMessage m);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class Packet : IPacket
|
internal abstract class Packet : IPacket
|
||||||
{
|
{
|
||||||
public abstract PacketType Type { get; }
|
public abstract PacketType Type { get; }
|
||||||
public virtual byte[] Serialize()
|
public void Pack(NetOutgoingMessage m)
|
||||||
{
|
{
|
||||||
return new byte[0];
|
m.Write((byte)Type);
|
||||||
}
|
Serialize(m);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
protected virtual void Serialize(NetOutgoingMessage m) { }
|
||||||
|
public virtual void Deserialize(NetIncomingMessage m) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,9 +1,7 @@
|
|||||||
using System;
|
using GTA;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using GTA;
|
|
||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
{
|
{
|
||||||
@ -61,92 +59,92 @@ namespace RageCoop.Core
|
|||||||
public float BlipScale { get; set; } = 1;
|
public float BlipScale { get; set; } = 1;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public override byte[] Serialize()
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
{
|
{
|
||||||
|
|
||||||
List<byte> byteArray = new List<byte>();
|
|
||||||
byteArray.AddInt(ID);
|
m.Write(ID);
|
||||||
byteArray.AddInt(OwnerID);
|
m.Write(OwnerID);
|
||||||
byteArray.AddRange(BitConverter.GetBytes((ushort)Flags));
|
m.Write((ushort)Flags);
|
||||||
byteArray.AddRange(BitConverter.GetBytes(Health));
|
m.Write(Health);
|
||||||
byteArray.Add(Speed);
|
m.Write(Speed);
|
||||||
if (Flags.HasPedFlag(PedDataFlags.IsRagdoll))
|
if (Flags.HasPedFlag(PedDataFlags.IsRagdoll))
|
||||||
{
|
{
|
||||||
byteArray.AddVector3(HeadPosition);
|
m.Write(HeadPosition);
|
||||||
byteArray.AddVector3(RightFootPosition);
|
m.Write(RightFootPosition);
|
||||||
byteArray.AddVector3(LeftFootPosition);
|
m.Write(LeftFootPosition);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Speed >= 4)
|
if (Speed >= 4)
|
||||||
{
|
{
|
||||||
byteArray.AddInt(VehicleID);
|
m.Write(VehicleID);
|
||||||
byteArray.Add((byte)(Seat+3));
|
m.Write((byte)(Seat + 3));
|
||||||
}
|
}
|
||||||
byteArray.AddVector3(Position);
|
m.Write(Position);
|
||||||
}
|
}
|
||||||
byteArray.AddVector3(Rotation);
|
m.Write(Rotation);
|
||||||
byteArray.AddVector3(Velocity);
|
m.Write(Velocity);
|
||||||
|
|
||||||
|
|
||||||
if (Flags.HasPedFlag(PedDataFlags.IsAiming))
|
if (Flags.HasPedFlag(PedDataFlags.IsAiming))
|
||||||
{
|
{
|
||||||
byteArray.AddVector3(AimCoords);
|
m.Write(AimCoords);
|
||||||
}
|
}
|
||||||
|
|
||||||
byteArray.AddFloat(Heading);
|
m.Write(Heading);
|
||||||
|
|
||||||
if (Flags.HasPedFlag(PedDataFlags.IsFullSync))
|
if (Flags.HasPedFlag(PedDataFlags.IsFullSync))
|
||||||
{
|
{
|
||||||
byteArray.AddInt(ModelHash);
|
m.Write(ModelHash);
|
||||||
byteArray.AddUint(CurrentWeaponHash);
|
m.Write(CurrentWeaponHash);
|
||||||
byteArray.AddRange(Clothes);
|
m.Write(Clothes);
|
||||||
if (WeaponComponents != null)
|
if (WeaponComponents != null)
|
||||||
{
|
{
|
||||||
byteArray.Add(0x01);
|
m.Write(true);
|
||||||
byteArray.AddRange(BitConverter.GetBytes((ushort)WeaponComponents.Count));
|
m.Write((ushort)WeaponComponents.Count);
|
||||||
foreach (KeyValuePair<uint, bool> component in WeaponComponents)
|
foreach (KeyValuePair<uint, bool> component in WeaponComponents)
|
||||||
{
|
{
|
||||||
byteArray.AddRange(BitConverter.GetBytes(component.Key));
|
m.Write(component.Key);
|
||||||
byteArray.AddRange(BitConverter.GetBytes(component.Value));
|
m.Write(component.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Player weapon doesn't have any components
|
// 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)
|
if ((byte)BlipColor != 255)
|
||||||
{
|
{
|
||||||
byteArray.AddUshort((ushort)BlipSprite);
|
m.Write((ushort)BlipSprite);
|
||||||
byteArray.AddFloat(BlipScale);
|
m.Write(BlipScale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return byteArray.ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Deserialize(byte[] array)
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
{
|
{
|
||||||
#region NetIncomingMessageToPacket
|
#region NetIncomingMessageToPacket
|
||||||
BitReader reader = new BitReader(array);
|
|
||||||
|
|
||||||
ID = reader.ReadInt32();
|
|
||||||
OwnerID=reader.ReadInt32();
|
ID = m.ReadInt32();
|
||||||
Flags = (PedDataFlags)reader.ReadUInt16();
|
OwnerID = m.ReadInt32();
|
||||||
Health = reader.ReadInt32();
|
Flags = (PedDataFlags)m.ReadUInt16();
|
||||||
Speed = reader.ReadByte();
|
Health = m.ReadInt32();
|
||||||
|
Speed = m.ReadByte();
|
||||||
|
|
||||||
if (Flags.HasPedFlag(PedDataFlags.IsRagdoll))
|
if (Flags.HasPedFlag(PedDataFlags.IsRagdoll))
|
||||||
{
|
{
|
||||||
HeadPosition=reader.ReadVector3();
|
HeadPosition = m.ReadVector3();
|
||||||
RightFootPosition=reader.ReadVector3();
|
RightFootPosition = m.ReadVector3();
|
||||||
LeftFootPosition=reader.ReadVector3();
|
LeftFootPosition = m.ReadVector3();
|
||||||
Position = HeadPosition;
|
Position = HeadPosition;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -154,54 +152,54 @@ namespace RageCoop.Core
|
|||||||
// Vehicle related
|
// Vehicle related
|
||||||
if (Speed >= 4)
|
if (Speed >= 4)
|
||||||
{
|
{
|
||||||
VehicleID=reader.ReadInt32();
|
VehicleID = m.ReadInt32();
|
||||||
Seat=(VehicleSeat)(reader.ReadByte()-3);
|
Seat = (VehicleSeat)(m.ReadByte() - 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read player position
|
// Read player position
|
||||||
Position = reader.ReadVector3();
|
Position = m.ReadVector3();
|
||||||
}
|
}
|
||||||
|
|
||||||
Rotation = reader.ReadVector3();
|
Rotation = m.ReadVector3();
|
||||||
Velocity = reader.ReadVector3();
|
Velocity = m.ReadVector3();
|
||||||
|
|
||||||
if (Flags.HasPedFlag(PedDataFlags.IsAiming))
|
if (Flags.HasPedFlag(PedDataFlags.IsAiming))
|
||||||
{
|
{
|
||||||
// Read player aim coords
|
// Read player aim coords
|
||||||
AimCoords = reader.ReadVector3();
|
AimCoords = m.ReadVector3();
|
||||||
}
|
}
|
||||||
|
|
||||||
Heading=reader.ReadSingle();
|
Heading = m.ReadFloat();
|
||||||
|
|
||||||
if (Flags.HasPedFlag(PedDataFlags.IsFullSync))
|
if (Flags.HasPedFlag(PedDataFlags.IsFullSync))
|
||||||
{
|
{
|
||||||
// Read player model hash
|
// Read player model hash
|
||||||
ModelHash = reader.ReadInt32();
|
ModelHash = m.ReadInt32();
|
||||||
|
|
||||||
// Read player weapon hash
|
// Read player weapon hash
|
||||||
CurrentWeaponHash = reader.ReadUInt32();
|
CurrentWeaponHash = m.ReadUInt32();
|
||||||
|
|
||||||
// Read player clothes
|
// Read player clothes
|
||||||
Clothes =reader.ReadBytes(36);
|
Clothes = m.ReadBytes(36);
|
||||||
|
|
||||||
// Read player weapon components
|
// Read player weapon components
|
||||||
if (reader.ReadBoolean())
|
if (m.ReadBoolean())
|
||||||
{
|
{
|
||||||
WeaponComponents = new Dictionary<uint, bool>();
|
WeaponComponents = new Dictionary<uint, bool>();
|
||||||
ushort comCount = reader.ReadUInt16();
|
ushort comCount = m.ReadUInt16();
|
||||||
for (ushort i = 0; i < comCount; i++)
|
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)
|
if ((byte)BlipColor != 255)
|
||||||
{
|
{
|
||||||
BlipSprite=(BlipSprite)reader.ReadUInt16();
|
BlipSprite = (BlipSprite)m.ReadUInt16();
|
||||||
BlipScale=reader.ReadSingle();
|
BlipScale = m.ReadFloat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
249
Core/Packets/PlayerPackets.cs
Normal file
249
Core/Packets/PlayerPackets.cs
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
using GTA.Math;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
internal struct PlayerData
|
||||||
|
{
|
||||||
|
public int ID;
|
||||||
|
public string Username;
|
||||||
|
}
|
||||||
|
public class Handshake : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.Handshake;
|
||||||
|
public int PedID { get; set; }
|
||||||
|
|
||||||
|
public string Username { get; set; }
|
||||||
|
|
||||||
|
public string ModVersion { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The asymetrically crypted Aes key
|
||||||
|
/// </summary>
|
||||||
|
public byte[] AesKeyCrypted;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The asymetrically crypted Aes IV
|
||||||
|
/// </summary>
|
||||||
|
public byte[] AesIVCrypted;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The password hash with client Aes
|
||||||
|
/// </summary>
|
||||||
|
public byte[] PasswordEncrypted { get; set; }
|
||||||
|
|
||||||
|
public IPEndPoint InternalEndPoint { get; set; }
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Write Player Ped ID
|
||||||
|
m.Write(PedID);
|
||||||
|
|
||||||
|
// Write Username
|
||||||
|
m.Write(Username);
|
||||||
|
|
||||||
|
// Write ModVersion
|
||||||
|
m.Write(ModVersion);
|
||||||
|
|
||||||
|
m.Write(InternalEndPoint.ToString());
|
||||||
|
|
||||||
|
// Write AesKeyCrypted
|
||||||
|
m.WriteByteArray(AesKeyCrypted);
|
||||||
|
|
||||||
|
// Write AesIVCrypted
|
||||||
|
m.WriteByteArray(AesIVCrypted);
|
||||||
|
|
||||||
|
|
||||||
|
// Write PassHash
|
||||||
|
m.WriteByteArray(PasswordEncrypted);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
|
||||||
|
// Read player netHandle
|
||||||
|
PedID = m.ReadInt32();
|
||||||
|
|
||||||
|
// Read Username
|
||||||
|
Username = m.ReadString();
|
||||||
|
|
||||||
|
// Read ModVersion
|
||||||
|
ModVersion = m.ReadString();
|
||||||
|
|
||||||
|
InternalEndPoint = CoreUtils.StringToEndPoint(m.ReadString());
|
||||||
|
|
||||||
|
AesKeyCrypted = m.ReadByteArray();
|
||||||
|
|
||||||
|
AesIVCrypted = m.ReadByteArray();
|
||||||
|
|
||||||
|
|
||||||
|
PasswordEncrypted = m.ReadByteArray();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class HandshakeSuccess : Packet
|
||||||
|
{
|
||||||
|
public PlayerData[] Players { get; set; }
|
||||||
|
public override PacketType Type => PacketType.HandshakeSuccess;
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
m.Write(Players.Length);
|
||||||
|
foreach (var p in Players)
|
||||||
|
{
|
||||||
|
m.Write(p.ID);
|
||||||
|
m.Write(p.Username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
Players = new PlayerData[m.ReadInt32()];
|
||||||
|
for (int i = 0; i < Players.Length; i++)
|
||||||
|
{
|
||||||
|
Players[i] = new PlayerData()
|
||||||
|
{
|
||||||
|
ID = m.ReadInt32(),
|
||||||
|
Username = m.ReadString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class PlayerConnect : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.PlayerConnect;
|
||||||
|
public int PedID { get; set; }
|
||||||
|
|
||||||
|
public string Username { get; set; }
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Write NetHandle
|
||||||
|
m.Write(PedID);
|
||||||
|
|
||||||
|
m.Write(Username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
// Read player netHandle
|
||||||
|
PedID = m.ReadInt32();
|
||||||
|
|
||||||
|
// Read Username
|
||||||
|
Username = m.ReadString();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlayerDisconnect : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.PlayerDisconnect;
|
||||||
|
public int PedID { get; set; }
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
m.Write(PedID);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
PedID = m.ReadInt32();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class PlayerInfoUpdate : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.PlayerInfoUpdate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ped ID for this Player
|
||||||
|
/// </summary>
|
||||||
|
public int PedID { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
public float Latency { get; set; }
|
||||||
|
public Vector3 Position { get; set; }
|
||||||
|
public bool IsHost;
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Write ID
|
||||||
|
m.Write(PedID);
|
||||||
|
|
||||||
|
// Write Username
|
||||||
|
m.Write(Username);
|
||||||
|
|
||||||
|
// Write Latency
|
||||||
|
m.Write(Latency);
|
||||||
|
|
||||||
|
m.Write(Position);
|
||||||
|
|
||||||
|
m.Write(IsHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// Read player ID
|
||||||
|
PedID = m.ReadInt32();
|
||||||
|
|
||||||
|
// Read Username
|
||||||
|
Username = m.ReadString();
|
||||||
|
|
||||||
|
Latency = m.ReadFloat();
|
||||||
|
|
||||||
|
Position = m.ReadVector3();
|
||||||
|
|
||||||
|
IsHost = m.ReadBoolean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PublicKeyResponse : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.PublicKeyResponse;
|
||||||
|
|
||||||
|
public byte[] Modulus;
|
||||||
|
public byte[] Exponent;
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
m.WriteByteArray(Modulus);
|
||||||
|
|
||||||
|
m.WriteByteArray(Exponent);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
Modulus = m.ReadByteArray();
|
||||||
|
Exponent = m.ReadByteArray();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PublicKeyRequest : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.PublicKeyRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
Core/Packets/ProjectileSync.cs
Normal file
82
Core/Packets/ProjectileSync.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using GTA.Math;
|
||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
internal class ProjectileSync : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.ProjectileSync;
|
||||||
|
public int ID { get; set; }
|
||||||
|
|
||||||
|
public int ShooterID { get; set; }
|
||||||
|
public uint WeaponHash { get; set; }
|
||||||
|
|
||||||
|
public Vector3 Position { get; set; }
|
||||||
|
|
||||||
|
public Vector3 Rotation { get; set; }
|
||||||
|
|
||||||
|
public Vector3 Velocity { get; set; }
|
||||||
|
|
||||||
|
public ProjectileDataFlags Flags { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Write id
|
||||||
|
m.Write(ID);
|
||||||
|
|
||||||
|
// Write ShooterID
|
||||||
|
m.Write(ShooterID);
|
||||||
|
|
||||||
|
m.Write(WeaponHash);
|
||||||
|
|
||||||
|
// Write position
|
||||||
|
m.Write(Position);
|
||||||
|
|
||||||
|
|
||||||
|
// Write rotation
|
||||||
|
m.Write(Rotation);
|
||||||
|
|
||||||
|
// Write velocity
|
||||||
|
m.Write(Velocity);
|
||||||
|
m.Write((byte)Flags);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
|
||||||
|
// Read id
|
||||||
|
ID = m.ReadInt32();
|
||||||
|
|
||||||
|
// Read ShooterID
|
||||||
|
ShooterID = m.ReadInt32();
|
||||||
|
|
||||||
|
WeaponHash = m.ReadUInt32();
|
||||||
|
|
||||||
|
// Read position
|
||||||
|
Position = m.ReadVector3();
|
||||||
|
|
||||||
|
// Read rotation
|
||||||
|
Rotation = m.ReadVector3();
|
||||||
|
|
||||||
|
// Read velocity
|
||||||
|
Velocity = m.ReadVector3();
|
||||||
|
|
||||||
|
Flags = (ProjectileDataFlags)m.ReadByte();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
Core/Packets/SyncEvents/BulletShot.cs
Normal file
65
Core/Packets/SyncEvents/BulletShot.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
using GTA.Math;
|
||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class BulletShot : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.BulletShot;
|
||||||
|
public int OwnerID { get; set; }
|
||||||
|
|
||||||
|
public uint WeaponHash { get; set; }
|
||||||
|
|
||||||
|
public Vector3 StartPosition { get; set; }
|
||||||
|
public Vector3 EndPosition { get; set; }
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Write OwnerID
|
||||||
|
m.Write(OwnerID);
|
||||||
|
|
||||||
|
// Write weapon hash
|
||||||
|
m.Write(WeaponHash);
|
||||||
|
|
||||||
|
// Write StartPosition
|
||||||
|
m.Write(StartPosition);
|
||||||
|
|
||||||
|
// Write EndPosition
|
||||||
|
m.Write(EndPosition);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
|
||||||
|
// Read OwnerID
|
||||||
|
OwnerID = m.ReadInt32();
|
||||||
|
|
||||||
|
// Read WeponHash
|
||||||
|
WeaponHash = m.ReadUInt32();
|
||||||
|
|
||||||
|
// Read StartPosition
|
||||||
|
StartPosition = m.ReadVector3();
|
||||||
|
|
||||||
|
// Read EndPosition
|
||||||
|
EndPosition = m.ReadVector3();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
42
Core/Packets/SyncEvents/NozzleTransform.cs
Normal file
42
Core/Packets/SyncEvents/NozzleTransform.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
internal class NozzleTransform : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.NozzleTransform;
|
||||||
|
public int VehicleID { get; set; }
|
||||||
|
|
||||||
|
public bool Hover { get; set; }
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
m.Write(VehicleID);
|
||||||
|
m.Write(Hover);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
VehicleID = m.ReadInt32();
|
||||||
|
Hover = m.ReadBoolean();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
38
Core/Packets/SyncEvents/OwnerChanged.cs
Normal file
38
Core/Packets/SyncEvents/OwnerChanged.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class OwnerChanged : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.OwnerChanged;
|
||||||
|
public int ID { get; set; }
|
||||||
|
|
||||||
|
public int NewOwnerID { get; set; }
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
m.Write(ID);
|
||||||
|
m.Write(NewOwnerID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
|
||||||
|
ID = m.ReadInt32();
|
||||||
|
NewOwnerID = m.ReadInt32();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
39
Core/Packets/SyncEvents/PedKilled.cs
Normal file
39
Core/Packets/SyncEvents/PedKilled.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class PedKilled : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.PedKilled;
|
||||||
|
public int VictimID { get; set; }
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
m.Write(VictimID);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
|
||||||
|
VictimID = m.ReadInt32();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
52
Core/Packets/SyncEvents/VehicleBulletShot.cs
Normal file
52
Core/Packets/SyncEvents/VehicleBulletShot.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using GTA.Math;
|
||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class VehicleBulletShot : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.VehicleBulletShot;
|
||||||
|
public int OwnerID { get; set; }
|
||||||
|
public ushort Bone { get; set; }
|
||||||
|
public uint WeaponHash { get; set; }
|
||||||
|
|
||||||
|
public Vector3 StartPosition { get; set; }
|
||||||
|
public Vector3 EndPosition { get; set; }
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
m.Write(OwnerID);
|
||||||
|
m.Write(Bone);
|
||||||
|
m.Write(WeaponHash);
|
||||||
|
m.Write(StartPosition);
|
||||||
|
m.Write(EndPosition);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
|
||||||
|
OwnerID = m.ReadInt32();
|
||||||
|
Bone = m.ReadUInt16();
|
||||||
|
WeaponHash = m.ReadUInt32();
|
||||||
|
StartPosition = m.ReadVector3();
|
||||||
|
EndPosition = m.ReadVector3();
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
227
Core/Packets/VehicleSync.cs
Normal file
227
Core/Packets/VehicleSync.cs
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
using GTA;
|
||||||
|
using GTA.Math;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
|
||||||
|
public class VehicleSync : Packet
|
||||||
|
{
|
||||||
|
public override PacketType Type => PacketType.VehicleSync;
|
||||||
|
public int ID { get; set; }
|
||||||
|
|
||||||
|
public int OwnerID { get; set; }
|
||||||
|
|
||||||
|
public VehicleDataFlags Flags { get; set; }
|
||||||
|
|
||||||
|
public Vector3 Position { get; set; }
|
||||||
|
|
||||||
|
public Quaternion Quaternion { get; set; }
|
||||||
|
// public Vector3 Rotation { get; set; }
|
||||||
|
|
||||||
|
public Vector3 Velocity { get; set; }
|
||||||
|
|
||||||
|
public Vector3 RotationVelocity { get; set; }
|
||||||
|
|
||||||
|
public float ThrottlePower { get; set; }
|
||||||
|
public float BrakePower { get; set; }
|
||||||
|
public float SteeringAngle { get; set; }
|
||||||
|
public float DeluxoWingRatio { get; set; } = -1;
|
||||||
|
|
||||||
|
#region FULL-SYNC
|
||||||
|
public int ModelHash { get; set; }
|
||||||
|
|
||||||
|
public float EngineHealth { get; set; }
|
||||||
|
|
||||||
|
public byte[] Colors { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<int, int> Mods { get; set; }
|
||||||
|
|
||||||
|
public VehicleDamageModel DamageModel { get; set; }
|
||||||
|
|
||||||
|
public byte LandingGear { get; set; }
|
||||||
|
public byte RoofState { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public VehicleLockStatus LockStatus { get; set; }
|
||||||
|
|
||||||
|
public int Livery { get; set; } = -1;
|
||||||
|
|
||||||
|
public byte RadioStation { get; set; } = 255;
|
||||||
|
public string LicensePlate { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
m.Write(DeluxoWingRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Flags.HasVehFlag(VehicleDataFlags.IsFullSync))
|
||||||
|
{
|
||||||
|
m.Write(ModelHash);
|
||||||
|
m.Write(EngineHealth);
|
||||||
|
|
||||||
|
// Check
|
||||||
|
if (Flags.HasVehFlag(VehicleDataFlags.IsAircraft))
|
||||||
|
{
|
||||||
|
// Write the vehicle landing gear
|
||||||
|
m.Write(LandingGear);
|
||||||
|
}
|
||||||
|
if (Flags.HasVehFlag(VehicleDataFlags.HasRoof))
|
||||||
|
{
|
||||||
|
m.Write(RoofState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write vehicle colors
|
||||||
|
m.Write(Colors[0]);
|
||||||
|
m.Write(Colors[1]);
|
||||||
|
|
||||||
|
// Write vehicle mods
|
||||||
|
// Write the count of mods
|
||||||
|
m.Write((short)Mods.Count);
|
||||||
|
// Loop the dictionary and add the values
|
||||||
|
foreach (KeyValuePair<int, int> mod in Mods)
|
||||||
|
{
|
||||||
|
// Write the mod value
|
||||||
|
m.Write(mod.Key);
|
||||||
|
m.Write(mod.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DamageModel.Equals(default(VehicleDamageModel)))
|
||||||
|
{
|
||||||
|
// Write boolean = true
|
||||||
|
m.Write(true);
|
||||||
|
// Write vehicle damage model
|
||||||
|
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
|
||||||
|
m.Write(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write LockStatus
|
||||||
|
m.Write((byte)LockStatus);
|
||||||
|
|
||||||
|
// Write RadioStation
|
||||||
|
m.Write(RadioStation);
|
||||||
|
|
||||||
|
// Write LicensePlate
|
||||||
|
m.Write(LicensePlate);
|
||||||
|
|
||||||
|
m.Write((byte)(Livery + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
#region NetIncomingMessageToPacket
|
||||||
|
|
||||||
|
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 = m.ReadFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Flags.HasVehFlag(VehicleDataFlags.IsFullSync))
|
||||||
|
{
|
||||||
|
// Read vehicle model hash
|
||||||
|
ModelHash = m.ReadInt32();
|
||||||
|
|
||||||
|
// Read vehicle engine health
|
||||||
|
EngineHealth = m.ReadFloat();
|
||||||
|
|
||||||
|
|
||||||
|
// Check
|
||||||
|
if (Flags.HasVehFlag(VehicleDataFlags.IsAircraft))
|
||||||
|
{
|
||||||
|
// Read vehicle landing gear
|
||||||
|
LandingGear = m.ReadByte();
|
||||||
|
}
|
||||||
|
if (Flags.HasVehFlag(VehicleDataFlags.HasRoof))
|
||||||
|
{
|
||||||
|
RoofState = m.ReadByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read vehicle colors
|
||||||
|
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 = m.ReadInt16();
|
||||||
|
// Loop
|
||||||
|
for (int i = 0; i < vehModCount; i++)
|
||||||
|
{
|
||||||
|
// Read the mod value
|
||||||
|
Mods.Add(m.ReadInt32(), m.ReadInt32());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m.ReadBoolean())
|
||||||
|
{
|
||||||
|
// Read vehicle damage model
|
||||||
|
DamageModel = new VehicleDamageModel()
|
||||||
|
{
|
||||||
|
BrokenDoors = m.ReadByte(),
|
||||||
|
OpenedDoors = m.ReadByte(),
|
||||||
|
BrokenWindows = m.ReadByte(),
|
||||||
|
BurstedTires = m.ReadInt16(),
|
||||||
|
LeftHeadLightBroken = m.ReadByte(),
|
||||||
|
RightHeadLightBroken = m.ReadByte()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Read LockStatus
|
||||||
|
LockStatus = (VehicleLockStatus)m.ReadByte();
|
||||||
|
|
||||||
|
// Read RadioStation
|
||||||
|
RadioStation = m.ReadByte();
|
||||||
|
|
||||||
|
LicensePlate = m.ReadString();
|
||||||
|
|
||||||
|
Livery = m.ReadByte() - 1;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
Core/Packets/Voice.cs
Normal file
29
Core/Packets/Voice.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using Lidgren.Network;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
internal partial class Packets
|
||||||
|
{
|
||||||
|
internal class Voice : Packet
|
||||||
|
{
|
||||||
|
public int ID { get; set; }
|
||||||
|
public byte[] Buffer { get; set; }
|
||||||
|
public int Recorded { get; set; }
|
||||||
|
public override PacketType Type => PacketType.Voice;
|
||||||
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
|
{
|
||||||
|
m.Write(ID);
|
||||||
|
m.Write(Buffer);
|
||||||
|
m.Write(Recorded);
|
||||||
|
|
||||||
|
}
|
||||||
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
|
{
|
||||||
|
|
||||||
|
ID = m.ReadInt32();
|
||||||
|
Buffer = m.ReadByteArray();
|
||||||
|
Recorded = m.ReadInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,14 @@
|
|||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
|
||||||
|
<NoWarn>1701;1702;1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
|
||||||
|
<NoWarn>1701;1702;1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Costura.Fody" Version="5.7.0">
|
<PackageReference Include="Costura.Fody" Version="5.7.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
@ -34,7 +42,8 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="6.0.8" />
|
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="6.0.8" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
|
<PackageReference Include="SharpZipLib" Version="1.4.0" />
|
||||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@ -42,9 +51,6 @@
|
|||||||
<Reference Include="Lidgren.Network">
|
<Reference Include="Lidgren.Network">
|
||||||
<HintPath>..\libs\Lidgren.Network.dll</HintPath>
|
<HintPath>..\libs\Lidgren.Network.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Newtonsoft.Json">
|
|
||||||
<HintPath>..\libs\Newtonsoft.Json.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="ScriptHookVDotNet3">
|
<Reference Include="ScriptHookVDotNet3">
|
||||||
<HintPath>..\libs\ScriptHookVDotNet3.dll</HintPath>
|
<HintPath>..\libs\ScriptHookVDotNet3.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
124
Core/Scripting/CustomEvents.cs
Normal file
124
Core/Scripting/CustomEvents.cs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace RageCoop.Core.Scripting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describes how the event should be sent or processed
|
||||||
|
/// </summary>
|
||||||
|
public enum CustomEventFlags : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Data will be encrypted and decrypted on target client
|
||||||
|
/// </summary>
|
||||||
|
Encrypted = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event will be queued and fired in script thread, specify this flag if your handler will call native functions.
|
||||||
|
/// </summary>
|
||||||
|
Queued = 2,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Struct to identify different event using hash
|
||||||
|
/// </summary>
|
||||||
|
public struct CustomEventHash
|
||||||
|
{
|
||||||
|
private static readonly MD5 Hasher = MD5.Create();
|
||||||
|
private static readonly Dictionary<int, string> Hashed = new Dictionary<int, string>();
|
||||||
|
/// <summary>
|
||||||
|
/// Hash value
|
||||||
|
/// </summary>
|
||||||
|
public int Hash;
|
||||||
|
/// <summary>
|
||||||
|
/// Create from hash
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hash"></param>
|
||||||
|
public static implicit operator CustomEventHash(int hash)
|
||||||
|
{
|
||||||
|
return new CustomEventHash() { Hash = hash };
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Create from string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
public static implicit operator CustomEventHash(string name)
|
||||||
|
{
|
||||||
|
return new CustomEventHash() { Hash = FromString(name) };
|
||||||
|
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Get a Int32 hash of a string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="ArgumentException">The exception is thrown when the name did not match a previously computed one and the hash was the same.</exception>
|
||||||
|
public static int FromString(string s)
|
||||||
|
{
|
||||||
|
var hash = BitConverter.ToInt32(Hasher.ComputeHash(Encoding.UTF8.GetBytes(s)), 0);
|
||||||
|
lock (Hashed)
|
||||||
|
{
|
||||||
|
if (Hashed.TryGetValue(hash, out string name))
|
||||||
|
{
|
||||||
|
if (name != s)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Hashed value has collision with another name:{name}, hashed value:{hash}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hashed.Add(hash, s);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// To int
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="h"></param>
|
||||||
|
public static implicit operator int(CustomEventHash h)
|
||||||
|
{
|
||||||
|
return h.Hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public static class CustomEvents
|
||||||
|
{
|
||||||
|
internal static readonly CustomEventHash OnPlayerDied = "RageCoop.OnPlayerDied";
|
||||||
|
internal static readonly CustomEventHash SetWeather = "RageCoop.SetWeather";
|
||||||
|
internal static readonly CustomEventHash OnPedDeleted = "RageCoop.OnPedDeleted";
|
||||||
|
internal static readonly CustomEventHash OnVehicleDeleted = "RageCoop.OnVehicleDeleted";
|
||||||
|
internal static readonly CustomEventHash SetAutoRespawn = "RageCoop.SetAutoRespawn";
|
||||||
|
internal static readonly CustomEventHash SetDisplayNameTag = "RageCoop.SetDisplayNameTag";
|
||||||
|
internal static readonly CustomEventHash NativeCall = "RageCoop.NativeCall";
|
||||||
|
internal static readonly CustomEventHash NativeResponse = "RageCoop.NativeResponse";
|
||||||
|
internal static readonly CustomEventHash AllResourcesSent = "RageCoop.AllResourcesSent";
|
||||||
|
internal static readonly CustomEventHash ServerPropSync = "RageCoop.ServerPropSync";
|
||||||
|
internal static readonly CustomEventHash ServerBlipSync = "RageCoop.ServerBlipSync";
|
||||||
|
internal static readonly CustomEventHash SetEntity = "RageCoop.SetEntity";
|
||||||
|
internal static readonly CustomEventHash DeleteServerProp = "RageCoop.DeleteServerProp";
|
||||||
|
internal static readonly CustomEventHash UpdatePedBlip = "RageCoop.UpdatePedBlip";
|
||||||
|
internal static readonly CustomEventHash DeleteEntity = "RageCoop.DeleteEntity";
|
||||||
|
internal static readonly CustomEventHash DeleteServerBlip = "RageCoop.DeleteServerBlip";
|
||||||
|
internal static readonly CustomEventHash CreateVehicle = "RageCoop.CreateVehicle";
|
||||||
|
internal static readonly CustomEventHash WeatherTimeSync = "RageCoop.WeatherTimeSync";
|
||||||
|
internal static readonly CustomEventHash IsHost = "RageCoop.IsHost";
|
||||||
|
/// <summary>
|
||||||
|
/// Get event hash from string.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <remarks>This method is obsoete, you should use implicit operator or <see cref="CustomEventHash.FromString(string)"/></remarks>
|
||||||
|
[Obsolete]
|
||||||
|
public static int Hash(string s)
|
||||||
|
{
|
||||||
|
return CustomEventHash.FromString(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
Core/Scripting/ResourceFile.cs
Normal file
24
Core/Scripting/ResourceFile.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace RageCoop.Core.Scripting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class ResourceFile
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Full name with relative path of this file
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this is a directory
|
||||||
|
/// </summary>
|
||||||
|
public bool IsDirectory { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Get a stream that can be used to read file content.
|
||||||
|
/// </summary>
|
||||||
|
public Func<Stream> GetStream { get; internal set; }
|
||||||
|
}
|
||||||
|
}
|
86
Core/Worker.cs
Normal file
86
Core/Worker.cs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace RageCoop.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A worker that constantly execute jobs in a background thread.
|
||||||
|
/// </summary>
|
||||||
|
public class Worker : IDisposable
|
||||||
|
{
|
||||||
|
private readonly SemaphoreSlim _semaphoreSlim;
|
||||||
|
private readonly Thread _workerThread;
|
||||||
|
private bool _stopping = false;
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the worker
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this worker is busy executing job(s).
|
||||||
|
/// </summary>
|
||||||
|
public bool IsBusy { get; private set; }
|
||||||
|
internal Worker(string name, Logger logger, int maxJobs = Int32.MaxValue)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
_semaphoreSlim = new SemaphoreSlim(0, maxJobs);
|
||||||
|
_workerThread = new Thread(() =>
|
||||||
|
{
|
||||||
|
while (!_stopping)
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
_semaphoreSlim.Wait();
|
||||||
|
if (Jobs.TryDequeue(out var job))
|
||||||
|
{
|
||||||
|
IsBusy = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
job.Invoke();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error("Error occurred when executing queued job:");
|
||||||
|
logger.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Hmm... that's unexpected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IsBusy = false;
|
||||||
|
});
|
||||||
|
_workerThread.Start();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a job to be executed
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="work"></param>
|
||||||
|
public void QueueJob(Action work)
|
||||||
|
{
|
||||||
|
Jobs.Enqueue(work);
|
||||||
|
_semaphoreSlim.Release();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Finish current job and stop the worker.
|
||||||
|
/// </summary>
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
_stopping = true;
|
||||||
|
QueueJob(() => { });
|
||||||
|
if (_workerThread.IsAlive)
|
||||||
|
{
|
||||||
|
_workerThread.Join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Finish current job and stop the worker.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
_semaphoreSlim.Dispose();
|
||||||
|
}
|
||||||
|
private readonly ConcurrentQueue<Action> Jobs = new ConcurrentQueue<Action>();
|
||||||
|
}
|
||||||
|
}
|
43
README.md
43
README.md
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
# 🌐 RAGECOOP
|
# 🌐 RAGECOOP
|
||||||
|
|
||||||
[![Downloads][downloads-shield]][downloads-url]
|
[![Downloads][downloads-shield]][downloads-url]
|
||||||
[![Contributors][contributors-shield]][contributors-url]
|
[![Contributors][contributors-shield]][contributors-url]
|
||||||
[![Forks][forks-shield]][forks-url]
|
[![Forks][forks-shield]][forks-url]
|
||||||
@ -9,24 +10,37 @@
|
|||||||
|
|
||||||
|
|
||||||
# 🧠 That's it
|
# 🧠 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!
|
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
|
# 👁 Requirements
|
||||||
- Visual Studio 2022
|
- ScriptHookV
|
||||||
- .NET 6.0
|
- ScriptHookVDotNet 3.5.1 or later
|
||||||
- .NET Framework 4.8
|
- .NET Framework 4.8 Runtime or SDK
|
||||||
|
|
||||||
# 📚 Libraries
|
# 📋 Building the project
|
||||||
- [ScriptHookVDotNet3](https://github.com/crosire/scripthookvdotnet/releases/tag/v3.4.0)
|
|
||||||
- [LemonUI.SHVDN3](https://github.com/justalemon/LemonUI/releases/tag/v1.6)
|
You'll need:
|
||||||
- Lidgren Network Custom (***PRIVATE***)
|
- .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)
|
- - 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)
|
- [ClearScript](https://github.com/microsoft/ClearScript)
|
||||||
- [SharpZipLib](https://github.com/icsharpcode/SharpZipLib)
|
- [SharpZipLib](https://github.com/icsharpcode/SharpZipLib)
|
||||||
- [DotNetCorePlugins](https://github.com/natemcmaster/DotNetCorePlugins)
|
- [DotNetCorePlugins](https://github.com/natemcmaster/DotNetCorePlugins)
|
||||||
|
|
||||||
# Features
|
# 👋 Features
|
||||||
|
|
||||||
1. Synchronized bullets
|
1. Synchronized bullets
|
||||||
2. Synchronized vehicle/player/NPC
|
2. Synchronized vehicle/player/NPC
|
||||||
@ -37,15 +51,15 @@ RAGECOOP brings multiplayer experience to the story mode, you can complete missi
|
|||||||
7. Optimization for high-Ping condition, play with friends around the world!
|
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.online).
|
||||||
|
|
||||||
# Known issues
|
# ⚠ Known issues
|
||||||
|
|
||||||
See [Bugs](https://github.com/RAGECOOP/RAGECOOP-V/issues/33)
|
See [Bugs](https://github.com/RAGECOOP/RAGECOOP-V/issues/33)
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
# 🔫 Installation
|
||||||
Refer to the [wiki](https://github.com/RAGECOOP/RAGECOOP-V/wiki)
|
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)
|
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
|
# 🦆 Special thanks to
|
||||||
|
|
||||||
- [Makinolo](https://github.com/Makinolo), [oldnapalm](https://github.com/oldnapalm)
|
- [Makinolo](https://github.com/Makinolo), [oldnapalm](https://github.com/oldnapalm)
|
||||||
- - For testing, ideas, contributions and the first modification with the API
|
- - For testing, ideas, contributions and the first modification with the API
|
||||||
- [crosire](https://github.com/crosire)
|
- [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
|
- - For the extensive work in LemonUI
|
||||||
|
|
||||||
# 📝 License
|
# 📝 License
|
||||||
|
|
||||||
This project is licensed under [MIT license](https://github.com/RAGECOOP/RAGECOOP-V/blob/main/LICENSE)
|
This project is licensed under [MIT license](https://github.com/RAGECOOP/RAGECOOP-V/blob/main/LICENSE)
|
||||||
|
|
||||||
[downloads-shield]: https://img.shields.io/github/downloads/RAGECOOP/RAGECOOP-V/total?style=for-the-badge
|
[downloads-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-shield]: https://img.shields.io/github/issues/RAGECOOP/RAGECOOP-V.svg?style=for-the-badge
|
||||||
[issues-url]: https://github.com/RAGECOOP/RAGECOOP-V/issues
|
[issues-url]: https://github.com/RAGECOOP/RAGECOOP-V/issues
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,11 +3,17 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.0.31919.166
|
VisualStudioVersion = 17.0.31919.166
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Server", "RageCoop.Server\RageCoop.Server.csproj", "{84AB99D9-5E00-4CA2-B1DD-56B8419AAD24}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Server", "Server\RageCoop.Server.csproj", "{84AB99D9-5E00-4CA2-B1DD-56B8419AAD24}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Core", "RageCoop.Core\RageCoop.Core.csproj", "{CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Core", "Core\RageCoop.Core.csproj", "{CC2E8102-E568-4524-AA1F-F8E0F1CFE58A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RageCoop.Client", "RageCoop.Client\RageCoop.Client.csproj", "{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RageCoop.Client", "Client\Scripts\RageCoop.Client.csproj", "{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RageCoop.Client.Installer", "Client\Installer\RageCoop.Client.Installer.csproj", "{576D8610-0C28-4B60-BE2B-8657EA7CEE1B}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RageCoop.Client.Loader", "Client\Loader\RageCoop.Client.Loader.csproj", "{FC8CBDBB-6DC3-43AF-B34D-092E476410A5}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{531656CF-7269-488D-B042-741BC96C3941}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -41,10 +47,31 @@ Global
|
|||||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|Any CPU.Build.0 = Release|Any CPU
|
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|x64.ActiveCfg = Release|Any CPU
|
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}.Release|x64.Build.0 = 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
|
||||||
|
{FC8CBDBB-6DC3-43AF-B34D-092E476410A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FC8CBDBB-6DC3-43AF-B34D-092E476410A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FC8CBDBB-6DC3-43AF-B34D-092E476410A5}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{FC8CBDBB-6DC3-43AF-B34D-092E476410A5}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{FC8CBDBB-6DC3-43AF-B34D-092E476410A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FC8CBDBB-6DC3-43AF-B34D-092E476410A5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{FC8CBDBB-6DC3-43AF-B34D-092E476410A5}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{FC8CBDBB-6DC3-43AF-B34D-092E476410A5}.Release|x64.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{EF56D109-1F22-43E0-9DFF-CFCFB94E0681} = {531656CF-7269-488D-B042-741BC96C3941}
|
||||||
|
{576D8610-0C28-4B60-BE2B-8657EA7CEE1B} = {531656CF-7269-488D-B042-741BC96C3941}
|
||||||
|
{FC8CBDBB-6DC3-43AF-B34D-092E476410A5} = {531656CF-7269-488D-B042-741BC96C3941}
|
||||||
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {6CC7EA75-E4FF-4534-8EB6-0AEECF2620B7}
|
SolutionGuid = {6CC7EA75-E4FF-4534-8EB6-0AEECF2620B7}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user