55 Commits

Author SHA1 Message Date
39b780e518 Merge pull request #56 from RAGECOOP/dev-nightly 2023-10-23 10:48:52 -03:00
4a54851c51 Update AssemblyInfo.cs 2023-10-23 10:36:57 -03:00
f0eefa575c Always sync player ped 2023-10-22 18:59:19 -03:00
3fc813b2d8 Fix bug disconnecting from server 2023-10-22 17:14:50 -03:00
fbff72ff14 Update LemonUI 2023-10-18 16:57:19 -03:00
4e52407591 Update nightly-build.yaml 2023-10-18 16:56:44 -03:00
4e6fde129d Add global limits 2023-10-18 10:41:34 -03:00
92e1a970a8 Show kill notification 2023-10-06 23:46:08 -03:00
d0eb0b7818 Bump version
Add kill message
2023-10-06 16:36:49 -03:00
14151d7b2c Add option to disable blip and nametag display 2023-08-14 14:08:30 -03:00
1f8d70a520 Fix player dying when switching characters in missions 2023-08-13 19:29:48 -03:00
2cb5baf5f7 Fix player dying when switching characters 2023-08-09 23:50:47 -03:00
34e33937e2 Merge pull request #49 from RAGECOOP/dev-nightly
Update README.md
2023-07-26 15:46:58 -03:00
9287aba0f9 Update README.md 2023-07-26 15:42:08 -03:00
e88e903096 Merge pull request #48 from RAGECOOP/dev-nightly
Dev nightly
2023-07-26 15:27:40 -03:00
99642fd40c Update SHVDN 2023-07-26 15:12:58 -03:00
2fbf06b504 Use Lidgren.Network release build 2023-07-24 10:40:33 -03:00
13b771ec9f Fix exception entering vehicle as passenger 2023-07-24 10:39:37 -03:00
3b987f59e0 Remove update menu 2023-07-14 09:43:00 -03:00
de96f29097 Don't delete peds in vehicle 2023-07-14 09:39:06 -03:00
6136cbfc14 Allow multiple servers on same address
with different ports
2023-07-14 09:38:02 -03:00
ed145aedd6 Update master server 2023-07-14 09:36:49 -03:00
3f3b5fd2d0 Closes #40 2022-09-30 23:40:14 +08:00
9173e9a99e Fix non-ambient peds get deleted 2022-09-30 23:27:37 +08:00
6e64c458df Merge branch 'dev-nightly' of https://github.com/RAGECOOP/RAGECOOP-V into dev-nightly 2022-09-09 11:24:02 +08:00
76f959abe9 Stuff 2022-09-09 11:23:46 +08:00
f2e85d66ab Update build-test.yaml 2022-09-09 11:15:27 +08:00
e30ef1f4bd Update actions 2022-09-08 20:09:52 -07:00
6e8f6e78f6 Add build test action 2022-09-08 20:05:26 -07:00
f28c83ccbd Merge pull request #38 from RAGECOOP/dev-nightly
Bump to 1.5.4
2022-09-07 22:44:48 -07:00
a83821b3d2 Version bump 2022-09-08 13:19:09 -07:00
3b5436064e Don't announce if already present in master server 2022-09-08 13:15:34 -07:00
c4b321324e Filter out white space for reload key parsing 2022-09-08 12:59:14 -07:00
ba8d525ddf Merge pull request #37 from RAGECOOP/dev-nightly
Rewrite packet system
2022-09-07 21:45:14 -07:00
884e2f39f0 Yet another code cleanup 2022-09-08 12:41:56 -07:00
76c529f1d1 Rewrote packet system to reduce heap allocation 2022-09-08 12:37:06 -07:00
df0064bd38 Update nightly-build.yaml 2022-09-07 21:01:22 -07:00
f1fc96bbd7 Fix weird projectile shooting 2022-09-07 11:08:25 +08:00
23e9326f5f Fix stuff, add listening address display and projectile shoot prediction 2022-09-07 09:52:40 +08:00
4621fb4987 Some code cleanup and formatting 2022-09-06 21:46:35 +08:00
6c82895fa7 code cleaned up 2022-09-05 13:02:09 +02:00
84b040766f Simplify GetBytesFromObject 2022-08-27 14:23:28 +08:00
f44558cd3b Add some client API 2022-08-27 14:17:10 +08:00
accdbbcbc6 blah 2022-08-27 13:53:03 +08:00
2d4107f35e Fix traffic 2022-08-27 12:40:47 +08:00
bac53fd769 Load scripts from main assembly only 2022-08-26 22:58:03 +08:00
8f63fee5b5 Delete temp directory 2022-08-25 22:34:54 +08:00
8d0ad0b600 Show runtime information 2022-08-25 22:32:01 +08:00
dc08c0c1f6 Added support for loading runtime-specific libraries 2022-08-25 21:51:09 +08:00
faaa856aa5 Instructional buttons for popup 2022-08-25 00:58:21 +08:00
eab64f9254 Check fixed data every 100 frames 2022-08-24 22:38:50 +08:00
6c936cb8f9 Show help in popup 2022-08-24 19:26:40 +08:00
83a37f8556 blah 2022-08-24 18:48:21 +08:00
bb4eacce26 Don't disable traffic if not on server 2022-08-24 18:47:59 +08:00
d5b71db5d4 💩 2022-08-23 23:21:35 +08:00
109 changed files with 3395 additions and 3572 deletions

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

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

View File

@ -2,9 +2,7 @@ name: Nightly-build
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
branches: [ "dev-nightly" ]
jobs:
build:
@ -30,8 +28,6 @@ jobs:
run: dotnet publish RageCoop.Server/RageCoop.Server.csproj --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=false -r win-x64 -o bin/Release/Server/win-x64 -c Release
- name: Build server linux-x64
run: dotnet publish RageCoop.Server/RageCoop.Server.csproj --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=false -r linux-x64 -o bin/Release/Server/linux-x64 -c Release
- 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 bin/Release/Server/linux-arm -c Release
- uses: vimtor/action-zip@v1
with:
files: bin/Release/Client
@ -47,11 +43,6 @@ jobs:
files: bin/Release/Server/linux-x64
dest: RageCoop.Server-linux-x64.zip
- uses: vimtor/action-zip@v1
with:
files: bin/Release/Server/linux-arm
dest: RageCoop.Server-linux-arm.zip
- uses: WebFreak001/deploy-nightly@v1.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # automatically provided by github actions
@ -84,17 +75,3 @@ jobs:
asset_name: RageCoop.Server-linux-x64.zip
asset_content_type: application/zip
max_releases: 7
- uses: WebFreak001/deploy-nightly@v1.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # automatically provided by github actions
with:
upload_url: https://uploads.github.com/repos/RAGECOOP/RAGECOOP-V/releases/70603992/assets{?name,label}
release_id: 70603992
asset_path: RageCoop.Server-linux-arm.zip
asset_name: RageCoop.Server-linux-arm.zip
asset_content_type: application/zip
max_releases: 7
- uses: actions/checkout@v2

View File

@ -15,7 +15,7 @@ RAGECOOP brings multiplayer experience to the story mode, you can complete missi
# 👁 Requirements
- ScriptHookV
- ScriptHookVDotNet 3.5.1 or later
- ScriptHookVDotNet 3.6.0 or later
- .NET Framework 4.8 Runtime or SDK
# 📋 Building the project
@ -49,7 +49,7 @@ Then run `dotnet build` in the solution directory, built binaries are in the `bi
5. Decent compatibility with other mods, set up a private modded server to have some fun!
6. Weaponized vehicle sync(WIP).
7. Optimization for high-Ping condition, play with friends around the world!
8. Powerful scripting API and resource system, easily [add multiplayer functionality to your mod](HTTPS://docs.ragecoop.online).
8. Powerful scripting API and resource system, easily [add multiplayer functionality to your mod](HTTPS://docs.ragecoop.com).
# ⚠ Known issues

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows;
namespace RageCoop.Client.Installer
{

View File

@ -1,6 +1,6 @@
using System.Windows;
[assembly:ThemeInfo(
[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)

View File

@ -1,27 +1,17 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Diagnostics;
using System.Reflection;
using RageCoop.Core;
using System.Threading;
using System.Net;
using System.Windows.Forms;
using Path = System.IO.Path;
using System.Windows.Input;
using MessageBox = System.Windows.MessageBox;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
using Path = System.IO.Path;
using RageCoop.Core;
namespace RageCoop.Client.Installer
{
@ -41,11 +31,12 @@ namespace RageCoop.Client.Installer
var od = new OpenFileDialog()
{
Filter = "GTA 5 executable |GTA5.exe;PlayGTAV.exe",
Title="Select you GTAV executable"
Title = "Select you GTAV executable"
};
if (od.ShowDialog() ?? false == true)
{
Task.Run(() => {
Task.Run(() =>
{
try
{
Install(Directory.GetParent(od.FileName).FullName);
@ -62,7 +53,8 @@ namespace RageCoop.Client.Installer
Environment.Exit(0);
}
}
void Install(string root)
private void Install(string root)
{
UpdateStatus("Checking requirements");
var shvPath = Path.Combine(root, "ScriptHookV.dll");
@ -70,7 +62,7 @@ namespace RageCoop.Client.Installer
var scriptsPath = Path.Combine(root, "Scripts");
var lemonPath = Path.Combine(scriptsPath, "LemonUI.SHVDN3.dll");
var installPath = Path.Combine(scriptsPath, "RageCoop");
if(Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName == installPath)
if (Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName == installPath)
{
throw new InvalidOperationException("The installer is not meant to be run in the game folder, please extract the zip to somewhere else and run again.");
}
@ -86,19 +78,19 @@ namespace RageCoop.Client.Installer
Environment.Exit(1);
}
var shvdnVer = GetVer(shvdnPath);
if (shvdnVer<new Version(3,5,1))
if (shvdnVer < new Version(3, 6, 0))
{
MessageBox.Show("Please update ScriptHookVDotNet to latest version!" +
$"\nCurrent version is {shvdnVer}, 3.5.1 or higher is required");
$"\nCurrent version is {shvdnVer}, 3.6.0 or higher is required");
Environment.Exit(1);
}
if (File.Exists(lemonPath))
{
var lemonVer=GetVer(lemonPath);
if(lemonVer<new Version(1, 7))
var lemonVer = GetVer(lemonPath);
if (lemonVer < new Version(1, 7))
{
UpdateStatus("Updating LemonUI");
File.WriteAllBytes(lemonPath,getLemon());
File.WriteAllBytes(lemonPath, getLemon());
}
}
@ -129,7 +121,7 @@ namespace RageCoop.Client.Installer
void Finish()
{
checkKeys:
checkKeys:
UpdateStatus("Checking conflicts");
var menyooConfig = Path.Combine(root, @"menyooStuff\menyooConfig.ini");
var settingsPath = Path.Combine(installPath, @"Data\RageCoop.Client.Settings.xml");
@ -144,28 +136,28 @@ namespace RageCoop.Client.Installer
}
if (File.Exists(menyooConfig))
{
var lines = File.ReadAllLines(menyooConfig).Where(x => !x.StartsWith(";") && x.EndsWith(" = " +(int)settings.MenuKey));
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" +
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);
var ae = new AutoResetEvent(false);
UpdateStatus("Press the key you wish to change to");
Dispatcher.BeginInvoke(new Action(() =>
KeyDown += (s,e) =>
KeyDown += (s, e) =>
{
settings.MenuKey = (Keys)KeyInterop.VirtualKeyFromKey(e.Key);
ae.Set();
}));
ae.WaitOne();
if (!Util.SaveSettings(settingsPath,settings))
if (!Util.SaveSettings(settingsPath, settings))
{
MessageBox.Show("Error occurred when saving settings");
Environment.Exit(1);
}
MessageBox.Show("Menu key changed to "+settings.MenuKey);
MessageBox.Show("Menu key changed to " + settings.MenuKey);
goto checkKeys;
}
}
@ -178,10 +170,10 @@ namespace RageCoop.Client.Installer
}
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)
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);
UpdateStatus("Downloading ZeroTier from " + url);
try
{
HttpHelper.DownloadFile(url, "ZeroTier.msi", (p) => UpdateStatus("Downloading ZeroTier " + p + "%"));
@ -201,15 +193,18 @@ namespace RageCoop.Client.Installer
Environment.Exit(0);
}
}
void UpdateStatus(string status)
private void UpdateStatus(string status)
{
Dispatcher.BeginInvoke(new Action(() => Status.Content = status));
}
Version GetVer(string location)
private Version GetVer(string location)
{
return Version.Parse(FileVersionInfo.GetVersionInfo(location).FileVersion);
}
byte[] getLemon()
private byte[] getLemon()
{
return (byte[])Resource.ResourceManager.GetObject("LemonUI_SHVDN3");
}

View File

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

View File

@ -36,14 +36,14 @@ namespace RageCoop.Client
string s = "";
foreach (KeyValuePair<TimeStamp, long> kvp in d)
{
s+=kvp.Key+":"+kvp.Value+"\n";
s += kvp.Key + ":" + kvp.Value + "\n";
}
return s;
}
public static void ShowTimeStamps()
{
GTA.UI.Notification.Hide(_lastNfHandle);
_lastNfHandle=GTA.UI.Notification.Show(Debug.TimeStamps.Dump());
_lastNfHandle = GTA.UI.Notification.Show(Debug.TimeStamps.Dump());
}
}

View File

@ -16,14 +16,14 @@ namespace RageCoop.Client
public static MuzzleDir Direction = MuzzleDir.Forward;
public DevTool()
{
Tick+=OnTick;
KeyDown+=OnKeyDown;
Tick += OnTick;
KeyDown += OnKeyDown;
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (ToMark==null||(!ToMark.Exists())) { return; }
if (DevToolMenu.Menu.SelectedItem==DevToolMenu.boneIndexItem)
if (ToMark == null || (!ToMark.Exists())) { return; }
if (DevToolMenu.Menu.SelectedItem == DevToolMenu.boneIndexItem)
{
switch (e.KeyCode)
@ -36,7 +36,7 @@ namespace RageCoop.Client
break;
}
}
else if (DevToolMenu.Menu.SelectedItem==DevToolMenu.secondaryBoneIndexItem)
else if (DevToolMenu.Menu.SelectedItem == DevToolMenu.secondaryBoneIndexItem)
{
switch (e.KeyCode)
@ -54,24 +54,24 @@ namespace RageCoop.Client
private static void Update()
{
if (Current>ToMark.Bones.Count-1)
if (Current > ToMark.Bones.Count - 1)
{
Current=0;
Current = 0;
}
else if (Current< 0)
else if (Current < 0)
{
Current=ToMark.Bones.Count-1;
Current = ToMark.Bones.Count - 1;
}
DevToolMenu.boneIndexItem.AltTitle= Current.ToString();
if (Secondary>ToMark.Bones.Count-1)
DevToolMenu.boneIndexItem.AltTitle = Current.ToString();
if (Secondary > ToMark.Bones.Count - 1)
{
Secondary=0;
Secondary = 0;
}
else if (Secondary< 0)
else if (Secondary < 0)
{
Secondary=ToMark.Bones.Count-1;
Secondary = ToMark.Bones.Count - 1;
}
DevToolMenu.secondaryBoneIndexItem.AltTitle= Secondary.ToString();
DevToolMenu.secondaryBoneIndexItem.AltTitle = Secondary.ToString();
}
private static void OnTick(object sender, EventArgs e)
{
@ -87,44 +87,44 @@ namespace RageCoop.Client
private static void Draw(int boneindex)
{
var bone = ToMark.Bones[boneindex];
World.DrawLine(bone.Position, bone.Position+2*bone.ForwardVector, Color.Blue);
World.DrawLine(bone.Position, bone.Position+2*bone.UpVector, Color.Green);
World.DrawLine(bone.Position, bone.Position+2*bone.RightVector, Color.Yellow);
World.DrawLine(bone.Position, bone.Position + 2 * bone.ForwardVector, Color.Blue);
World.DrawLine(bone.Position, bone.Position + 2 * bone.UpVector, Color.Green);
World.DrawLine(bone.Position, bone.Position + 2 * bone.RightVector, Color.Yellow);
Vector3 todraw = bone.ForwardVector;
switch ((byte)Direction)
{
case 0:
todraw=bone.ForwardVector;
todraw = bone.ForwardVector;
break;
case 1:
todraw=bone.RightVector;
todraw = bone.RightVector;
break;
case 2:
todraw=bone.UpVector;
todraw = bone.UpVector;
break;
case 3:
todraw=bone.ForwardVector*-1;
todraw = bone.ForwardVector * -1;
break;
case 4:
todraw=bone.RightVector*-1;
todraw = bone.RightVector * -1;
break;
case 5:
todraw=bone.UpVector*-1;
todraw = bone.UpVector * -1;
break;
}
World.DrawLine(bone.Position, bone.Position+10*todraw, Color.Red);
World.DrawLine(bone.Position, bone.Position + 10 * todraw, Color.Red);
}
public static void CopyToClipboard(MuzzleDir dir)
{
if (ToMark!=null)
if (ToMark != null)
{
string s;
if (UseSecondary)
{
if ((byte)dir<3)
if ((byte)dir < 3)
{
s=$@"
s = $@"
// {ToMark.DisplayName}
case {ToMark.Model.Hash}:
return BulletsShot%2==0 ? {Current} : {Secondary};
@ -132,7 +132,7 @@ namespace RageCoop.Client
}
else
{
s=$@"
s = $@"
// {ToMark.DisplayName}
case {ToMark.Model.Hash}:
return BulletsShot%2==0 ? {Current} : {Secondary};
@ -141,9 +141,9 @@ namespace RageCoop.Client
}
else
{
if ((byte)dir<3)
if ((byte)dir < 3)
{
s=$@"
s = $@"
// {ToMark.DisplayName}
case {ToMark.Model.Hash}:
return {Current};
@ -151,7 +151,7 @@ namespace RageCoop.Client
}
else
{
s=$@"
s = $@"
// {ToMark.DisplayName}
case {ToMark.Model.Hash}:
return {Current};

View File

@ -6,12 +6,11 @@ using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RageCoop.Client
{
@ -21,7 +20,7 @@ namespace RageCoop.Client
internal class Main : Script
{
private 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;
@ -39,7 +38,7 @@ namespace RageCoop.Client
internal static ulong Ticked = 0;
internal static Vector3 PlayerPosition;
internal static Scripting.Resources Resources = null;
private static List<Func<bool>> QueuedActions = new List<Func<bool>>();
private static readonly List<Func<bool>> QueuedActions = new List<Func<bool>>();
public static Worker Worker;
/// <summary>
@ -47,9 +46,6 @@ namespace RageCoop.Client
/// </summary>
public Main()
{
#if DEBUG_HIGH_PING
Networking.SimulatedLatency=0.3f;
#endif
Worker = new Worker("RageCoop.Client.Main.Worker", Logger);
try
{
@ -58,14 +54,14 @@ namespace RageCoop.Client
catch
{
GTA.UI.Notification.Show("Malformed configuration, overwriting with default values...");
Settings=new Settings();
Settings = new Settings();
Util.SaveSettings();
}
Directory.CreateDirectory(Settings.DataDirectory);
Logger=new Logger()
Logger = new Logger()
{
LogPath=$"{Settings.DataDirectory}\\RageCoop.Client.log",
UseConsole=false,
LogPath = $"{Settings.DataDirectory}\\RageCoop.Client.log",
UseConsole = false,
#if DEBUG
LogLevel = 0,
#else
@ -90,7 +86,7 @@ namespace RageCoop.Client
return;
}
BaseScript.OnStart();
SyncedPedsGroup=World.AddRelationshipGroup("SYNCPED");
SyncedPedsGroup = World.AddRelationshipGroup("SYNCPED");
Game.Player.Character.RelationshipGroup.SetRelationshipBetweenGroups(SyncedPedsGroup, Relationship.Neutral, true);
#if !NON_INTERACTIVE
#endif
@ -98,9 +94,9 @@ namespace RageCoop.Client
Tick += OnTick;
Tick += (s, e) => { Scripting.API.Events.InvokeTick(); };
KeyDown += OnKeyDown;
KeyDown+=(s, e) => { Scripting.API.Events.InvokeKeyDown(s, e); };
KeyUp+=(s, e) => { Scripting.API.Events.InvokeKeyUp(s, e); };
Aborted += (object sender, EventArgs e) => CleanUp();
KeyDown += (s, e) => { Scripting.API.Events.InvokeKeyDown(s, e); };
KeyUp += (s, e) => { Scripting.API.Events.InvokeKeyUp(s, e); };
Aborted += (object sender, EventArgs e) => Disconnected("Abort");
Util.NativeMemory();
Counter.Restart();
@ -111,24 +107,9 @@ namespace RageCoop.Client
private bool _lastDead;
private void OnTick(object sender, EventArgs e)
{
/*
unsafe
{
var stationName = Function.Call<string>(Hash.GET_RADIO_STATION_NAME, Game.RadioStation);
//_GET_CURRENT_RADIO_TRACK_NAME
var currentTrack = Function.Call<int>((Hash)0x34D66BC058019CE0, stationName);
Function.Call(Hash.SET_RADIO_TRACK, "RADIO_03_HIPHOP_NEW", "ARM1_RADIO_STARTS");
return currentTrack;
var h1 = Function.Call<int>(Hash._GET_CURRENT_RADIO_STATION_HASH);
return $"{h1},{h2},{s},{s1}";
}
*/
P= Game.Player.Character;
PlayerPosition=P.ReadPosition();
FPS=Game.FPS;
// World.DrawMarker(MarkerType.DebugSphere, PedExtensions.RaycastEverything(default), default, default, new Vector3(0.2f, 0.2f, 0.2f), Color.AliceBlue);
P = Game.Player.Character;
PlayerPosition = P.ReadPosition();
FPS = Game.FPS;
if (Game.IsLoading)
{
return;
@ -137,7 +118,6 @@ namespace RageCoop.Client
{
#if !NON_INTERACTIVE
GTA.UI.Notification.Show(GTA.UI.NotificationIcon.AllPlayersConf, "RAGECOOP", "Welcome!", $"Press ~g~{Main.Settings.MenuKey}~s~ to open the menu.");
WorldThread.Traffic(!Settings.DisableTraffic);
#endif
}
@ -151,9 +131,9 @@ namespace RageCoop.Client
{
return;
}
if (Game.TimeScale!=1)
if (Game.TimeScale != 1)
{
Game.TimeScale=1;
Game.TimeScale = 1;
}
try
{
@ -161,7 +141,9 @@ namespace RageCoop.Client
}
catch (Exception ex)
{
#if DEBUG
Main.Logger.Error(ex);
#endif
}
if (Networking.ShowNetworkInfo)
@ -183,12 +165,12 @@ namespace RageCoop.Client
{
Function.Call(Hash.SET_FADE_OUT_AFTER_DEATH, false);
if (P.Health!=1)
if (P.Health != 1)
{
P.Health=1;
Game.Player.WantedLevel=0;
P.Health = 1;
Game.Player.WantedLevel = 0;
Main.Logger.Debug("Player died.");
Scripting.API.Events.InvokePlayerDied();
Scripting.API.Events.InvokePlayerDied(KillMessage());
}
GTA.UI.Screen.StopEffects();
}
@ -199,10 +181,10 @@ namespace RageCoop.Client
}
else if (P.IsDead && !_lastDead)
{
Scripting.API.Events.InvokePlayerDied();
Scripting.API.Events.InvokePlayerDied(KillMessage());
}
_lastDead=P.IsDead;
_lastDead = P.IsDead;
Ticked++;
}
private void OnKeyDown(object sender, KeyEventArgs e)
@ -233,7 +215,7 @@ namespace RageCoop.Client
Function.Call(Hash.ACTIVATE_FRONTEND_MENU, Function.Call<int>(Hash.GET_HASH_KEY, "FE_MENU_VERSION_SP_PAUSE"), false, 0);
return;
}
if (Game.IsControlPressed(GTA.Control.FrontendPauseAlternate)&&Settings.DisableAlternatePause)
if (Game.IsControlPressed(GTA.Control.FrontendPauseAlternate) && Settings.DisableAlternatePause)
{
Function.Call(Hash.ACTIVATE_FRONTEND_MENU, Function.Call<int>(Hash.GET_HASH_KEY, "FE_MENU_VERSION_SP_PAUSE"), false, 0);
return;
@ -247,8 +229,8 @@ namespace RageCoop.Client
{
if (x.Visible)
{
CoopMenu.LastMenu=x;
x.Visible=false;
CoopMenu.LastMenu = x;
x.Visible = false;
}
});
}
@ -273,7 +255,7 @@ namespace RageCoop.Client
PlayerList.Pressed = (currentTimestamp - PlayerList.Pressed) < 5000 ? (currentTimestamp - 6000) : currentTimestamp;
}
}
else if (e.KeyCode==Settings.PassengerKey)
else if (e.KeyCode == Settings.PassengerKey)
{
var P = Game.Player.Character;
@ -287,13 +269,13 @@ namespace RageCoop.Client
{
var V = World.GetClosestVehicle(P.ReadPosition(), 50);
if (V!=null)
if (V != null)
{
var seat = P.GetNearestSeat(V);
var p = V.GetPedOnSeat(seat);
if (p != null && !p.IsDead)
{
for(int i = -1; i < V.PassengerCapacity; i++)
for (int i = -1; i < V.PassengerCapacity; i++)
{
seat = (VehicleSeat)i;
p = V.GetPedOnSeat(seat);
@ -303,21 +285,55 @@ namespace RageCoop.Client
}
}
}
P.Task.EnterVehicle(V, seat,-1,5,EnterVehicleFlags.None);
P.Task.EnterVehicle(V, seat, -1, 5, EnterVehicleFlags.None);
}
}
}
}
}
public static void CleanUp()
internal static void Connected()
{
MainChat.Clear();
Memory.ApplyPatches();
if (Settings.Voice && !Voice.WasInitialized())
{
Voice.Init();
}
QueueAction(() =>
{
WorldThread.Traffic(!Settings.DisableTraffic);
Function.Call(Hash.SET_ENABLE_VEHICLE_SLIPSTREAMING, true);
CoopMenu.ConnectedMenuSetting();
MainChat.Init();
GTA.UI.Notification.Show("~g~Connected!");
});
Logger.Info(">> Connected <<");
}
public static void Disconnected(string reason)
{
Logger.Info($">> Disconnected << reason: {reason}");
QueueAction(() =>
{
if (MainChat.Focused)
{
MainChat.Focused = false;
}
PlayerList.Cleanup();
MainChat.Clear();
EntityPool.Cleanup();
WorldThread.Traffic(true);
Function.Call(Hash.SET_ENABLE_VEHICLE_SLIPSTREAMING, false);
CoopMenu.DisconnectedMenuSetting();
if (reason != "Abort")
GTA.UI.Notification.Show("~r~Disconnected: " + reason);
LocalPlayerID = default;
});
Memory.RestorePatches();
DownloadManager.Cleanup();
Voice.ClearAll();
EntityPool.Cleanup();
PlayerList.Cleanup();
LocalPlayerID=default;
WorldThread.Traffic(!Settings.DisableTraffic);
Function.Call(Hash.SET_ENABLE_VEHICLE_SLIPSTREAMING, false);
Resources.Unload();
}
private static void DoQueuedActions()
{
@ -334,7 +350,9 @@ namespace RageCoop.Client
}
catch (Exception ex)
{
#if DEBUG
Logger.Error(ex);
#endif
QueuedActions.Remove(action);
}
}
@ -375,5 +393,16 @@ namespace RageCoop.Client
QueueAction(a);
});
}
private string KillMessage()
{
if (P.Killer != null)
{
var killer = EntityPool.GetPedByHandle(P.Killer.Handle);
if (killer != null && killer.ID == killer.Owner.ID)
return $"~h~{PlayerList.GetPlayer(LocalPlayerID).Username}~h~ was killed by ~h~{killer.Owner.Username}~h~ ({P.CauseOfDeath})";
}
return $"~h~{PlayerList.GetPlayer(LocalPlayerID).Username}~h~ died";
}
}
}

View File

@ -1,4 +1,5 @@
using GTA;
using GTA.Native;
using LemonUI;
using LemonUI.Menus;
using LemonUI.Scaleform;
@ -19,12 +20,12 @@ namespace RageCoop.Client.Menus
};
public static PopUp PopUp = new PopUp()
{
Title="",
Prompt="",
Title = "",
Prompt = "",
Subtitle = "",
Error="",
Error = "",
ShowBackground = true,
Visible=false,
Visible = false,
};
public static NativeMenu LastMenu { get; set; } = Menu;
#region ITEMS
@ -49,10 +50,10 @@ namespace RageCoop.Client.Menus
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
_usernameItem.Activated += UsernameActivated;
_passwordItem.Activated+=_passwordActivated;
_passwordItem.Activated += _passwordActivated;
ServerIpItem.Activated += ServerIpActivated;
_serverConnectItem.Activated += (sender, item) => { Networking.ToggleConnection(Main.Settings.LastServerAddress); };
@ -66,17 +67,18 @@ namespace RageCoop.Client.Menus
Menu.AddSubMenu(SettingsMenu.Menu);
Menu.AddSubMenu(DevToolMenu.Menu);
#if DEBUG
Menu.AddSubMenu(DebugMenu.Menu);
Menu.AddSubMenu(UpdateMenu.Menu);
#endif
MenuPool.Add(Menu);
MenuPool.Add(SettingsMenu.Menu);
MenuPool.Add(DevToolMenu.Menu);
#if DEBUG
MenuPool.Add(DebugMenu.Menu);
MenuPool.Add(DebugMenu.DiagnosticMenu);
#endif
MenuPool.Add(ServersMenu.Menu);
MenuPool.Add(UpdateMenu.Menu);
MenuPool.Add(PopUp);
Menu.Add(_aboutItem);
@ -85,20 +87,30 @@ namespace RageCoop.Client.Menus
public static bool ShowPopUp(string prompt, string title, string subtitle, string error, bool showbackground)
{
PopUp.Prompt=prompt;
PopUp.Title=title;
PopUp.Subtitle=subtitle;
PopUp.Error=error;
PopUp.ShowBackground=showbackground;
PopUp.Visible=true;
PopUp.Prompt = prompt;
PopUp.Title = title;
PopUp.Subtitle = subtitle;
PopUp.Error = error;
PopUp.ShowBackground = showbackground;
PopUp.Visible = true;
Script.Yield();
while (true)
{
Game.DisableAllControlsThisFrame();
MenuPool.Process();
var scaleform = new Scaleform("instructional_buttons");
scaleform.CallFunction("CLEAR_ALL");
scaleform.CallFunction("TOGGLE_MOUSE_BUTTONS", 0);
scaleform.CallFunction("CREATE_CONTAINER");
scaleform.CallFunction("SET_DATA_SLOT", 0, Function.Call<string>((Hash)0x0499D7B09FC9B407, 2, (int)Control.FrontendAccept, 0), "Continue");
scaleform.CallFunction("SET_DATA_SLOT", 1, Function.Call<string>((Hash)0x0499D7B09FC9B407, 2, (int)Control.FrontendCancel, 0), "Cancel");
scaleform.CallFunction("DRAW_INSTRUCTIONAL_BUTTONS", -1);
scaleform.Render2D();
if (Game.IsControlJustPressed(Control.FrontendAccept))
{
PopUp.Visible=false;
PopUp.Visible = false;
return true;
}
else if (Game.IsControlJustPressed(Control.FrontendCancel))
@ -107,6 +119,8 @@ namespace RageCoop.Client.Menus
return false;
}
Script.Yield();
Game.DisableAllControlsThisFrame();
}
}
public static void UsernameActivated(object a, System.EventArgs b)

View File

@ -1,7 +1,8 @@
using GTA;
#if DEBUG
using GTA;
using LemonUI.Menus;
using System.Drawing;
using System;
using System.Drawing;
namespace RageCoop.Client
{
@ -24,10 +25,10 @@ namespace RageCoop.Client
static DebugMenu()
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
DiagnosticMenu.Opening+=(sender, e) =>
DiagnosticMenu.Opening += (sender, e) =>
{
DiagnosticMenu.Clear();
DiagnosticMenu.Add(new NativeItem("EntityPool", EntityPool.DumpDebug()));
@ -36,13 +37,13 @@ namespace RageCoop.Client
DiagnosticMenu.Add(new NativeItem(pair.Key.ToString(), pair.Value.ToString(), pair.Value.ToString()));
}
};
SimulatedLatencyItem.Activated+=(s, e) =>
SimulatedLatencyItem.Activated += (s, e) =>
{
try
{
SimulatedLatencyItem.AltTitle=((Networking.SimulatedLatency=int.Parse(Game.GetUserInput(SimulatedLatencyItem.AltTitle))*0.002f)*500).ToString();
SimulatedLatencyItem.AltTitle = ((Networking.SimulatedLatency = int.Parse(Game.GetUserInput(SimulatedLatencyItem.AltTitle)) * 0.002f) * 500).ToString();
}
catch(Exception ex) { Main.Logger.Error(ex); }
catch (Exception ex) { Main.Logger.Error(ex); }
};
ShowNetworkInfoItem.CheckboxChanged += (s, e) => { Networking.ShowNetworkInfo = ShowNetworkInfoItem.Checked; };
ShowOwnerItem.CheckboxChanged += (s, e) => { Main.Settings.ShowEntityOwnerName = ShowOwnerItem.Checked; Util.SaveSettings(); };
@ -56,3 +57,4 @@ namespace RageCoop.Client
}
}
#endif

View File

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

View File

@ -1,12 +1,12 @@
using LemonUI.Menus;
using GTA.UI;
using LemonUI.Menus;
using Newtonsoft.Json;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Net;
using System.Threading;
using RageCoop.Core;
using GTA.UI;
namespace RageCoop.Client.Menus
{
@ -30,7 +30,7 @@ namespace RageCoop.Client.Menus
static ServersMenu()
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
Menu.Opening += (object sender, System.ComponentModel.CancelEventArgs e) =>
{
@ -38,7 +38,7 @@ namespace RageCoop.Client.Menus
Menu.Add(ResultItem = new NativeItem("Loading..."));
// Prevent freezing
GetServersThread=new Thread(() => GetAllServers());
GetServersThread = new Thread(() => GetAllServers());
GetServersThread.Start();
};
Menu.Closing += (object sender, System.ComponentModel.CancelEventArgs e) =>
@ -76,7 +76,7 @@ namespace RageCoop.Client.Menus
foreach (ServerInfo server in serverList)
{
string address = $"{server.address}:{server.port}";
NativeItem tmpItem = new NativeItem($"[{server.country}] {server.name}", $"~b~{address}~s~~n~~g~Version {server.version}.x~s~") { AltTitle = $"[{server.players}/{server.maxPlayers}]" };
NativeItem tmpItem = new NativeItem($"[{server.country}] {server.name}", $"~b~{address}~s~~n~~g~Version {server.version}~s~") { AltTitle = $"[{server.players}/{server.maxPlayers}]" };
tmpItem.Activated += (object sender, EventArgs e) =>
{
try
@ -84,14 +84,14 @@ namespace RageCoop.Client.Menus
Menu.Visible = false;
if (server.useZT)
{
address=$"{server.ztAddress}:{server.port}";
address = $"{server.ztAddress}:{server.port}";
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");
}
}
Networking.ToggleConnection(address,null,null,PublicKey.FromServerInfo(server));
Networking.ToggleConnection(address, null, null, PublicKey.FromServerInfo(server));
#if !NON_INTERACTIVE
CoopMenu.ServerIpItem.AltTitle = address;

View File

@ -17,24 +17,36 @@ namespace RageCoop.Client.Menus
private static readonly NativeCheckboxItem _disableTrafficItem = new NativeCheckboxItem("Disable Traffic (NPCs/Vehicles)", "Local traffic only", Main.Settings.DisableTraffic);
private static readonly NativeCheckboxItem _flipMenuItem = new NativeCheckboxItem("Flip menu", Main.Settings.FlipMenu);
private static readonly NativeCheckboxItem _disablePauseAlt = new NativeCheckboxItem("Disable Alternate Pause", "Don't freeze game time when Esc pressed", Main.Settings.DisableAlternatePause);
private static readonly NativeCheckboxItem _showBlip = new NativeCheckboxItem("Show player blip", "Show other player's blip on map", Main.Settings.ShowPlayerBlip);
private static readonly NativeCheckboxItem _showNametag = new NativeCheckboxItem("Show player nametag", "Show other player's nametag on your screen", Main.Settings.ShowPlayerNameTag);
private static readonly NativeCheckboxItem _disableVoice = new NativeCheckboxItem("Enable voice", "Check your GTA:V settings to find the right key on your keyboard for PushToTalk and talk to your friends", Main.Settings.Voice);
private static NativeItem _menuKey = new NativeItem("Menu Key", "The key to open menu", Main.Settings.MenuKey.ToString());
private static NativeItem _passengerKey = new NativeItem("Passenger Key", "The key to enter a vehicle as passenger", Main.Settings.PassengerKey.ToString());
private static NativeItem _vehicleSoftLimit = new NativeItem("Vehicle limit (soft)", "The game won't spawn more NPC traffic if the limit is exceeded. \n-1 for unlimited (not recommended).", Main.Settings.WorldVehicleSoftLimit.ToString());
private static readonly NativeItem _menuKey = new NativeItem("Menu Key", "The key to open menu", Main.Settings.MenuKey.ToString());
private static readonly NativeItem _passengerKey = new NativeItem("Passenger Key", "The key to enter a vehicle as passenger", Main.Settings.PassengerKey.ToString());
private static readonly NativeItem _vehicleSoftLimit = new NativeItem("Vehicle limit (soft)", "The game won't spawn more NPC traffic if the limit is exceeded. \n-1 for unlimited (not recommended).", Main.Settings.WorldVehicleSoftLimit.ToString());
static SettingsMenu()
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
_disableTrafficItem.CheckboxChanged += DisableTrafficCheckboxChanged;
_disablePauseAlt.CheckboxChanged+= DisablePauseAltCheckboxChanged;
_disablePauseAlt.CheckboxChanged += DisablePauseAltCheckboxChanged;
_disableVoice.CheckboxChanged += DisableVoiceCheckboxChanged;
_flipMenuItem.CheckboxChanged += FlipMenuCheckboxChanged;
_menuKey.Activated+= ChaneMenuKey;
_passengerKey.Activated+= ChangePassengerKey;
_vehicleSoftLimit.Activated+= VehicleSoftLimitActivated;
_menuKey.Activated += ChaneMenuKey;
_passengerKey.Activated += ChangePassengerKey;
_vehicleSoftLimit.Activated += VehicleSoftLimitActivated;
_showBlip.Activated += (s, e) =>
{
Main.Settings.ShowPlayerBlip = _showBlip.Checked;
Util.SaveSettings();
};
_showNametag.Activated += (s, e) =>
{
Main.Settings.ShowPlayerNameTag = _showNametag.Checked;
Util.SaveSettings();
};
Menu.Add(_disableTrafficItem);
Menu.Add(_disablePauseAlt);
@ -43,6 +55,8 @@ namespace RageCoop.Client.Menus
Menu.Add(_menuKey);
Menu.Add(_passengerKey);
Menu.Add(_vehicleSoftLimit);
Menu.Add(_showBlip);
Menu.Add(_showNametag);
}
private static void DisableVoiceCheckboxChanged(object sender, EventArgs e)
@ -53,7 +67,9 @@ namespace RageCoop.Client.Menus
{
Voice.Init();
}
} else {
}
else
{
Voice.ClearAll();
}
@ -63,17 +79,17 @@ namespace RageCoop.Client.Menus
private static void DisablePauseAltCheckboxChanged(object sender, EventArgs e)
{
Main.Settings.DisableAlternatePause=_disablePauseAlt.Checked;
Main.Settings.DisableAlternatePause = _disablePauseAlt.Checked;
Util.SaveSettings();
}
private static void VehicleSoftLimitActivated(object sender, EventArgs e)
{
try
{
Main.Settings.WorldVehicleSoftLimit =int.Parse(
Main.Settings.WorldVehicleSoftLimit = int.Parse(
Game.GetUserInput(WindowTitle.EnterMessage20,
Main.Settings.WorldVehicleSoftLimit.ToString(), 20));
_menuKey.AltTitle=Main.Settings.WorldVehicleSoftLimit.ToString();
_menuKey.AltTitle = Main.Settings.WorldVehicleSoftLimit.ToString();
Util.SaveSettings();
}
catch { }
@ -82,11 +98,11 @@ namespace RageCoop.Client.Menus
{
try
{
Main.Settings.MenuKey =(Keys)Enum.Parse(
Main.Settings.MenuKey = (Keys)Enum.Parse(
typeof(Keys),
Game.GetUserInput(WindowTitle.EnterMessage20,
Main.Settings.MenuKey.ToString(), 20));
_menuKey.AltTitle=Main.Settings.MenuKey.ToString();
_menuKey.AltTitle = Main.Settings.MenuKey.ToString();
Util.SaveSettings();
}
catch { }
@ -96,11 +112,11 @@ namespace RageCoop.Client.Menus
{
try
{
Main.Settings.PassengerKey =(Keys)Enum.Parse(
Main.Settings.PassengerKey = (Keys)Enum.Parse(
typeof(Keys),
Game.GetUserInput(WindowTitle.EnterMessage20,
Main.Settings.PassengerKey.ToString(), 20));
_passengerKey.AltTitle=Main.Settings.PassengerKey.ToString();
_passengerKey.AltTitle = Main.Settings.PassengerKey.ToString();
Util.SaveSettings();
}
catch { }

View File

@ -1,105 +0,0 @@
using ICSharpCode.SharpZipLib.Zip;
using LemonUI.Menus;
using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Threading.Tasks;
namespace RageCoop.Client.Menus
{
internal class UpdateMenu
{
public static bool IsUpdating { get; private set; } = false;
private static NativeItem _updatingItem = new NativeItem("Updating...");
private static NativeItem _downloadItem = new NativeItem("Download", "Download and update to latest nightly");
private static string _downloadPath = Path.Combine(Main.Settings.DataDirectory, "RageCoop.Client.zip");
public static NativeMenu Menu = new NativeMenu("Update", "Update", "Download and install latest nightly build from GitHub")
{
UseMouse = false,
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
};
static UpdateMenu()
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
Menu.Opening+=Opening;
_downloadItem.Activated+=StartUpdate;
}
private static void StartUpdate(object sender, EventArgs e)
{
IsUpdating=true;
Menu.Clear();
Menu.Add(_updatingItem);
Task.Run(() =>
{
try
{
if (File.Exists(_downloadPath)) { File.Delete(_downloadPath); }
WebClient client = new WebClient();
// TLS only
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
client.DownloadProgressChanged += (s, e1) => { Main.QueueAction(() => { _updatingItem.AltTitle=$"{e1.ProgressPercentage}%"; }); };
client.DownloadFileCompleted +=(s, e2) => { Install(); };
client.DownloadFileAsync(new Uri("https://github.com/RAGECOOP/RAGECOOP-V/releases/download/nightly/RageCoop.Client.zip"), _downloadPath);
}
catch (Exception ex)
{
Main.Logger.Error(ex);
}
});
}
private static void Install()
{
try
{
Main.QueueAction(() =>
{
_updatingItem.AltTitle="Installing...";
});
Directory.CreateDirectory(@"Scripts\RageCoop");
foreach(var f in Directory.GetFiles(@"Scripts\RageCoop", "*.dll", SearchOption.AllDirectories))
{
try { File.Delete(f); }
catch { }
}
new FastZip().ExtractZip(_downloadPath, "Scripts", FastZip.Overwrite.Always, null, null, null, true);
try { File.Delete(_downloadPath); } catch { }
try { File.Delete(Path.Combine("Scripts","RageCoop.Client.Installer.exe")); } catch { }
Main.QueueAction(() =>
{
Util.Reload();
IsUpdating=false;
});
}
catch (Exception ex)
{
Main.Logger.Error(ex);
}
}
private static void Opening(object sender, System.ComponentModel.CancelEventArgs e)
{
Menu.Clear();
if (Networking.IsOnServer)
{
Menu.Add(new NativeItem("Disconnect from the server first"));
}
else if (IsUpdating)
{
Menu.Add(_updatingItem);
}
else
{
Menu.Add(_downloadItem);
}
}
}
}

View File

@ -16,7 +16,7 @@ namespace RageCoop.Client
private bool CurrentFocused { get; set; }
public bool Focused
{
get { return CurrentFocused; }
get => CurrentFocused;
set
{
if (value && Hidden)
@ -35,7 +35,7 @@ namespace RageCoop.Client
private bool CurrentHidden { get; set; }
private bool Hidden
{
get { return CurrentHidden; }
get => CurrentHidden;
set
{
if (value)

View File

@ -21,8 +21,8 @@ namespace RageCoop.Client
}
return new Packets.FileTransferResponse()
{
ID= fr.ID,
Response=AddFile(fr.ID, fr.Name, fr.FileLength) ? FileResponse.NeedToDownload : FileResponse.AlreadyExists
ID = fr.ID,
Response = AddFile(fr.ID, fr.Name, fr.FileLength) ? FileResponse.NeedToDownload : FileResponse.AlreadyExists
};
});
Networking.RequestHandlers.Add(PacketType.FileTransferComplete, (data) =>
@ -36,8 +36,8 @@ namespace RageCoop.Client
// Inform the server that the download is completed
return new Packets.FileTransferResponse()
{
ID= packet.ID,
Response=FileResponse.Completed
ID = packet.ID,
Response = FileResponse.Completed
};
});
Networking.RequestHandlers.Add(PacketType.AllResourcesSent, (data) =>
@ -45,13 +45,13 @@ namespace RageCoop.Client
try
{
Main.Resources.Load(ResourceFolder, _resources.ToArray());
return new Packets.FileTransferResponse() { ID=0, Response=FileResponse.Loaded };
return new Packets.FileTransferResponse() { ID = 0, Response = FileResponse.Loaded };
}
catch (Exception ex)
{
Main.Logger.Error("Error occurred when loading server resource:");
Main.Logger.Error(ex);
return new Packets.FileTransferResponse() { ID=0, Response=FileResponse.LoadFailed };
return new Packets.FileTransferResponse() { ID = 0, Response = FileResponse.LoadFailed };
}
});
}
@ -122,8 +122,7 @@ namespace RageCoop.Client
{
lock (InProgressDownloads)
{
DownloadFile file;
if (InProgressDownloads.TryGetValue(id, out file))
if (InProgressDownloads.TryGetValue(id, out DownloadFile file))
{
file.Stream.Write(chunk, 0, chunk.Length);
@ -137,9 +136,8 @@ namespace RageCoop.Client
public static void Complete(int id)
{
DownloadFile f;
if (InProgressDownloads.TryGetValue(id, out f))
if (InProgressDownloads.TryGetValue(id, out DownloadFile f))
{
InProgressDownloads.Remove(id);
f.Dispose();
@ -176,7 +174,7 @@ namespace RageCoop.Client
public FileStream Stream { get; set; }
public void Dispose()
{
if (Stream!= null)
if (Stream != null)
{
Stream.Flush();
Stream.Close();

View File

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

View File

@ -1,44 +1,45 @@
using Lidgren.Network;
using GTA.UI;
using Lidgren.Network;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Net;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using GTA.UI;
using System.Net;
namespace RageCoop.Client
{
internal static partial class Networking
{
public static CoopPeer Peer;
public static float Latency => ServerConnection.AverageRoundtripTime/2;
public static float Latency => ServerConnection.AverageRoundtripTime / 2;
public static bool ShowNetworkInfo = false;
public static Security Security;
public static NetConnection ServerConnection;
private static readonly Dictionary<int, Action<PacketType, byte[]>> PendingResponses = new Dictionary<int, Action<PacketType, byte[]>>();
internal static readonly Dictionary<PacketType, Func<byte[], Packet>> RequestHandlers = new Dictionary<PacketType, Func<byte[], Packet>>();
internal static float SimulatedLatency=0;
private static readonly Dictionary<int, Action<PacketType, NetIncomingMessage>> PendingResponses = new Dictionary<int, Action<PacketType, NetIncomingMessage>>();
internal static readonly Dictionary<PacketType, Func<NetIncomingMessage, Packet>> RequestHandlers = new Dictionary<PacketType, Func<NetIncomingMessage, Packet>>();
internal static float SimulatedLatency = 0;
public static bool IsConnecting { get; private set; }
public static IPEndPoint _targetServerEP;
static Networking()
{
Security=new Security(Main.Logger);
Security = new Security(Main.Logger);
}
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)
{
Menus.CoopMenu.Menu.Visible=false;
Peer?.Shutdown("Bye");
if (IsOnServer)
Menus.CoopMenu.Menu.Visible = false;
if (IsConnecting)
{
// ?
}
else if (IsConnecting) {
_publicKeyReceived.Set();
IsConnecting = false;
Notification.Show("Connection has been canceled");
Main.QueueAction(() => Notification.Show("Connection has been canceled"));
Peer?.Shutdown("Bye");
}
else if (IsOnServer)
{
Peer?.Shutdown("Bye");
}
else
{
@ -46,19 +47,20 @@ namespace RageCoop.Client
IsConnecting = true;
password = password ?? Main.Settings.Password;
username=username ?? Main.Settings.Username;
username = username ?? Main.Settings.Username;
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
{
AutoFlushSendQueue = false,
SimulatedMinimumLatency =SimulatedLatency,
SimulatedRandomLatency=0,
AcceptIncomingConnections = true,
MaximumConnections = 32,
PingInterval = 5
};
#if DEBUG
config.SimulatedMinimumLatency = SimulatedLatency;
config.SimulatedRandomLatency = 0;
#endif
config.EnableMessageType(NetIncomingMessageType.UnconnectedData);
config.EnableMessageType(NetIncomingMessageType.NatIntroductionSuccess);
@ -78,45 +80,54 @@ namespace RageCoop.Client
PlayerList.Cleanup();
EntityPool.AddPlayer();
if (publicKey==null && !string.IsNullOrEmpty(password) && !Menus.CoopMenu.ShowPopUp("", "WARNING", "Server's IP can be spoofed when using direct connection, do you wish to continue?", "", true))
if (publicKey == null && !string.IsNullOrEmpty(password) && !Menus.CoopMenu.ShowPopUp("", "WARNING", "Server's IP can be spoofed when using direct connection, do you wish to continue?", "", true))
{
IsConnecting=false;
IsConnecting = false;
return;
}
Task.Run(() =>
{
try
{
_targetServerEP=CoreUtils.StringToEndPoint(address);
_targetServerEP = CoreUtils.StringToEndPoint(address);
// Ensure static constructor invocation
DownloadManager.Cleanup();
Peer = new CoopPeer(config);
Peer.OnMessageReceived+= (s, m) =>
Peer.OnMessageReceived += (s, m) =>
{
try { ProcessMessage(m); }
catch (Exception ex) { Main.Logger.Error(ex); }
catch (Exception ex)
{
#if DEBUG
Main.Logger.Error(ex);
#endif
}
};
Main.QueueAction(() => { Notification.Show($"~y~Trying to connect..."); });
Menus.CoopMenu._serverConnectItem.Enabled=false;
Menus.CoopMenu._serverConnectItem.Enabled = false;
Security.Regen();
if(publicKey==null){
if (!GetServerPublicKey(ip[0],int.Parse(ip[1])))
if (publicKey == null)
{
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");
}
}
else{
Security.SetServerPublicKey(publicKey.Modulus,publicKey.Exponent);
else
{
Security.SetServerPublicKey(publicKey.Modulus, publicKey.Exponent);
}
// Send handshake packet
NetOutgoingMessage outgoingMessage = Peer.CreateMessage();
var handshake = new Packets.Handshake()
{
PedID = Main.LocalPlayerID,
Username =username,
PedID = Main.LocalPlayerID,
Username = username,
ModVersion = Main.Version.ToString(),
PasswordEncrypted=Security.Encrypt(password.GetBytes()),
PasswordEncrypted = Security.Encrypt(password.GetBytes()),
InternalEndPoint = new System.Net.IPEndPoint(CoreUtils.GetLocalAddress(ip[0]), Peer.Port)
};
@ -128,9 +139,9 @@ namespace RageCoop.Client
catch (Exception ex)
{
Main.Logger.Error("Cannot connect to server: ", ex);
Main.QueueAction(() => Notification.Show("Cannot connect to server: "+ex.Message));
Main.QueueAction(() => Notification.Show("Cannot connect to server: " + ex.Message));
}
IsConnecting=false;
IsConnecting = false;
});
}
}
@ -141,8 +152,8 @@ namespace RageCoop.Client
{
var p = new Player
{
PedID = packet.PedID,
Username= packet.Username,
ID = packet.PedID,
Username = packet.Username,
};
PlayerList.SetPlayer(packet.PedID, packet.Username);
@ -153,9 +164,10 @@ namespace RageCoop.Client
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
{
var player = PlayerList.GetPlayer(packet.PedID);
if (player==null) { return; }
if (player == null) { return; }
PlayerList.RemovePlayer(packet.PedID);
Main.QueueAction(() => {
Main.QueueAction(() =>
{
EntityPool.RemoveAllFromPlayer(packet.PedID);
GTA.UI.Notification.Show($"~h~{player.Username}~h~ left.");
});
@ -163,13 +175,13 @@ namespace RageCoop.Client
#endregion // -- PLAYER --
#region -- GET --
private static bool GetServerPublicKey(string host,int port, int timeout = 10000)
private static bool GetServerPublicKey(string host, int port, int timeout = 10000)
{
Security.ServerRSA=null;
Security.ServerRSA = null;
var msg = Peer.CreateMessage();
new Packets.PublicKeyRequest().Pack(msg);
Peer.SendUnconnectedMessage(msg, host, port);
return _publicKeyReceived.WaitOne(timeout) && Security.ServerRSA!=null;
return _publicKeyReceived.WaitOne(timeout) && Security.ServerRSA != null;
}
public static void GetResponse<T>(Packet request, Action<T> callback, ConnectionChannel channel = ConnectionChannel.RequestResponse) where T : Packet, new()
@ -186,14 +198,14 @@ namespace RageCoop.Client
msg.Write((byte)PacketType.Request);
msg.Write(id);
request.Pack(msg);
Peer.SendMessage(msg,ServerConnection, NetDeliveryMethod.ReliableOrdered, (int)channel);
Peer.SendMessage(msg, ServerConnection, NetDeliveryMethod.ReliableOrdered, (int)channel);
}
#endregion
private static int NewRequestID()
{
int ID = 0;
while ((ID==0) || PendingResponses.ContainsKey(ID))
while ((ID == 0) || PendingResponses.ContainsKey(ID))
{
byte[] rngBytes = new byte[4];

View File

@ -3,9 +3,7 @@ using Lidgren.Network;
using RageCoop.Client.Menus;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Threading;
using GTA.Native;
namespace RageCoop.Client
{
@ -15,7 +13,7 @@ namespace RageCoop.Client
/// <summary>
/// Reduce GC pressure by reusing frequently used packets
/// </summary>
static class ReceivedPackets
private static class ReceivedPackets
{
public static Packets.PedSync PedPacket = new Packets.PedSync();
public static Packets.VehicleSync VehicelPacket = new Packets.VehicleSync();
@ -25,7 +23,7 @@ namespace RageCoop.Client
/// <summary>
/// Used to reslove entity handle in a <see cref="Packets.CustomEvent"/>
/// </summary>
private static readonly Func<byte, BitReader, object> _resolveHandle = (t, reader) =>
private static readonly Func<byte, NetIncomingMessage, object> _resolveHandle = (t, reader) =>
{
switch (t)
{
@ -38,14 +36,15 @@ namespace RageCoop.Client
case 60:
return EntityPool.ServerBlips[reader.ReadInt32()].Handle;
default:
throw new ArgumentException("Cannot resolve server side argument: "+t);
throw new ArgumentException("Cannot resolve server side argument: " + t);
}
};
private static readonly AutoResetEvent _publicKeyReceived = new AutoResetEvent(false);
private static bool _recycle;
public static void ProcessMessage(NetIncomingMessage message)
{
if (message == null) { return; }
_recycle = true;
switch (message.MessageType)
{
case NetIncomingMessageType.StatusChanged:
@ -54,50 +53,36 @@ namespace RageCoop.Client
switch (status)
{
case NetConnectionStatus.InitiatedConnect:
if (message.SenderConnection==ServerConnection)
if (message.SenderConnection == ServerConnection)
{
CoopMenu.InitiateConnectionMenuSetting();
}
break;
case NetConnectionStatus.Connected:
if (message.SenderConnection==ServerConnection)
if (message.SenderConnection == ServerConnection)
{
Memory.ApplyPatches();
var response = message.SenderConnection.RemoteHailMessage;
if ((PacketType)response.ReadByte()!=PacketType.HandshakeSuccess)
if ((PacketType)response.ReadByte() != PacketType.HandshakeSuccess)
{
throw new Exception("Invalid handshake response!");
}
var p = new Packets.HandshakeSuccess();
p.Deserialize(response.ReadBytes(response.ReadInt32()));
foreach(var player in p.Players)
p.Deserialize(response);
foreach (var player in p.Players)
{
PlayerList.SetPlayer(player.ID,player.Username);
PlayerList.SetPlayer(player.ID, player.Username);
}
Main.QueueAction(() =>
{
WorldThread.Traffic(!Main.Settings.DisableTraffic);
Function.Call(Hash.SET_ENABLE_VEHICLE_SLIPSTREAMING, true);
CoopMenu.ConnectedMenuSetting();
Main.MainChat.Init();
if (Main.Settings.Voice && !Voice.WasInitialized())
{
Voice.Init();
}
GTA.UI.Notification.Show("~g~Connected!");
});
Main.Logger.Info(">> Connected <<");
Main.Connected();
}
else
{
// Self-initiated connection
if (message.SenderConnection.RemoteHailMessage==null) { return; }
if (message.SenderConnection.RemoteHailMessage == null) { return; }
var p = message.SenderConnection.RemoteHailMessage.GetPacket<Packets.P2PConnect>();
if (PlayerList.Players.TryGetValue(p.ID,out var player))
if (PlayerList.Players.TryGetValue(p.ID, out var player))
{
player.Connection=message.SenderConnection;
player.Connection = message.SenderConnection;
Main.Logger.Debug($"Direct connection to {player.Username} established");
}
else
@ -108,28 +93,16 @@ namespace RageCoop.Client
}
break;
case NetConnectionStatus.Disconnected:
if (message.SenderConnection==ServerConnection)
if (message.SenderConnection == ServerConnection)
{
Memory.RestorePatches();
DownloadManager.Cleanup();
if (Main.MainChat.Focused)
{
Main.MainChat.Focused = false;
}
Main.QueueAction(() => Main.CleanUp());
CoopMenu.DisconnectedMenuSetting();
Main.Logger.Info($">> Disconnected << reason: {reason}");
Main.QueueAction(() => GTA.UI.Notification.Show("~r~Disconnected: " + reason));
Main.Resources.Unload();
Main.Disconnected(reason);
}
break;
}
break;
case NetIncomingMessageType.Data:
{
if (message.LengthBytes==0) { break; }
if (message.LengthBytes == 0) { break; }
var packetType = PacketType.Unknown;
try
{
@ -142,7 +115,7 @@ namespace RageCoop.Client
int id = message.ReadInt32();
if (PendingResponses.TryGetValue(id, out var callback))
{
callback((PacketType)message.ReadByte(), message.ReadBytes(message.ReadInt32()));
callback((PacketType)message.ReadByte(), message);
PendingResponses.Remove(id);
}
break;
@ -151,57 +124,60 @@ namespace RageCoop.Client
{
int id = message.ReadInt32();
var realType = (PacketType)message.ReadByte();
int len = message.ReadInt32();
if (RequestHandlers.TryGetValue(realType, out var handler))
{
var response = Peer.CreateMessage();
response.Write((byte)PacketType.Response);
response.Write(id);
handler(message.ReadBytes(len)).Pack(response);
Peer.SendMessage(response,ServerConnection, NetDeliveryMethod.ReliableOrdered, message.SequenceChannel);
handler(message).Pack(response);
Peer.SendMessage(response, ServerConnection, NetDeliveryMethod.ReliableOrdered, message.SequenceChannel);
Peer.FlushSendQueue();
}
else
{
Main.Logger.Debug("Did not find a request handler of type: " + realType);
}
break;
}
default:
{
byte[] data = message.ReadBytes(message.ReadInt32());
HandlePacket(packetType, data,message.SenderConnection);
HandlePacket(packetType, message, message.SenderConnection, ref _recycle);
break;
}
}
}
catch (Exception ex)
{
#if DEBUG
Main.QueueAction(() =>
{
GTA.UI.Notification.Show("~r~~h~Packet Error");
GTA.UI.Notification.Show($"~r~~h~Packet Error {ex.Message}");
return true;
});
Main.Logger.Error($"[{packetType}] {ex.Message}");
Main.Logger.Error(ex);
Peer.Shutdown($"Packet Error [{packetType}]");
#endif
_recycle = false;
}
break;
}
case NetIncomingMessageType.UnconnectedData:
{
var packetType = (PacketType)message.ReadByte();
int len = message.ReadInt32();
byte[] data = message.ReadBytes(len);
switch (packetType)
{
case PacketType.HolePunch:
{
HolePunch.Punched(data.GetPacket<Packets.HolePunch>(), message.SenderEndPoint);
HolePunch.Punched(message.GetPacket<Packets.HolePunch>(), message.SenderEndPoint);
break;
}
case PacketType.PublicKeyResponse:
{
if(message.SenderEndPoint.ToString()!=_targetServerEP.ToString() ||!IsConnecting){break;}
var packet = data.GetPacket<Packets.PublicKeyResponse>();
if (message.SenderEndPoint.ToString() != _targetServerEP.ToString() || !IsConnecting) { break; }
var packet = message.GetPacket<Packets.PublicKeyResponse>();
Security.SetServerPublicKey(packet.Modulus, packet.Exponent);
_publicKeyReceived.Set();
break;
@ -218,41 +194,42 @@ namespace RageCoop.Client
default:
break;
}
Peer.Recycle(message);
if (_recycle)
{
Peer.Recycle(message);
}
}
private static void HandlePacket(PacketType packetType, byte[] data, NetConnection senderConnection)
private static void HandlePacket(PacketType packetType, NetIncomingMessage msg, NetConnection senderConnection, ref bool recycle)
{
switch (packetType)
{
case PacketType.HolePunchInit:
HolePunch.Add(data.GetPacket<Packets.HolePunchInit>());
HolePunch.Add(msg.GetPacket<Packets.HolePunchInit>());
break;
case PacketType.PlayerConnect:
PlayerConnect(data.GetPacket<Packets.PlayerConnect>());
PlayerConnect(msg.GetPacket<Packets.PlayerConnect>());
break;
case PacketType.PlayerDisconnect:
PlayerDisconnect(data.GetPacket<Packets.PlayerDisconnect>());
PlayerDisconnect(msg.GetPacket<Packets.PlayerDisconnect>());
break;
case PacketType.PlayerInfoUpdate:
PlayerList.UpdatePlayer(data.GetPacket<Packets.PlayerInfoUpdate>());
PlayerList.UpdatePlayer(msg.GetPacket<Packets.PlayerInfoUpdate>());
break;
case PacketType.VehicleSync:
ReceivedPackets.VehicelPacket.Deserialize(data);
ReceivedPackets.VehicelPacket.Deserialize(msg);
VehicleSync(ReceivedPackets.VehicelPacket);
break;
case PacketType.PedSync:
ReceivedPackets.PedPacket.Deserialize(data);
ReceivedPackets.PedPacket.Deserialize(msg);
PedSync(ReceivedPackets.PedPacket);
break;
case PacketType.ProjectileSync:
ReceivedPackets.ProjectilePacket.Deserialize(data);
ReceivedPackets.ProjectilePacket.Deserialize(msg);
ProjectileSync(ReceivedPackets.ProjectilePacket);
break;
@ -260,7 +237,7 @@ namespace RageCoop.Client
{
Packets.ChatMessage packet = new Packets.ChatMessage((b) => Security.Decrypt(b));
packet.Deserialize(data);
packet.Deserialize(msg);
Main.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message); return true; });
}
@ -271,7 +248,7 @@ namespace RageCoop.Client
if (Main.Settings.Voice)
{
Packets.Voice packet = new Packets.Voice();
packet.Deserialize(data);
packet.Deserialize(msg);
SyncedPed player = EntityPool.GetPedByID(packet.ID);
@ -286,18 +263,20 @@ namespace RageCoop.Client
case PacketType.CustomEvent:
{
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
packet.Deserialize(data);
packet.Deserialize(msg);
Scripting.API.Events.InvokeCustomEventReceived(packet);
}
break;
case PacketType.CustomEventQueued:
{
recycle = false;
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
Main.QueueAction(() =>
{
packet.Deserialize(data);
packet.Deserialize(msg);
Scripting.API.Events.InvokeCustomEventReceived(packet);
Peer.Recycle(msg);
});
}
break;
@ -305,7 +284,7 @@ namespace RageCoop.Client
case PacketType.FileTransferChunk:
{
Packets.FileTransferChunk packet = new Packets.FileTransferChunk();
packet.Deserialize(data);
packet.Deserialize(msg);
DownloadManager.Write(packet.ID, packet.FileChunk);
}
break;
@ -313,8 +292,9 @@ namespace RageCoop.Client
default:
if (packetType.IsSyncEvent())
{
recycle = false;
// Dispatch to script thread
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, data); return true; });
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, msg); return true; });
}
break;
}
@ -323,34 +303,36 @@ namespace RageCoop.Client
private static void PedSync(Packets.PedSync packet)
{
SyncedPed c = EntityPool.GetPedByID(packet.ID);
if (c==null)
if (c == null)
{
// Main.Logger.Debug($"Creating character for incoming sync:{packet.ID}");
EntityPool.ThreadSafe.Add(c=new SyncedPed(packet.ID));
if (EntityPool.allPeds.Length < Main.Settings.GlobalPedSoftLimit || PlayerList.Players.ContainsKey(packet.ID))
EntityPool.ThreadSafe.Add(c = new SyncedPed(packet.ID));
else return;
}
PedDataFlags flags = packet.Flags;
c.ID=packet.ID;
c.OwnerID=packet.OwnerID;
c.ID = packet.ID;
c.OwnerID = packet.OwnerID;
c.Health = packet.Health;
c.Rotation = packet.Rotation;
c.Velocity = packet.Velocity;
c.Speed = packet.Speed;
c.Flags=packet.Flags;
c.Heading=packet.Heading;
c.Flags = packet.Flags;
c.Heading = packet.Heading;
c.Position = packet.Position;
c.LastSyncedStopWatch.Restart();
if (c.IsRagdoll)
{
c.HeadPosition=packet.HeadPosition;
c.RightFootPosition=packet.RightFootPosition;
c.LeftFootPosition=packet.LeftFootPosition;
c.HeadPosition = packet.HeadPosition;
c.RightFootPosition = packet.RightFootPosition;
c.LeftFootPosition = packet.LeftFootPosition;
}
else if (c.Speed>=4)
else if (c.Speed >= 4)
{
c.VehicleID=packet.VehicleID;
c.Seat=packet.Seat;
c.VehicleID = packet.VehicleID;
c.Seat = packet.Seat;
}
c.LastSynced = Main.Ticked;
c.LastSynced = Main.Ticked;
if (c.IsAiming)
{
c.AimCoords = packet.AimCoords;
@ -358,13 +340,13 @@ namespace RageCoop.Client
if (packet.Flags.HasPedFlag(PedDataFlags.IsFullSync))
{
c.CurrentWeaponHash = packet.CurrentWeaponHash;
c.Clothes=packet.Clothes;
c.WeaponComponents=packet.WeaponComponents;
c.WeaponTint=packet.WeaponTint;
c.Model=packet.ModelHash;
c.BlipColor=packet.BlipColor;
c.BlipSprite=packet.BlipSprite;
c.BlipScale=packet.BlipScale;
c.Clothes = packet.Clothes;
c.WeaponComponents = packet.WeaponComponents;
c.WeaponTint = packet.WeaponTint;
c.Model = packet.ModelHash;
c.BlipColor = packet.BlipColor;
c.BlipSprite = packet.BlipSprite;
c.BlipScale = packet.BlipScale;
c.LastFullSynced = Main.Ticked;
}
@ -372,58 +354,63 @@ namespace RageCoop.Client
private static void VehicleSync(Packets.VehicleSync packet)
{
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
if (v==null)
if (v == null)
{
EntityPool.ThreadSafe.Add(v=new SyncedVehicle(packet.ID));
if (EntityPool.allVehicles.Length < Main.Settings.GlobalVehicleSoftLimit)
EntityPool.ThreadSafe.Add(v = new SyncedVehicle(packet.ID));
else return;
}
if (v.IsLocal) { return; }
v.ID= packet.ID;
v.OwnerID= packet.OwnerID;
v.Flags=packet.Flags;
v.Position=packet.Position;
v.Quaternion=packet.Quaternion;
v.SteeringAngle=packet.SteeringAngle;
v.ThrottlePower=packet.ThrottlePower;
v.BrakePower=packet.BrakePower;
v.Velocity=packet.Velocity;
v.RotationVelocity=packet.RotationVelocity;
v.DeluxoWingRatio=packet.DeluxoWingRatio;
v.LastSynced=Main.Ticked;
v.ID = packet.ID;
v.OwnerID = packet.OwnerID;
v.Flags = packet.Flags;
v.Position = packet.Position;
v.Quaternion = packet.Quaternion;
v.SteeringAngle = packet.SteeringAngle;
v.ThrottlePower = packet.ThrottlePower;
v.BrakePower = packet.BrakePower;
v.Velocity = packet.Velocity;
v.RotationVelocity = packet.RotationVelocity;
v.DeluxoWingRatio = packet.DeluxoWingRatio;
v.LastSynced = Main.Ticked;
v.LastSyncedStopWatch.Restart();
if (packet.Flags.HasVehFlag(VehicleDataFlags.IsFullSync))
{
v.DamageModel=packet.DamageModel;
v.EngineHealth=packet.EngineHealth;
v.Mods=packet.Mods;
v.Model=packet.ModelHash;
v.Colors=packet.Colors;
v.LandingGear=packet.LandingGear;
v.RoofState=(VehicleRoofState)packet.RoofState;
v.LockStatus=packet.LockStatus;
v.RadioStation=packet.RadioStation;
v.LicensePlate=packet.LicensePlate;
v.Livery=packet.Livery;
v.LastFullSynced= Main.Ticked;
v.DamageModel = packet.DamageModel;
v.EngineHealth = packet.EngineHealth;
v.Mods = packet.Mods;
v.Model = packet.ModelHash;
v.Colors = packet.Colors;
v.LandingGear = packet.LandingGear;
v.RoofState = (VehicleRoofState)packet.RoofState;
v.LockStatus = packet.LockStatus;
v.RadioStation = packet.RadioStation;
v.LicensePlate = packet.LicensePlate;
v.Livery = packet.Livery;
v.LastFullSynced = Main.Ticked;
}
}
private static void ProjectileSync(Packets.ProjectileSync packet)
{
var p = EntityPool.GetProjectileByID(packet.ID);
if (p==null)
if (p == null)
{
if (packet.Flags.HasProjDataFlag(ProjectileDataFlags.Exploded)) { return; }
// Main.Logger.Debug($"Creating new projectile: {(WeaponHash)packet.WeaponHash}");
EntityPool.ThreadSafe.Add(p=new SyncedProjectile(packet.ID));
if (EntityPool.allProjectiles.Length < Main.Settings.GlobalProjectileSoftLimit)
EntityPool.ThreadSafe.Add(p = new SyncedProjectile(packet.ID));
else return;
}
p.Flags=packet.Flags;
p.Position=packet.Position;
p.Rotation=packet.Rotation;
p.Velocity=packet.Velocity;
p.WeaponHash=(WeaponHash)packet.WeaponHash;
p.Shooter= packet.Flags.HasProjDataFlag(ProjectileDataFlags.IsShotByVehicle) ?
p.Flags = packet.Flags;
p.Position = packet.Position;
p.Rotation = packet.Rotation;
p.Velocity = packet.Velocity;
p.WeaponHash = (WeaponHash)packet.WeaponHash;
p.Shooter = packet.Flags.HasProjDataFlag(ProjectileDataFlags.IsShotByVehicle) ?
(SyncedEntity)EntityPool.GetVehicleByID(packet.ShooterID) : EntityPool.GetPedByID(packet.ShooterID);
p.LastSynced=Main.Ticked;
p.LastSynced = Main.Ticked;
p.LastSyncedStopWatch.Restart();
}
}
}

View File

@ -13,7 +13,7 @@ namespace RageCoop.Client
/// <summary>
/// Reduce GC pressure by reusing frequently used packets
/// </summary>
static class SendPackets
private static class SendPackets
{
public static Packets.PedSync PedPacket = new Packets.PedSync();
public static Packets.VehicleSync VehicelPacket = new Packets.VehicleSync();
@ -28,50 +28,50 @@ namespace RageCoop.Client
public static void SendPed(SyncedPed sp, bool full)
{
if (sp.LastSentStopWatch.ElapsedMilliseconds<SyncInterval)
if (sp.LastSentStopWatch.ElapsedMilliseconds < SyncInterval)
{
return;
}
Ped ped = sp.MainPed;
var p = SendPackets.PedPacket;
p.ID =sp.ID;
p.OwnerID=sp.OwnerID;
p.ID = sp.ID;
p.OwnerID = sp.OwnerID;
p.Health = ped.Health;
p.Rotation = ped.ReadRotation();
p.Velocity = ped.ReadVelocity();
p.Speed = ped.GetPedSpeed();
p.Flags = ped.GetPedFlags();
p.Heading=ped.Heading;
p.Heading = ped.Heading;
if (p.Flags.HasPedFlag(PedDataFlags.IsAiming))
{
p.AimCoords = ped.GetAimCoord();
}
if (p.Flags.HasPedFlag(PedDataFlags.IsRagdoll))
{
p.HeadPosition=ped.Bones[Bone.SkelHead].Position;
p.RightFootPosition=ped.Bones[Bone.SkelRightFoot].Position;
p.LeftFootPosition=ped.Bones[Bone.SkelLeftFoot].Position;
p.HeadPosition = ped.Bones[Bone.SkelHead].Position;
p.RightFootPosition = ped.Bones[Bone.SkelRightFoot].Position;
p.LeftFootPosition = ped.Bones[Bone.SkelLeftFoot].Position;
}
else
{
// Seat sync
if (p.Speed>=4)
if (p.Speed >= 4)
{
var veh = ped.CurrentVehicle?.GetSyncEntity() ?? ped.VehicleTryingToEnter?.GetSyncEntity() ?? ped.LastVehicle?.GetSyncEntity();
p.VehicleID = veh?.ID ?? 0;
if (p.VehicleID==0) { Main.Logger.Error("Invalid vehicle"); }
if (p.Speed==5)
if (p.VehicleID == 0) { Main.Logger.Error("Invalid vehicle"); }
if (p.Speed == 5)
{
p.Seat=ped.GetSeatTryingToEnter();
p.Seat = ped.GetSeatTryingToEnter();
}
else
{
p.Seat=ped.SeatIndex;
p.Seat = ped.SeatIndex;
}
if (!veh.IsLocal && p.Speed==4 && p.Seat==VehicleSeat.Driver)
if (!veh.IsLocal && p.Speed == 4 && p.Seat == VehicleSeat.Driver)
{
veh.OwnerID=Main.LocalPlayerID;
SyncEvents.TriggerChangeOwner(veh.ID,Main.LocalPlayerID);
veh.OwnerID = Main.LocalPlayerID;
SyncEvents.TriggerChangeOwner(veh.ID, Main.LocalPlayerID);
}
}
p.Position = ped.ReadPosition();
@ -80,57 +80,57 @@ namespace RageCoop.Client
if (full)
{
var w = ped.VehicleWeapon;
p.CurrentWeaponHash = (w!=VehicleWeaponHash.Invalid)? (uint)w:(uint)ped.Weapons.Current.Hash;
p.CurrentWeaponHash = (w != VehicleWeaponHash.Invalid) ? (uint)w : (uint)ped.Weapons.Current.Hash;
p.Flags |= PedDataFlags.IsFullSync;
p.Clothes=ped.GetPedClothes();
p.ModelHash=ped.Model.Hash;
p.WeaponComponents=ped.Weapons.Current.GetWeaponComponents();
p.WeaponTint=(byte)Function.Call<int>(Hash.GET_PED_WEAPON_TINT_INDEX, ped, ped.Weapons.Current.Hash);
p.Clothes = ped.GetPedClothes();
p.ModelHash = ped.Model.Hash;
p.WeaponComponents = ped.Weapons.Current.GetWeaponComponents();
p.WeaponTint = (byte)Function.Call<int>(Hash.GET_PED_WEAPON_TINT_INDEX, ped, ped.Weapons.Current.Hash);
Blip b;
if (sp.IsPlayer)
{
p.BlipColor=Scripting.API.Config.BlipColor;
p.BlipSprite=Scripting.API.Config.BlipSprite;
p.BlipScale=Scripting.API.Config.BlipScale;
p.BlipColor = Scripting.API.Config.BlipColor;
p.BlipSprite = Scripting.API.Config.BlipSprite;
p.BlipScale = Scripting.API.Config.BlipScale;
}
else if ((b = ped.AttachedBlip) !=null)
else if ((b = ped.AttachedBlip) != null)
{
p.BlipColor=b.Color;
p.BlipSprite=b.Sprite;
p.BlipColor = b.Color;
p.BlipSprite = b.Sprite;
if (p.BlipSprite==BlipSprite.PoliceOfficer || p.BlipSprite==BlipSprite.PoliceOfficer2)
if (p.BlipSprite == BlipSprite.PoliceOfficer || p.BlipSprite == BlipSprite.PoliceOfficer2)
{
p.BlipScale=0.5f;
p.BlipScale = 0.5f;
}
}
else
{
p.BlipColor=(BlipColor)255;
p.BlipColor = (BlipColor)255;
}
}
SendSync(p, ConnectionChannel.PedSync);
}
public static void SendVehicle(SyncedVehicle v, bool full)
{
if (v.LastSentStopWatch.ElapsedMilliseconds<SyncInterval)
if (v.LastSentStopWatch.ElapsedMilliseconds < SyncInterval)
{
return;
}
Vehicle veh = v.MainVehicle;
var packet = SendPackets.VehicelPacket;
packet.ID =v.ID;
packet.OwnerID=v.OwnerID;
packet.ID = v.ID;
packet.OwnerID = v.OwnerID;
packet.Flags = v.GetVehicleFlags();
packet.SteeringAngle = veh.SteeringAngle;
packet.Position = veh.ReadPosition();
packet.Velocity=veh.Velocity;
packet.Quaternion=veh.ReadQuaternion();
packet.RotationVelocity=veh.RotationVelocity;
packet.Velocity = veh.Velocity;
packet.Quaternion = veh.ReadQuaternion();
packet.RotationVelocity = veh.RotationVelocity;
packet.ThrottlePower = veh.ThrottlePower;
packet.BrakePower = veh.BrakePower;
v.LastSentStopWatch.Restart();
if (packet.Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering)) { packet.DeluxoWingRatio=v.MainVehicle.GetDeluxoWingRatio(); }
if (packet.Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering)) { packet.DeluxoWingRatio = v.MainVehicle.GetDeluxoWingRatio(); }
if (full)
{
byte primaryColor = 0;
@ -141,24 +141,24 @@ namespace RageCoop.Client
}
packet.Flags |= VehicleDataFlags.IsFullSync;
packet.Colors = new byte[] { primaryColor, secondaryColor };
packet.DamageModel=veh.GetVehicleDamageModel();
packet.DamageModel = veh.GetVehicleDamageModel();
packet.LandingGear = veh.IsAircraft ? (byte)veh.LandingGearState : (byte)0;
packet.RoofState=(byte)veh.RoofState;
packet.RoofState = (byte)veh.RoofState;
packet.Mods = veh.Mods.GetVehicleMods();
packet.ModelHash=veh.Model.Hash;
packet.EngineHealth=veh.EngineHealth;
packet.LockStatus=veh.LockStatus;
packet.LicensePlate=Function.Call<string>(Hash.GET_VEHICLE_NUMBER_PLATE_TEXT, veh);
packet.Livery=Function.Call<int>(Hash.GET_VEHICLE_LIVERY, veh);
if (v.MainVehicle==Game.Player.LastVehicle)
packet.ModelHash = veh.Model.Hash;
packet.EngineHealth = veh.EngineHealth;
packet.LockStatus = veh.LockStatus;
packet.LicensePlate = Function.Call<string>(Hash.GET_VEHICLE_NUMBER_PLATE_TEXT, veh);
packet.Livery = Function.Call<int>(Hash.GET_VEHICLE_LIVERY, veh);
if (v.MainVehicle == Game.Player.LastVehicle)
{
packet.RadioStation=Util.GetPlayerRadioIndex();
packet.RadioStation = Util.GetPlayerRadioIndex();
}
if (packet.EngineHealth>v.LastEngineHealth)
if (packet.EngineHealth > v.LastEngineHealth)
{
packet.Flags |= VehicleDataFlags.Repaired;
}
v.LastEngineHealth=packet.EngineHealth;
v.LastEngineHealth = packet.EngineHealth;
}
SendSync(packet, ConnectionChannel.VehicleSync);
}
@ -178,25 +178,25 @@ namespace RageCoop.Client
StartPosition = start,
EndPosition = end,
OwnerID = ownerID,
WeaponHash=weapon,
WeaponHash = weapon,
}, ConnectionChannel.SyncEvents);
}
public static void SendVehicleBullet(uint hash,SyncedPed owner,EntityBone b)
public static void SendVehicleBullet(uint hash, SyncedPed owner, EntityBone b)
{
SendSync(new Packets.VehicleBulletShot
{
StartPosition = b.Position,
EndPosition = b.Position+b.ForwardVector,
OwnerID=owner.ID,
Bone=(ushort)b.Index,
WeaponHash=hash
EndPosition = b.Position + b.ForwardVector,
OwnerID = owner.ID,
Bone = (ushort)b.Index,
WeaponHash = hash
});
}
#endregion
public static void SendChatMessage(string message)
{
Peer.SendTo(new Packets.ChatMessage(new Func<string, byte[]>((s) => Security.Encrypt(s.GetBytes())))
{ Username = Main.Settings.Username, Message = message },ServerConnection, ConnectionChannel.Chat, NetDeliveryMethod.ReliableOrdered);
{ Username = Main.Settings.Username, Message = message }, ServerConnection, ConnectionChannel.Chat, NetDeliveryMethod.ReliableOrdered);
Peer.FlushSendQueue();
}
public static void SendVoiceMessage(byte[] buffer, int recorded)

View File

@ -16,8 +16,8 @@ namespace RageCoop.Client
var bu = Networking.Peer.Statistics.SentBytes;
var bd = Networking.Peer.Statistics.ReceivedBytes;
Thread.Sleep(1000);
BytesUpPerSecond=Networking.Peer.Statistics.SentBytes-bu;
BytesDownPerSecond=Networking.Peer.Statistics.ReceivedBytes-bd;
BytesUpPerSecond = Networking.Peer.Statistics.SentBytes - bu;
BytesDownPerSecond = Networking.Peer.Statistics.ReceivedBytes - bd;
}
});
}

View File

@ -1,11 +1,11 @@
using GTA;
using GTA.Math;
using GTA.Native;
using Lidgren.Network;
using RageCoop.Core;
using System.Collections.Generic;
using Lidgren.Network;
using System.Net;
using System.Linq;
using System.Net;
namespace RageCoop.Client
{
@ -50,11 +50,11 @@ namespace RageCoop.Client
_mainScaleform.CallFunction("SET_DATA_SLOT_EMPTY", 0);
int i=0;
int i = 0;
foreach (var player in Players.Values)
{
_mainScaleform.CallFunction("SET_DATA_SLOT", i++, $"{player.Ping * 1000:N0}ms", player.Username+(player.IsHost ? " (Host)" : ""), 116, 0, i - 1, "", "", 2, "", "", ' ');
_mainScaleform.CallFunction("SET_DATA_SLOT", i++, $"{player.Ping * 1000:N0}ms", player.Username + (player.IsHost ? " (Host)" : ""), 116, 0, i - 1, "", "", 2, "", "", ' ');
}
_mainScaleform.CallFunction("SET_TITLE", "Player list", $"{Players.Count} players");
@ -63,34 +63,33 @@ namespace RageCoop.Client
public static void SetPlayer(int id, string username, float latency = 0)
{
Main.Logger.Debug($"{id},{username},{latency}");
Player p;
if (Players.TryGetValue(id, out p))
if (Players.TryGetValue(id, out Player p))
{
p.Username=username;
p.PedID=id;
p._latencyToServer=latency;
p.Username = username;
p.ID = id;
p._latencyToServer = latency;
}
else
{
p = new Player { PedID=id, Username=username, _latencyToServer=latency };
p = new Player { ID = id, Username = username, _latencyToServer = latency };
Players.Add(id, p);
}
}
public static void UpdatePlayer(Packets.PlayerInfoUpdate packet)
{
var p = GetPlayer(packet.PedID);
if (p!=null)
if (p != null)
{
p._latencyToServer = packet.Latency;
p.Position = packet.Position;
p.IsHost= packet.IsHost;
p.IsHost = packet.IsHost;
Main.QueueAction(() =>
{
if (p.FakeBlip?.Exists()!=true)
if (p.FakeBlip?.Exists() != true)
{
p.FakeBlip=World.CreateBlip(p.Position);
p.FakeBlip = World.CreateBlip(p.Position);
}
if (EntityPool.PedExists(p.PedID))
if (EntityPool.PedExists(p.ID))
{
p.FakeBlip.DisplayType = BlipDisplayType.NoDisplay;
}
@ -108,22 +107,21 @@ namespace RageCoop.Client
}
public static Player GetPlayer(int id)
{
Player p;
Players.TryGetValue(id, out p);
Players.TryGetValue(id, out Player p);
return p;
}
public static Player GetPlayer(SyncedPed p)
{
var player = GetPlayer(p.ID);
if (player!=null)
if (player != null)
{
player.Character=p;
player.Character = p;
}
return player;
}
public static void RemovePlayer(int id)
{
if (Players.TryGetValue(id,out var player))
if (Players.TryGetValue(id, out var player))
{
Players.Remove(id);
Main.QueueAction(() => player.FakeBlip?.Delete());
@ -131,40 +129,40 @@ namespace RageCoop.Client
}
public static void Cleanup()
{
foreach(var p in Players.Values.ToArray())
foreach (var p in Players.Values.ToArray())
{
p.FakeBlip?.Delete();
}
Players=new Dictionary<int, Player> { };
Players = new Dictionary<int, Player> { };
}
}
internal class Player
public class Player
{
public byte HolePunchStatus { get; set; } = 1;
public bool IsHost;
public byte HolePunchStatus { get; internal set; } = 1;
public bool IsHost { get; internal set; }
public string Username { get; internal set; }
/// <summary>
/// Universal character ID.
/// Universal ped ID.
/// </summary>
public int PedID
public int ID
{
get; internal set;
}
public IPEndPoint InternalEndPoint { get; set; }
public IPEndPoint ExternalEndPoint { get; set; }
public bool ConnectWhenPunched { get; set; }
public Blip FakeBlip { get; set; }
public Vector3 Position { get; set; }
public SyncedPed Character { get; set; }
public IPEndPoint InternalEndPoint { get; internal set; }
public IPEndPoint ExternalEndPoint { get; internal set; }
internal bool ConnectWhenPunched { get; set; }
public Blip FakeBlip { get; internal set; }
public Vector3 Position { get; internal set; }
public SyncedPed Character { get; internal set; }
/// <summary>
/// Player round-trip time in seconds, will be the latency to server if not using P2P connection.
/// Player round-trip time in seconds, will be the rtt to server if not using P2P connection.
/// </summary>
public float Ping => Main.LocalPlayerID==PedID ? Networking.Latency*2 : (HasDirectConnection ? Connection.AverageRoundtripTime : _latencyToServer*2);
public float PacketTravelTime => HasDirectConnection ? Connection.AverageRoundtripTime/2 : Networking.Latency+_latencyToServer;
public float _latencyToServer = 0;
public float Ping => Main.LocalPlayerID == ID ? Networking.Latency * 2 : (HasDirectConnection ? Connection.AverageRoundtripTime : _latencyToServer * 2);
public float PacketTravelTime => HasDirectConnection ? Connection.AverageRoundtripTime / 2 : Networking.Latency + _latencyToServer;
internal float _latencyToServer = 0;
public bool DisplayNameTag { get; set; } = true;
public NetConnection Connection { get; set; }
public bool HasDirectConnection => Connection?.Status==NetConnectionStatus.Connected;
public NetConnection Connection { get; internal set; }
public bool HasDirectConnection => Connection?.Status == NetConnectionStatus.Connected;
}
}

View File

@ -15,8 +15,8 @@ using System.Resources;
[assembly: AssemblyCulture("")]
// Version informationr(
[assembly: AssemblyVersion("1.5.3.124")]
[assembly: AssemblyFileVersion("1.5.3.124")]
// Version information
[assembly: AssemblyVersion("1.5.4.6")]
[assembly: AssemblyFileVersion("1.5.4.6")]
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]

View File

@ -21,6 +21,7 @@
<OutPutPath>..\bin\Debug\Client</OutPutPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>DEBUG</DefineConstants>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<OutPutPath>..\bin\Release\Client</OutPutPath>
@ -35,7 +36,6 @@
<Compile Include="Menus\Sub\DevToolMenu.cs" />
<Compile Include="Menus\Sub\ServersMenu.cs" />
<Compile Include="Menus\Sub\SettingsMenu.cs" />
<Compile Include="Menus\Sub\UpdateMenu.cs" />
<Compile Include="Networking\Chat.cs" />
<Compile Include="Networking\DownloadManager.cs" />
<Compile Include="Networking\HolePunch.cs" />
@ -55,6 +55,7 @@
<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" />
@ -65,6 +66,7 @@
<Compile Include="Sync\EntityPool.cs" />
<Compile Include="Sync\SyncEvents.cs" />
<Compile Include="Sync\Voice.cs" />
<Compile Include="Util\AddOnDataProvider.cs" />
<Compile Include="Util\Memory.cs" />
<Compile Include="Util\NativeCaller.cs" />
<Compile Include="Util\PedConfigFlags.cs" />
@ -88,7 +90,7 @@
<Reference Include="ICSharpCode.SharpZipLib, Version=1.3.3.11, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.1.3.3\lib\net45\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="LemonUI.SHVDN3, Version=1.7.0.0, Culture=neutral, processorArchitecture=AMD64">
<Reference Include="LemonUI.SHVDN3, Version=1.10.0.0, Culture=neutral, processorArchitecture=AMD64">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\libs\LemonUI.SHVDN3.dll</HintPath>
</Reference>

View File

@ -1,5 +1,6 @@
#undef DEBUG
using GTA;
using Newtonsoft.Json;
using RageCoop.Core;
using System;
using System.Collections.Generic;
@ -39,7 +40,7 @@ namespace RageCoop.Client.Scripting
/// </summary>
public static string Username
{
get { return Main.Settings.Username; }
get => Main.Settings.Username;
set
{
if (Networking.IsOnServer || string.IsNullOrEmpty(value))
@ -90,7 +91,7 @@ namespace RageCoop.Client.Scripting
/// <summary>
/// The local player is dead
/// </summary>
public static event EmptyEvent OnPlayerDied;
public static event EventHandler<string> OnPlayerDied;
/// <summary>
/// A local vehicle is spawned
@ -132,7 +133,7 @@ namespace RageCoop.Client.Scripting
internal static void InvokeVehicleDeleted(SyncedVehicle v) { OnVehicleDeleted?.Invoke(null, v); }
internal static void InvokePedSpawned(SyncedPed p) { OnPedSpawned?.Invoke(null, p); }
internal static void InvokePedDeleted(SyncedPed p) { OnPedDeleted?.Invoke(null, p); }
internal static void InvokePlayerDied() { OnPlayerDied?.Invoke(); }
internal static void InvokePlayerDied(string m) { OnPlayerDied?.Invoke(null, m); }
internal static void InvokeTick() { OnTick?.Invoke(); }
internal static void InvokeKeyDown(object s, KeyEventArgs e) { OnKeyDown?.Invoke(s, e); }
@ -141,12 +142,11 @@ namespace RageCoop.Client.Scripting
internal static void InvokeCustomEventReceived(Packets.CustomEvent p)
{
var args = new CustomEventReceivedArgs() { Hash=p.Hash, Args=p.Args };
var args = new CustomEventReceivedArgs() { Hash = p.Hash, Args = p.Args };
// Main.Logger.Debug($"CustomEvent:\n"+args.Args.DumpWithType());
List<Action<CustomEventReceivedArgs>> handlers;
if (CustomEventHandlers.TryGetValue(p.Hash, out handlers))
if (CustomEventHandlers.TryGetValue(p.Hash, out List<Action<CustomEventReceivedArgs>> handlers))
{
handlers.ForEach((x) => { x.Invoke(args); });
}
@ -160,65 +160,48 @@ namespace RageCoop.Client.Scripting
/// Get the local player's ID
/// </summary>
/// <returns>PlayerID</returns>
public static int LocalPlayerID
{
get { return Main.LocalPlayerID; }
}
public static int LocalPlayerID => Main.LocalPlayerID;
/// <summary>
/// Check if player is connected to a server
/// </summary>
public static bool IsOnServer { get { return Networking.IsOnServer; } }
public static bool IsOnServer => Networking.IsOnServer;
/// <summary>
/// Get an <see cref="System.Net.IPEndPoint"/> that the player is currently connected to, or null if not connected to the server
/// </summary>
public static System.Net.IPEndPoint ServerEndPoint { get { return Networking.IsOnServer ? Networking.ServerConnection?.RemoteEndPoint : null; } }
public static System.Net.IPEndPoint ServerEndPoint => Networking.IsOnServer ? Networking.ServerConnection?.RemoteEndPoint : null;
/// <summary>
/// Check if a RAGECOOP menu is visible
/// </summary>
public static bool IsMenuVisible
{
get { return Menus.CoopMenu.MenuPool.AreAnyVisible; }
}
public static bool IsMenuVisible => Menus.CoopMenu.MenuPool.AreAnyVisible;
/// <summary>
/// Check if the RAGECOOP chat is visible
/// </summary>
public static bool IsChatFocused
{
get { return Main.MainChat.Focused; }
}
public static bool IsChatFocused => Main.MainChat.Focused;
/// <summary>
/// Check if the RAGECOOP list of players is visible
/// </summary>
public static bool IsPlayerListVisible
{
get { return Util.GetTickCount64() - PlayerList.Pressed < 5000; }
}
public static bool IsPlayerListVisible => Util.GetTickCount64() - PlayerList.Pressed < 5000;
/// <summary>
/// Get the version of RAGECOOP
/// </summary>
public static Version CurrentVersion
{
get { return Main.Version; }
}
public static Version CurrentVersion => Main.Version;
/// <summary>
/// Get a <see cref="Core.Logger"/> that RAGECOOP is currently using.
/// </summary>
/// <returns></returns>
public static Logger Logger
{
get
{
return Main.Logger;
}
}
public static Logger Logger => Main.Logger;
/// <summary>
/// Get all players indexed by their ID
/// </summary>
public static Dictionary<int, Player> Players => new Dictionary<int, Player>(PlayerList.Players);
#endregion
#region FUNCTIONS
@ -246,6 +229,15 @@ namespace RageCoop.Client.Scripting
}
}
/// <summary>
/// List all servers from master server address
/// </summary>
/// <returns></returns>
public static List<ServerInfo> ListServers()
{
return JsonConvert.DeserializeObject<List<ServerInfo>>(HttpHelper.DownloadString(Main.Settings.MasterServer));
}
/// <summary>
/// Send a local chat message to this player
/// </summary>
@ -293,9 +285,9 @@ namespace RageCoop.Client.Scripting
Networking.Peer.SendTo(new Packets.CustomEvent()
{
Args=args,
Hash=eventHash
},Networking.ServerConnection, ConnectionChannel.Event, Lidgren.Network.NetDeliveryMethod.ReliableOrdered);
Args = args,
Hash = eventHash
}, Networking.ServerConnection, ConnectionChannel.Event, Lidgren.Network.NetDeliveryMethod.ReliableOrdered);
}
/// <summary>
@ -328,17 +320,17 @@ namespace RageCoop.Client.Scripting
callback(e);
}
};
DownloadManager.DownloadCompleted+=handler;
DownloadManager.DownloadCompleted += handler;
Networking.GetResponse<Packets.FileTransferResponse>(new Packets.FileTransferRequest()
{
Name=name,
Name = name,
},
(p) =>
{
if (p.Response != FileResponse.Loaded)
{
DownloadManager.DownloadCompleted-=handler;
throw new ArgumentException("Requested file was not found on the server: "+name);
DownloadManager.DownloadCompleted -= handler;
throw new ArgumentException("Requested file was not found on the server: " + name);
}
});
}

View File

@ -14,9 +14,9 @@ namespace RageCoop.Client.Scripting
private bool _isHost = false;
public override void OnStart()
{
API.Events.OnPedDeleted+=(s, p) => { API.SendCustomEvent(CustomEvents.OnPedDeleted, p.ID); };
API.Events.OnVehicleDeleted+=(s, p) => { API.SendCustomEvent(CustomEvents.OnVehicleDeleted, p.ID); };
API.Events.OnPlayerDied+=() => { API.SendCustomEvent(CustomEvents.OnPlayerDied); };
API.Events.OnPedDeleted += (s, p) => { API.SendCustomEvent(CustomEvents.OnPedDeleted, p.ID); };
API.Events.OnVehicleDeleted += (s, p) => { API.SendCustomEvent(CustomEvents.OnVehicleDeleted, p.ID); };
API.Events.OnPlayerDied += (s, m) => { API.SendCustomEvent(CustomEvents.OnPlayerDied, m); };
API.RegisterCustomEventHandler(CustomEvents.SetAutoRespawn, SetAutoRespawn);
API.RegisterCustomEventHandler(CustomEvents.SetDisplayNameTag, SetDisplayNameTag);
@ -29,9 +29,9 @@ namespace RageCoop.Client.Scripting
API.RegisterCustomEventHandler(CustomEvents.DeleteServerBlip, DeleteServerBlip);
API.RegisterCustomEventHandler(CustomEvents.CreateVehicle, CreateVehicle);
API.RegisterCustomEventHandler(CustomEvents.UpdatePedBlip, UpdatePedBlip);
API.RegisterCustomEventHandler(CustomEvents.IsHost, (e) => { _isHost=(bool)e.Args[0]; });
API.RegisterCustomEventHandler(CustomEvents.IsHost, (e) => { _isHost = (bool)e.Args[0]; });
API.RegisterCustomEventHandler(CustomEvents.WeatherTimeSync, WeatherTimeSync);
API.RegisterCustomEventHandler(CustomEvents.OnPlayerDied, (e) => { GTA.UI.Notification.Show($"~h~{e.Args[0]}~h~ died."); });
API.RegisterCustomEventHandler(CustomEvents.OnPlayerDied, (e) => { GTA.UI.Notification.Show((string)e.Args[0]); });
Task.Run(() =>
{
while (true)
@ -46,7 +46,7 @@ namespace RageCoop.Client.Scripting
int weather1 = default(int);
int weather2 = default(int);
float percent2 = default(float);
Function.Call(Hash._GET_WEATHER_TYPE_TRANSITION, &weather1, &weather2, &percent2);
Function.Call(Hash.GET_CURR_WEATHER_STATE, &weather1, &weather2, &percent2);
API.SendCustomEvent(CustomEvents.WeatherTimeSync, time.Hours, time.Minutes, time.Seconds, weather1, weather2, percent2);
}
});
@ -59,33 +59,33 @@ namespace RageCoop.Client.Scripting
private void WeatherTimeSync(CustomEventReceivedArgs e)
{
World.CurrentTimeOfDay=new TimeSpan((int)e.Args[0], (int)e.Args[1], (int)e.Args[2]);
Function.Call(Hash._SET_WEATHER_TYPE_TRANSITION, (int)e.Args[3], (int)e.Args[4], (float)e.Args[5]);
World.CurrentTimeOfDay = new TimeSpan((int)e.Args[0], (int)e.Args[1], (int)e.Args[2]);
Function.Call(Hash.SET_CURR_WEATHER_STATE, (int)e.Args[3], (int)e.Args[4], (float)e.Args[5]);
}
private void SetDisplayNameTag(CustomEventReceivedArgs e)
{
var p = PlayerList.GetPlayer((int)e.Args[0]);
if (p != null) { p.DisplayNameTag=(bool)e.Args[1]; }
if (p != null) { p.DisplayNameTag = (bool)e.Args[1]; }
}
private void UpdatePedBlip(CustomEventReceivedArgs e)
{
var p = Entity.FromHandle((int)e.Args[0]);
if (p == null) { return; }
if (p.Handle==Game.Player.Character.Handle)
if (p.Handle == Game.Player.Character.Handle)
{
API.Config.BlipColor=(BlipColor)(byte)e.Args[1];
API.Config.BlipSprite=(BlipSprite)(ushort)e.Args[2];
API.Config.BlipScale=(float)e.Args[3];
API.Config.BlipColor = (BlipColor)(byte)e.Args[1];
API.Config.BlipSprite = (BlipSprite)(ushort)e.Args[2];
API.Config.BlipScale = (float)e.Args[3];
}
else
{
var b = p.AttachedBlip;
if (b == null) { b=p.AddBlip(); }
b.Color=(BlipColor)(byte)e.Args[1];
b.Sprite=(BlipSprite)(ushort)e.Args[2];
b.Scale=(float)e.Args[3];
if (b == null) { b = p.AddBlip(); }
b.Color = (BlipColor)(byte)e.Args[1];
b.Sprite = (BlipSprite)(ushort)e.Args[2];
b.Scale = (float)e.Args[3];
}
}
@ -94,17 +94,17 @@ namespace RageCoop.Client.Scripting
var vehicleModel = (Model)e.Args[1];
vehicleModel.Request(1000);
Vehicle veh = World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3]);
while (veh==null)
while (veh == null)
{
veh = World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3]);
veh = World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3]);
Thread.Sleep(10);
}
veh.CanPretendOccupants=false;
veh.CanPretendOccupants = false;
var v = new SyncedVehicle()
{
ID=(int)e.Args[0],
MainVehicle=veh,
OwnerID=Main.LocalPlayerID,
ID = (int)e.Args[0],
MainVehicle = veh,
OwnerID = Main.LocalPlayerID,
};
EntityPool.Add(v);
}
@ -127,10 +127,9 @@ namespace RageCoop.Client.Scripting
var pos = (Vector3)obj.Args[4];
int rot = (int)obj.Args[5];
var name = (string)obj.Args[6];
Blip blip;
if (!EntityPool.ServerBlips.TryGetValue(id, out blip))
if (!EntityPool.ServerBlips.TryGetValue(id, out Blip blip))
{
EntityPool.ServerBlips.Add(id, blip=World.CreateBlip(pos));
EntityPool.ServerBlips.Add(id, blip = World.CreateBlip(pos));
}
blip.Sprite = sprite;
blip.Color = color;
@ -152,14 +151,14 @@ namespace RageCoop.Client.Scripting
private void SetNameTag(CustomEventReceivedArgs e)
{
var p = PlayerList.GetPlayer((int)e.Args[0]);
if (p!= null)
if (p != null)
{
p.DisplayNameTag=(bool)e.Args[1];
p.DisplayNameTag = (bool)e.Args[1];
}
}
private void SetAutoRespawn(CustomEventReceivedArgs args)
{
API.Config.EnableAutoRespawn=(bool)args.Args[0];
API.Config.EnableAutoRespawn = (bool)args.Args[0];
}
private void DeleteServerProp(CustomEventReceivedArgs e)
{
@ -179,13 +178,13 @@ namespace RageCoop.Client.Scripting
{
if (!EntityPool.ServerProps.TryGetValue(id, out prop))
{
EntityPool.ServerProps.Add(id, prop=new SyncedProp(id));
EntityPool.ServerProps.Add(id, prop = new SyncedProp(id));
}
}
prop.LastSynced=Main.Ticked+1;
prop.Model= (Model)e.Args[1];
prop.Position=(Vector3)e.Args[2];
prop.Rotation=(Vector3)e.Args[3];
prop.LastSynced = Main.Ticked + 1;
prop.Model = (Model)e.Args[1];
prop.Position = (Vector3)e.Args[2];
prop.Rotation = (Vector3)e.Args[3];
prop.Update();
}
private void NativeCall(CustomEventReceivedArgs e)
@ -194,14 +193,14 @@ namespace RageCoop.Client.Scripting
int i;
var ty = (byte)e.Args[0];
TypeCode returnType = (TypeCode)ty;
i = returnType==TypeCode.Empty ? 1 : 2;
i = returnType == TypeCode.Empty ? 1 : 2;
var hash = (Hash)e.Args[i++];
for (; i<e.Args.Length; i++)
for (; i < e.Args.Length; i++)
{
arguments.Add(GetInputArgument(e.Args[i]));
}
if (returnType==TypeCode.Empty)
if (returnType == TypeCode.Empty)
{
Function.Call(hash, arguments.ToArray());
return;

View File

@ -30,7 +30,7 @@ namespace RageCoop.Client.Scripting
/// <summary>
/// Eqivalent of <see cref="ClientResource.Logger"/> in <see cref="CurrentResource"/>
/// </summary>
public Core.Logger Logger { get { return CurrentResource.Logger; } }
public Core.Logger Logger => CurrentResource.Logger;
}
}

View File

@ -38,9 +38,11 @@ namespace RageCoop.Client.Scripting
}
internal class Resources
{
private readonly List<ClientResource> LoadedResources = new List<ClientResource>();
private const string BaseScriptType = "RageCoop.Client.Scripting.ClientScript";
private Logger Logger { get; set; }
public Resources()
{
BaseScriptType = "RageCoop.Client.Scripting.ClientScript";
Logger = Main.Logger;
}
private void StartAll()
@ -53,12 +55,12 @@ namespace RageCoop.Client.Scripting
{
try
{
s.CurrentResource=d;
s.CurrentResource = d;
s.OnStart();
}
catch (Exception ex)
{
Logger.Error("Error occurred when starting script:"+s.GetType().FullName);
Logger.Error("Error occurred when starting script:" + s.GetType().FullName);
Logger?.Error(ex);
}
}
@ -79,7 +81,7 @@ namespace RageCoop.Client.Scripting
}
catch (Exception ex)
{
Logger.Error("Error occurred when stopping script:"+s.GetType().FullName);
Logger.Error("Error occurred when stopping script:" + s.GetType().FullName);
Logger?.Error(ex);
}
}
@ -106,9 +108,6 @@ namespace RageCoop.Client.Scripting
}
LoadedResources.Clear();
}
private List<ClientResource> LoadedResources = new List<ClientResource>();
private string BaseScriptType;
public Logger Logger { get; set; }
private void LoadResource(ZipFile file, string dataFolderRoot)
{
@ -117,22 +116,22 @@ namespace RageCoop.Client.Scripting
{
Logger = Main.Logger,
Scripts = new List<ClientScript>(),
Name=Path.GetFileNameWithoutExtension(file.Name),
DataFolder=Path.Combine(dataFolderRoot, Path.GetFileNameWithoutExtension(file.Name))
Name = Path.GetFileNameWithoutExtension(file.Name),
DataFolder = Path.Combine(dataFolderRoot, Path.GetFileNameWithoutExtension(file.Name))
};
Directory.CreateDirectory(r.DataFolder);
foreach (ZipEntry entry in file)
{
ResourceFile rFile;
r.Files.Add(entry.Name, rFile=new ResourceFile()
r.Files.Add(entry.Name, rFile = new ResourceFile()
{
Name=entry.Name,
IsDirectory=entry.IsDirectory,
Name = entry.Name,
IsDirectory = entry.IsDirectory,
});
if (!entry.IsDirectory)
{
rFile.GetStream=() => { return file.GetInputStream(entry); };
rFile.GetStream = () => { return file.GetInputStream(entry); };
if (entry.Name.EndsWith(".dll") && !entry.Name.Contains("/"))
{
// Don't load API assembly
@ -145,12 +144,12 @@ namespace RageCoop.Client.Scripting
{
continue;
}
var asm=Assembly.LoadFrom(tmp);
toLoad.Add(() => LoadScriptsFromAssembly(rFile,asm, entry.Name,r));
var asm = Assembly.LoadFrom(tmp);
toLoad.Add(() => LoadScriptsFromAssembly(rFile, asm, entry.Name, r));
}
}
}
foreach(var a in toLoad)
foreach (var a in toLoad)
{
a();
}
@ -174,8 +173,8 @@ namespace RageCoop.Client.Scripting
// Invoke script constructor
var script = constructor.Invoke(null) as ClientScript;
// script.CurrentResource = toload;
script.CurrentFile=rfile;
script.CurrentResource=toload;
script.CurrentFile = rfile;
script.CurrentResource = toload;
toload.Scripts.Add(script);
count++;
}

View File

@ -7,7 +7,7 @@ namespace RageCoop.Client
{
public RSA ServerRSA { get; set; }
public Aes ClientAes { get; set; } = Aes.Create();
private Logger Logger;
private readonly Logger Logger;
public Security(Logger logger)
{
Logger = logger;
@ -17,8 +17,8 @@ namespace RageCoop.Client
public void GetSymmetricKeysCrypted(out byte[] cryptedKey, out byte[] cryptedIV)
{
// Logger?.Debug($"Aes.Key:{ClientAes.Key.Dump()}, Aes.IV:{ClientAes.IV.Dump()}");
cryptedKey =ServerRSA.Encrypt(ClientAes.Key, RSAEncryptionPadding.Pkcs1);
cryptedIV =ServerRSA.Encrypt(ClientAes.IV, RSAEncryptionPadding.Pkcs1);
cryptedKey = ServerRSA.Encrypt(ClientAes.Key, RSAEncryptionPadding.Pkcs1);
cryptedIV = ServerRSA.Encrypt(ClientAes.IV, RSAEncryptionPadding.Pkcs1);
}
public byte[] Encrypt(byte[] data)
{
@ -33,11 +33,11 @@ namespace RageCoop.Client
var para = new RSAParameters();
para.Modulus = modulus;
para.Exponent = exponent;
ServerRSA=RSA.Create(para);
ServerRSA = RSA.Create(para);
}
public void Regen()
{
ClientAes=Aes.Create();
ClientAes = Aes.Create();
ClientAes.GenerateKey();
ClientAes.GenerateIV();
}

View File

@ -22,7 +22,7 @@ namespace RageCoop.Client
/// <summary>
/// Don't use it!
/// </summary>
public string MasterServer { get; set; } = "https://masterserver.ragecoop.online/";
public string MasterServer { get; set; } = "https://masterserver.ragecoop.com/";
/// <summary>
/// Don't use it!
/// </summary>
@ -51,7 +51,7 @@ namespace RageCoop.Client
/// <summary>
/// Disable world NPC traffic, mission entities won't be affected
/// </summary>
public bool DisableTraffic { get; set; } = true;
public bool DisableTraffic { get; set; } = false;
/// <summary>
/// Bring up pause menu but don't freeze time when FrontEndPauseAlternate(Esc) is pressed.
@ -67,6 +67,22 @@ namespace RageCoop.Client
/// The game won't spawn more NPC traffic if the limit is exceeded. -1 for unlimited (not recommended).
/// </summary>
public int WorldPedSoftLimit { get; set; } = 30;
/// <summary>
/// The mod won't sync more vehicles if the limit is exceeded.
/// </summary>
public int GlobalVehicleSoftLimit { get; set; } = 100;
/// <summary>
/// The mod won't sync more peds if the limit is exceeded.
/// </summary>
public int GlobalPedSoftLimit { get; set; } = 100;
/// <summary>
/// The mod won't sync more projectiles if the limit is exceeded.
/// </summary>
public int GlobalProjectileSoftLimit { get; set; } = 100;
/// <summary>
/// The directory where log and resources downloaded from server will be placed.
/// </summary>
@ -76,5 +92,15 @@ namespace RageCoop.Client
/// Show the owner name of the entity you're aiming at
/// </summary>
public bool ShowEntityOwnerName { get; set; } = false;
/// <summary>
/// Show other player's nametag on your screen
/// </summary>
public bool ShowPlayerNameTag { get; set; } = true;
/// <summary>
/// Show other player's blip on map
/// </summary>
public bool ShowPlayerBlip { get; set; } = true;
}
}

View File

@ -116,10 +116,10 @@ namespace RageCoop.Client
case unchecked((uint)-1357824103):
case unchecked((uint)-1074790547):
case unchecked((uint)2132975508):
case unchecked(2132975508):
case unchecked((uint)-2084633992):
case unchecked((uint)-952879014):
case unchecked((uint)100416529):
case unchecked(100416529):
case unchecked((uint)WeaponHash.Gusenberg):
case unchecked((uint)WeaponHash.MG):
case unchecked((uint)WeaponHash.CombatMG):

View File

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

View File

@ -15,7 +15,6 @@ namespace RageCoop.Client
/// </summary>
public partial class SyncedPed : SyncedEntity
{
#region CONSTRUCTORS
/// <summary>
/// Create a local entity (outgoing sync)
@ -23,13 +22,13 @@ namespace RageCoop.Client
/// <param name="p"></param>
internal SyncedPed(Ped p)
{
ID=EntityPool.RequestNewID();
p.CanWrithe=false;
p.IsOnlyDamagedByPlayer=false;
MainPed=p;
OwnerID=Main.LocalPlayerID;
ID = EntityPool.RequestNewID();
p.CanWrithe = false;
p.IsOnlyDamagedByPlayer = false;
MainPed = p;
OwnerID = Main.LocalPlayerID;
Function.Call(Hash._SET_PED_CAN_PLAY_INJURED_ANIMS, false);
//Function.Call(Hash.SET_PED_IS_IGNORED_BY_AUTO_OPEN_DOORS, false);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
// MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableMelee, true);
@ -40,82 +39,13 @@ namespace RageCoop.Client
/// </summary>
internal SyncedPed(int id)
{
ID=id;
LastSynced=Main.Ticked;
ID = id;
LastSynced = Main.Ticked;
}
#endregion
internal Blip PedBlip = null;
internal BlipColor BlipColor = (BlipColor)255;
internal BlipSprite BlipSprite = 0;
internal float BlipScale = 1;
internal int VehicleID
{
get => CurrentVehicle?.ID ?? 0;
set
{
if (CurrentVehicle == null || value != CurrentVehicle?.ID)
{
CurrentVehicle=EntityPool.GetVehicleByID(value);
}
}
}
internal SyncedVehicle CurrentVehicle { get; private set; }
internal VehicleSeat Seat;
public bool IsPlayer { get => OwnerID == ID && ID != 0; }
public Ped MainPed { get; internal set; }
internal int Health { get; set; }
internal Vector3 HeadPosition { get; set; }
internal Vector3 RightFootPosition { get; set; }
internal Vector3 LeftFootPosition { get; set; }
internal byte WeaponTint { get; set; }
internal Vehicle _lastVehicle { get; set; }
internal int _lastVehicleID { get; set; }
private bool _lastRagdoll = false;
private ulong _lastRagdollTime = 0;
private bool _lastInCover = false;
private byte[] _lastClothes = null;
internal byte[] Clothes { get; set; }
internal float Heading { get; set; }
internal ulong LastSpeakingTime { get; set; } = 0;
internal bool IsSpeaking { get; set; } = false;
#region -- VARIABLES --
public byte Speed { get; set; }
private bool _lastIsJumping = false;
internal PedDataFlags Flags;
internal bool IsAiming => Flags.HasPedFlag(PedDataFlags.IsAiming);
internal bool _lastDriveBy;
internal bool IsReloading => Flags.HasPedFlag(PedDataFlags.IsReloading);
internal bool IsJumping => Flags.HasPedFlag(PedDataFlags.IsJumping);
internal bool IsRagdoll => Flags.HasPedFlag(PedDataFlags.IsRagdoll);
internal bool IsOnFire => Flags.HasPedFlag(PedDataFlags.IsOnFire);
internal bool IsInParachuteFreeFall => Flags.HasPedFlag(PedDataFlags.IsInParachuteFreeFall);
internal bool IsParachuteOpen => Flags.HasPedFlag(PedDataFlags.IsParachuteOpen);
internal bool IsOnLadder => Flags.HasPedFlag(PedDataFlags.IsOnLadder);
internal bool IsVaulting => Flags.HasPedFlag(PedDataFlags.IsVaulting);
internal bool IsInCover => Flags.HasPedFlag(PedDataFlags.IsInCover);
internal bool IsInLowCover => Flags.HasPedFlag(PedDataFlags.IsInLowCover);
internal bool IsInCoverFacingLeft => Flags.HasPedFlag(PedDataFlags.IsInCoverFacingLeft);
internal bool IsBlindFiring => Flags.HasPedFlag(PedDataFlags.IsBlindFiring);
internal bool IsInStealthMode => Flags.HasPedFlag(PedDataFlags.IsInStealthMode);
internal Prop ParachuteProp { get; set; } = null;
internal uint CurrentWeaponHash { get; set; }
private Dictionary<uint, bool> _lastWeaponComponents = null;
internal Dictionary<uint, bool> WeaponComponents { get; set; } = null;
private Entity _weaponObj;
#endregion
internal Vector3 AimCoords { get; set; }
private WeaponAsset WeaponAsset { get; set; }
internal override void Update()
{
if (Owner==null) { OwnerID=OwnerID;return; }
if (Owner == null) { OwnerID = OwnerID; return; }
if (IsPlayer)
{
RenderNameTag();
@ -136,9 +66,9 @@ namespace RageCoop.Client
}
// Need to update state
if (LastFullSynced>=LastUpdated)
if (LastFullSynced >= LastUpdated)
{
if (MainPed!=null&& (Model != MainPed.Model.Hash))
if (MainPed != null && (Model != MainPed.Model.Hash))
{
if (!CreateCharacter())
{
@ -146,29 +76,30 @@ namespace RageCoop.Client
}
}
if (((byte)BlipColor==255) && (PedBlip!=null))
if (!Main.Settings.ShowPlayerBlip && (byte)BlipColor != 255) BlipColor = (BlipColor)255;
if ((byte)BlipColor == 255 && PedBlip != null)
{
PedBlip.Delete();
PedBlip=null;
PedBlip = null;
}
else if (((byte)BlipColor != 255) && PedBlip==null)
else if ((byte)BlipColor != 255 && PedBlip == null)
{
PedBlip=MainPed.AddBlip();
PedBlip = MainPed.AddBlip();
PedBlip.Color=BlipColor;
PedBlip.Sprite=BlipSprite;
PedBlip.Scale=BlipScale;
PedBlip.Color = BlipColor;
PedBlip.Sprite = BlipSprite;
PedBlip.Scale = BlipScale;
}
if (PedBlip!=null)
if (PedBlip != null)
{
if (PedBlip.Color!=BlipColor)
if (PedBlip.Color != BlipColor)
{
PedBlip.Color=BlipColor;
PedBlip.Color = BlipColor;
}
if (PedBlip.Sprite!=BlipSprite)
if (PedBlip.Sprite != BlipSprite)
{
PedBlip.Sprite=BlipSprite;
PedBlip.Sprite = BlipSprite;
}
if (IsPlayer)
{
@ -186,7 +117,7 @@ namespace RageCoop.Client
if (MainPed.IsDead)
{
if (Health>0)
if (Health > 0)
{
if (IsPlayer)
{
@ -198,7 +129,7 @@ namespace RageCoop.Client
}
}
}
else if (IsPlayer&&(MainPed.Health != Health))
else if (IsPlayer && (MainPed.Health != Health))
{
MainPed.Health = Health;
@ -210,13 +141,13 @@ namespace RageCoop.Client
}
}
if (Speed>=4)
if (Speed >= 4)
{
DisplayInVehicle();
}
else
{
if (MainPed.IsInVehicle()) { MainPed.Task.LeaveVehicle(LeaveVehicleFlags.WarpOut);return; }
if (MainPed.IsInVehicle()) { MainPed.Task.LeaveVehicle(LeaveVehicleFlags.WarpOut); return; }
DisplayOnFoot();
}
@ -235,12 +166,12 @@ namespace RageCoop.Client
}
}
LastUpdated=Main.Ticked;
LastUpdated = Main.Ticked;
}
private void RenderNameTag()
{
if (!Owner.DisplayNameTag || (MainPed==null) || !MainPed.IsVisible || !MainPed.IsInRange(Main.PlayerPosition, 40f))
if (!Owner.DisplayNameTag || !Main.Settings.ShowPlayerNameTag || MainPed == null || !MainPed.IsVisible || !MainPed.IsInRange(Main.PlayerPosition, 40f))
{
return;
}
@ -249,12 +180,12 @@ namespace RageCoop.Client
Point toDraw = default;
if (Util.WorldToScreen(targetPos, ref toDraw))
{
toDraw.Y-=100;
toDraw.Y -= 100;
new ScaledText(toDraw, Owner.Username, 0.4f, GTA.UI.Font.ChaletLondon)
{
Outline = true,
Alignment = GTA.UI.Alignment.Center,
Color=Owner.HasDirectConnection? Color.FromArgb(179, 229, 252) : Color.White,
Color = Owner.HasDirectConnection ? Color.FromArgb(179, 229, 252) : Color.White,
}.Draw();
}
}
@ -293,19 +224,19 @@ namespace RageCoop.Client
Model.MarkAsNoLongerNeeded();
MainPed.BlockPermanentEvents = true;
MainPed.CanWrithe=false;
MainPed.CanWrithe = false;
MainPed.CanBeDraggedOutOfVehicle = true;
MainPed.IsOnlyDamagedByPlayer = false;
MainPed.RelationshipGroup=Main.SyncedPedsGroup;
MainPed.IsFireProof=false;
MainPed.IsExplosionProof=false;
MainPed.RelationshipGroup = Main.SyncedPedsGroup;
MainPed.IsFireProof = false;
MainPed.IsExplosionProof = false;
Function.Call(Hash.SET_PED_DROPS_WEAPONS_WHEN_DEAD, MainPed.Handle, false);
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED, MainPed.Handle, true);
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED_BY_PLAYER, MainPed.Handle, Game.Player, true);
Function.Call(Hash.SET_PED_GET_OUT_UPSIDE_DOWN_VEHICLE, MainPed.Handle, false);
Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, MainPed.Handle, true, true);
Function.Call(Hash._SET_PED_CAN_PLAY_INJURED_ANIMS, false);
Function.Call(Hash.SET_PED_IS_IGNORED_BY_AUTO_OPEN_DOORS, false);
Function.Call(Hash.SET_PED_CAN_EVASIVE_DIVE, MainPed.Handle, false);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DrownsInWater, false);
@ -321,8 +252,8 @@ namespace RageCoop.Client
SetClothes();
if (IsPlayer) { MainPed.IsInvincible=true; }
if (IsInvincible) { MainPed.IsInvincible=true; }
if (IsPlayer) { MainPed.IsInvincible = true; }
if (IsInvincible) { MainPed.IsInvincible = true; }
lock (EntityPool.PedsLock)
{
@ -337,15 +268,12 @@ namespace RageCoop.Client
{
for (byte i = 0; i < 12; i++)
{
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, MainPed.Handle, i, (int)Clothes[i], (int)Clothes[i+12], (int)Clothes[i+24]);
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, MainPed.Handle, i, (int)Clothes[i], (int)Clothes[i + 12], (int)Clothes[i + 24]);
}
_lastClothes = Clothes;
}
#region ONFOOT
private string[] _currentAnimation = new string[2] { "", "" };
private void DisplayOnFoot()
{
@ -492,7 +420,7 @@ namespace RageCoop.Client
}
_lastIsJumping = false;
if (IsRagdoll || Health==0)
if (IsRagdoll || Health == 0)
{
if (!MainPed.IsRagdoll)
{
@ -502,26 +430,22 @@ namespace RageCoop.Client
if (!_lastRagdoll)
{
_lastRagdoll = true;
_lastRagdollTime=Main.Ticked;
_lastRagdollTime = Main.Ticked;
}
return;
}
else
if (MainPed.IsRagdoll)
{
if (MainPed.IsRagdoll)
if (Speed == 0)
{
if (Speed==0)
{
MainPed.CancelRagdoll();
}
else
{
MainPed.Task.ClearAllImmediately();
}
return;
MainPed.CancelRagdoll();
}
else
{
MainPed.Task.ClearAllImmediately();
}
_lastRagdoll = false;
return;
}
if (IsReloading)
@ -551,11 +475,11 @@ namespace RageCoop.Client
Function.Call(Hash.TASK_STAY_IN_COVER, MainPed.Handle);
}
_lastInCover=true;
_lastInCover = true;
if (IsAiming)
{
DisplayAiming();
_lastInCover=false;
_lastInCover = false;
}
else if (MainPed.IsInCover)
{
@ -565,7 +489,7 @@ namespace RageCoop.Client
else if (_lastInCover)
{
MainPed.Task.ClearAllImmediately();
_lastInCover=false;
_lastInCover = false;
}
else if (IsAiming)
{
@ -581,12 +505,12 @@ namespace RageCoop.Client
}
}
#region WEAPON
private void CheckCurrentWeapon()
{
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) || (Speed <= 3 && _weaponObj?.IsVisible != true))
{
WeaponAsset=new WeaponAsset(CurrentWeaponHash);
new WeaponAsset(CurrentWeaponHash).Request();
MainPed.Weapons.RemoveAll();
_weaponObj = Entity.FromHandle(Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0));
if (_weaponObj == null) { return; }
@ -606,7 +530,7 @@ namespace RageCoop.Client
}
_lastWeaponComponents = WeaponComponents;
}
if (Function.Call<int>(Hash.GET_PED_WEAPON_TINT_INDEX, MainPed, CurrentWeaponHash)!=WeaponTint)
if (Function.Call<int>(Hash.GET_PED_WEAPON_TINT_INDEX, MainPed, CurrentWeaponHash) != WeaponTint)
{
Function.Call<int>(Hash.SET_PED_WEAPON_TINT_INDEX, MainPed, CurrentWeaponHash, WeaponTint);
}
@ -614,27 +538,25 @@ namespace RageCoop.Client
private void DisplayAiming()
{
if (Velocity==default)
if (Velocity == default)
{
MainPed.Task.AimAt(AimCoords, 1000);
}
else
{
Function.Call(Hash.TASK_GO_TO_COORD_WHILE_AIMING_AT_COORD, MainPed.Handle,
Position.X+Velocity.X, Position.Y+Velocity.Y, Position.Z+Velocity.Z,
Position.X + Velocity.X, Position.Y + Velocity.Y, Position.Z + Velocity.Z,
AimCoords.X, AimCoords.Y, AimCoords.Z, 3f, false, 0x3F000000, 0x40800000, false, 512, false, 0);
}
SmoothTransition();
}
#endregion
private bool LastMoving;
private void WalkTo()
{
MainPed.Task.ClearAll();
Function.Call(Hash.SET_PED_STEALTH_MOVEMENT, MainPed, IsInStealthMode, 0);
Vector3 predictPosition = Predict(Position)+Velocity;
Vector3 predictPosition = Predict(Position) + Velocity;
float range = predictPosition.DistanceToSquared(MainPed.ReadPosition());
switch (Speed)
@ -676,6 +598,8 @@ namespace RageCoop.Client
MainPed.Task.StandStill(2000);
LastMoving = false;
}
if (MainPed.IsTaskActive(TaskType.CTaskDiveToGround)) MainPed.Task.ClearAll();
break;
}
SmoothTransition();
@ -688,23 +612,23 @@ namespace RageCoop.Client
var dist = predicted.DistanceTo(MainPed.ReadPosition());
if (IsOff(dist))
{
MainPed.PositionNoOffset= predicted;
MainPed.PositionNoOffset = predicted;
return;
}
if (!(localRagdoll || MainPed.IsDead))
{
if (!IsAiming && !MainPed.IsGettingUp)
{
var cur=MainPed.Heading;
var diff=Heading-cur;
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.Heading = cur + diff / 2;
}
MainPed.Velocity = Velocity + 5 * dist * (predicted - MainPed.ReadPosition());
}
else if (Main.Ticked-_lastRagdollTime<10)
else if (Main.Ticked - _lastRagdollTime < 10)
{
return;
}
@ -717,10 +641,10 @@ namespace RageCoop.Client
Vector3 amount;
// 20:head, 3:left foot, 6:right foot, 17:right hand,
amount= 20 * (Predict(HeadPosition) - head.Position);
amount = 20 * (Predict(HeadPosition) - head.Position);
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
helper.EqualizeAmount = 1;
helper.PartIndex=20;
helper.PartIndex = 20;
helper.Impulse = amount;
helper.Start();
helper.Stop();
@ -728,7 +652,7 @@ namespace RageCoop.Client
amount = 20 * (Predict(RightFootPosition) - rightFoot.Position);
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
helper.EqualizeAmount = 1;
helper.PartIndex=6;
helper.PartIndex = 6;
helper.Impulse = amount;
helper.Start();
helper.Stop();
@ -736,7 +660,7 @@ namespace RageCoop.Client
amount = 20 * (Predict(LeftFootPosition) - leftFoot.Position);
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
helper.EqualizeAmount = 1;
helper.PartIndex=3;
helper.PartIndex = 3;
helper.Impulse = amount;
helper.Start();
helper.Stop();
@ -744,23 +668,19 @@ namespace RageCoop.Client
else
{
// localRagdoll
var force = Velocity - MainPed.Velocity+5 * dist * (predicted - MainPed.ReadPosition());
if (force.Length() > 20) { force = force.Normalized*20; }
var force = Velocity - MainPed.Velocity + 5 * dist * (predicted - MainPed.ReadPosition());
if (force.Length() > 20) { force = force.Normalized * 20; }
MainPed.ApplyForce(force);
}
}
#endregion
private void DisplayInVehicle()
{
if (CurrentVehicle?.MainVehicle==null) { return; }
if (CurrentVehicle?.MainVehicle == null) { return; }
switch (Speed)
{
case 4:
if (MainPed.CurrentVehicle!=CurrentVehicle.MainVehicle || MainPed.SeatIndex != Seat || (!MainPed.IsSittingInVehicle() && !MainPed.IsBeingJacked))
if (MainPed.CurrentVehicle != CurrentVehicle.MainVehicle || MainPed.SeatIndex != Seat || (!MainPed.IsSittingInVehicle() && !MainPed.IsBeingJacked))
{
MainPed.SetIntoVehicle(CurrentVehicle.MainVehicle, Seat);
}
@ -769,7 +689,7 @@ namespace RageCoop.Client
// Function.Call(Hash.SET_VEHICLE_TURRET_SPEED_THIS_FRAME, MainPed.CurrentVehicle, 100);
Function.Call(Hash.TASK_VEHICLE_AIM_AT_COORD, MainPed.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z);
}
if (MainPed.VehicleWeapon==VehicleWeaponHash.Invalid)
if (MainPed.VehicleWeapon == VehicleWeaponHash.Invalid)
{
// World.DrawMarker(MarkerType.DebugSphere,AimCoords,default,default,new Vector3(0.2f,0.2f,0.2f),Color.AliceBlue);
if (IsAiming)
@ -777,32 +697,32 @@ namespace RageCoop.Client
Function.Call(Hash.SET_DRIVEBY_TASK_TARGET, MainPed, 0, 0, AimCoords.X, AimCoords.Y, AimCoords.Z);
if (!_lastDriveBy)
{
_lastDriveBy=true;
_lastDriveBy = true;
Function.Call(Hash.TASK_DRIVE_BY, MainPed, 0, 0, AimCoords.X, AimCoords.Y, AimCoords.Z, 1, 100, 1, FiringPattern.SingleShot);
}
}
else if (_lastDriveBy || MainPed.IsTaskActive(TaskType.CTaskAimGunVehicleDriveBy))
{
MainPed.Task.ClearAll();
_lastDriveBy=false;
_lastDriveBy = false;
}
}
else if (MainPed.VehicleWeapon!=(VehicleWeaponHash)CurrentWeaponHash)
else if (MainPed.VehicleWeapon != (VehicleWeaponHash)CurrentWeaponHash)
{
MainPed.VehicleWeapon=(VehicleWeaponHash)CurrentWeaponHash;
MainPed.VehicleWeapon = (VehicleWeaponHash)CurrentWeaponHash;
}
break;
case 5:
if (MainPed.VehicleTryingToEnter!=CurrentVehicle.MainVehicle || MainPed.GetSeatTryingToEnter()!=Seat)
if (MainPed.VehicleTryingToEnter != CurrentVehicle.MainVehicle || MainPed.GetSeatTryingToEnter() != Seat)
{
MainPed.Task.EnterVehicle(CurrentVehicle.MainVehicle,Seat,-1,5,EnterVehicleFlags.AllowJacking);
MainPed.Task.EnterVehicle(CurrentVehicle.MainVehicle, Seat, -1, 5, EnterVehicleFlags.JackAnyone);
}
break;
case 6:
if (!MainPed.IsTaskActive(TaskType.CTaskExitVehicle))
{
MainPed.Task.LeaveVehicle(CurrentVehicle.Velocity.Length() > 5f ? LeaveVehicleFlags.BailOut:LeaveVehicleFlags.None);
MainPed.Task.LeaveVehicle(CurrentVehicle.Velocity.Length() > 5f ? LeaveVehicleFlags.BailOut : LeaveVehicleFlags.None);
}
break;
}

View File

@ -33,11 +33,12 @@ namespace RageCoop.Client
get => _ownerID;
internal set
{
if (value==_ownerID && Owner!=null) { return; }
if (value == _ownerID && Owner != null) { return; }
_ownerID = value;
Owner=PlayerList.GetPlayer(value);
if(this is SyncedPed && Owner!=null){
Owner.Character=((SyncedPed)this);
Owner = PlayerList.GetPlayer(value);
if (this is SyncedPed && Owner != null)
{
Owner.Character = ((SyncedPed)this);
}
}
}
@ -83,7 +84,7 @@ namespace RageCoop.Client
/// <summary>
///
/// </summary>
internal protected bool _lastFrozen = false;
protected internal bool _lastFrozen = false;
internal Model Model { get; set; }
internal Vector3 Position { get; set; }
internal Vector3 Rotation { get; set; }
@ -93,18 +94,18 @@ namespace RageCoop.Client
internal abstract void Update();
internal void PauseUpdate(ulong frames)
{
LastUpdated=Main.Ticked+frames;
LastUpdated = Main.Ticked + frames;
}
protected Vector3 Predict(Vector3 input)
{
return (Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds) * Velocity + input;
}
private float _accumulatedOff=0;
protected bool IsOff(float thisOff, float tolerance=3 , float limit = 30)
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)
if (_accumulatedOff < 0) { _accumulatedOff = 0; }
else if (_accumulatedOff >= limit)
{
_accumulatedOff = 0;
return true;

View File

@ -1,13 +1,13 @@
using GTA;
using GTA.Math;
using RageCoop.Core;
using GTA.Native;
using RageCoop.Core;
namespace RageCoop.Client
{
internal class SyncedProjectile : SyncedEntity
{
public ProjectileDataFlags Flags { private get; set; }=ProjectileDataFlags.None;
public ProjectileDataFlags Flags { private get; set; } = ProjectileDataFlags.None;
public readonly Vector3 Origin;
private bool _firstSend = false;
@ -19,28 +19,27 @@ namespace RageCoop.Client
public SyncedEntity Shooter { get; set; }
public bool Exploded => Flags.HasProjDataFlag(ProjectileDataFlags.Exploded);
internal override Player Owner => Shooter.Owner;
/// <summary>
/// Invalid property for projectile.
/// </summary>
private new int OwnerID { set { } }
internal override Player Owner => Shooter.Owner;
public WeaponHash WeaponHash { get; set; }
private WeaponAsset Asset { get; set; }
public void ExtractData(ref Packets.ProjectileSync p)
{
p.Position=MainProjectile.Position;
p.Velocity=MainProjectile.Velocity;
p.Rotation=MainProjectile.Rotation;
p.ID=ID;
p.ShooterID=Shooter.ID;
p.WeaponHash=(uint)MainProjectile.WeaponHash;
p.Flags=ProjectileDataFlags.None;
p.Position = MainProjectile.Position;
p.Velocity = MainProjectile.Velocity;
p.Rotation = MainProjectile.Rotation;
p.ID = ID;
p.ShooterID = Shooter.ID;
p.WeaponHash = (uint)MainProjectile.WeaponHash;
p.Flags = ProjectileDataFlags.None;
if (MainProjectile.IsDead)
{
p.Flags |= ProjectileDataFlags.Exploded;
}
if (MainProjectile.AttachedEntity!=null)
if (MainProjectile.AttachedEntity != null)
{
p.Flags |= ProjectileDataFlags.IsAttached;
}
@ -51,44 +50,44 @@ namespace RageCoop.Client
if (_firstSend)
{
p.Flags |= ProjectileDataFlags.IsAttached;
_firstSend=false;
_firstSend = false;
}
}
public SyncedProjectile(Projectile p)
{
var owner = p.OwnerEntity;
if (owner==null) { IsValid=false;return; }
ID=EntityPool.RequestNewID();
if (owner == null) { IsValid = false; return; }
ID = EntityPool.RequestNewID();
MainProjectile = p;
Origin=p.Position;
if(EntityPool.PedsByHandle.TryGetValue(owner.Handle,out var shooter))
Origin = p.Position;
if (EntityPool.PedsByHandle.TryGetValue(owner.Handle, out var shooter))
{
if (shooter.MainPed!=null
&& (p.AttachedEntity==shooter.MainPed.Weapons.CurrentWeaponObject
|| p.AttachedEntity== shooter.MainPed))
if (shooter.MainPed != null
&& (p.AttachedEntity == shooter.MainPed.Weapons.CurrentWeaponObject
|| p.AttachedEntity == shooter.MainPed))
{
// Reloading
IsValid=false;
IsValid = false;
return;
}
Shooter=shooter;
IsLocal=shooter.IsLocal;
Shooter = shooter;
IsLocal = shooter.IsLocal;
}
else if(EntityPool.VehiclesByHandle.TryGetValue(owner.Handle,out var shooterVeh))
else if (EntityPool.VehiclesByHandle.TryGetValue(owner.Handle, out var shooterVeh))
{
Shooter=shooterVeh;
IsLocal=shooterVeh.IsLocal;
Shooter = shooterVeh;
IsLocal = shooterVeh.IsLocal;
}
else
{
IsValid=false;
IsValid = false;
}
}
public SyncedProjectile(int id)
{
ID= id;
IsLocal=false;
ID = id;
IsLocal = false;
}
internal override void Update()
{
@ -101,27 +100,26 @@ namespace RageCoop.Client
CreateProjectile();
return;
}
MainProjectile.Velocity=Velocity+(Position+Shooter.Owner.PacketTravelTime*Velocity-MainProjectile.Position);
MainProjectile.Rotation=Rotation;
LastUpdated=Main.Ticked;
MainProjectile.Velocity = Velocity + 10 * (Predict(Position) - MainProjectile.Position);
MainProjectile.Rotation = Rotation;
LastUpdated = Main.Ticked;
}
private void CreateProjectile()
{
Asset=new WeaponAsset(WeaponHash);
Asset = new WeaponAsset(WeaponHash);
if (!Asset.IsLoaded) { Asset.Request(); return; }
if(Shooter == null) { return; }
if (Shooter == null) { return; }
Entity owner;
owner=(Shooter as SyncedPed)?.MainPed ?? (Entity)(Shooter as SyncedVehicle)?.MainVehicle;
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);
owner = (Shooter as SyncedPed)?.MainPed ?? (Entity)(Shooter as SyncedVehicle)?.MainVehicle;
Position = (Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds) * Shooter.Velocity + Position;
var end = Position + Velocity;
Function.Call(Hash.SHOOT_SINGLE_BULLET_BETWEEN_COORDS_IGNORE_ENTITY, Position.X, Position.Y, Position.Z, end.X, end.Y, end.Z, 0, 1, WeaponHash, owner?.Handle ?? 0, 1, 0, -1);
var ps = World.GetAllProjectiles();
MainProjectile=ps[ps.Length-1];
MainProjectile.IsCollisionEnabled=false;
MainProjectile.Position=Position;
MainProjectile.Rotation =Rotation;
MainProjectile.Velocity=Velocity;
Main.Delay(()=>MainProjectile.IsCollisionEnabled=true, 100);
MainProjectile = ps[ps.Length - 1];
MainProjectile.Position = Position;
MainProjectile.Rotation = Rotation;
MainProjectile.Velocity = Velocity;
EntityPool.Add(this);
}
}

View File

@ -9,7 +9,7 @@ namespace RageCoop.Client
{
internal SyncedProp(int id)
{
ID= id;
ID = id;
}
/// <summary>
/// The real entity
@ -27,15 +27,15 @@ namespace RageCoop.Client
{
if (!NeedUpdate) { return; }
if (MainProp== null || !MainProp.Exists())
if (MainProp == null || !MainProp.Exists())
{
MainProp=World.CreateProp(Model, Position, Rotation, false, false);
MainProp.IsInvincible=true;
MainProp = World.CreateProp(Model, Position, Rotation, false, false);
MainProp.IsInvincible = true;
}
MainProp.Position=Position;
MainProp.Rotation=Rotation;
MainProp.Position = Position;
MainProp.Rotation = Rotation;
MainProp.SetFrozen(true);
LastUpdated=Main.Ticked;
LastUpdated = Main.Ticked;
}
}
}

View File

@ -1,13 +1,12 @@
using System;
using RageCoop.Core;
using GTA;
using System.Diagnostics;
using System.Collections.Generic;
using GTA.Math;
using GTA.Native;
using RageCoop.Core;
using System.Collections.Generic;
namespace RageCoop.Client{
public partial class SyncedVehicle{
namespace RageCoop.Client
{
public partial class SyncedVehicle
{
public Vehicle MainVehicle { get; internal set; }
@ -68,11 +67,9 @@ namespace RageCoop.Client{
private bool _lastHornActive = false;
private bool _lastTransformed = false;
internal int _lastLivery = -1;
List<Vector3> _predictedTrace = new List<Vector3>();
List<Vector3> _orgTrace = new List<Vector3>();
private readonly List<Vector3> _predictedTrace = new List<Vector3>();
private readonly List<Vector3> _orgTrace = new List<Vector3>();
private Vector3 _predictedPosition;
float _elapsed;
#endregion
#region OUTGOING

View File

@ -4,8 +4,6 @@ using GTA.Native;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
namespace RageCoop.Client
{
@ -24,22 +22,24 @@ namespace RageCoop.Client
internal SyncedVehicle(Vehicle v)
{
ID=EntityPool.RequestNewID();
MainVehicle=v;
MainVehicle.CanPretendOccupants=false;
OwnerID=Main.LocalPlayerID;
ID = EntityPool.RequestNewID();
MainVehicle = v;
MainVehicle.CanPretendOccupants = false;
OwnerID = Main.LocalPlayerID;
SetUpFixedData();
}
private void SetUpFixedData(){
internal void SetUpFixedData()
{
if (MainVehicle == null) { return; }
IsAircraft = MainVehicle.IsAircraft;
IsMotorcycle = MainVehicle.IsMotorcycle;
HasRocketBoost = MainVehicle.HasRocketBoost;
HasParachute = MainVehicle.HasParachute;
HasRoof = MainVehicle.HasRoof;
IsSubmarineCar=MainVehicle.IsSubmarineCar;
IsDeluxo=MainVehicle.Model==1483171323;
IsSubmarineCar = MainVehicle.IsSubmarineCar;
IsDeluxo = MainVehicle.Model == 1483171323;
}
/// <summary>
@ -51,8 +51,8 @@ namespace RageCoop.Client
}
internal SyncedVehicle(int id)
{
ID=id;
LastSynced=Main.Ticked;
ID = id;
LastSynced = Main.Ticked;
}
#endregion
/// <summary>
@ -97,8 +97,8 @@ namespace RageCoop.Client
{
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * SteeringAngle);
}
MainVehicle.ThrottlePower=ThrottlePower;
MainVehicle.BrakePower=BrakePower;
MainVehicle.ThrottlePower = ThrottlePower;
MainVehicle.BrakePower = BrakePower;
if (IsDead)
{
@ -119,7 +119,7 @@ namespace RageCoop.Client
{
MainVehicle.Repair();
}
},1000);
}, 1000);
}
}
if (MainVehicle.IsOnFire)
@ -149,8 +149,6 @@ namespace RageCoop.Client
MainVehicle.AreHighBeamsOn = HighBeamsOn;
}
if (IsAircraft)
{
if (LandingGear != (byte)MainVehicle.LandingGearState)
@ -179,15 +177,17 @@ namespace RageCoop.Client
MainVehicle.SoundHorn(1);
}
if (HasRoof && MainVehicle.RoofState!=RoofState)
if (HasRoof && MainVehicle.RoofState != RoofState)
{
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));
}
if(HasParachute && Flags.HasFlag(VehicleDataFlags.IsParachuteActive) != MainVehicle.IsParachuteActive()){
if (HasParachute && Flags.HasFlag(VehicleDataFlags.IsParachuteActive) != MainVehicle.IsParachuteActive())
{
MainVehicle.SetParachuteActive(Flags.HasFlag(VehicleDataFlags.IsParachuteActive));
}
if (IsSubmarineCar)
@ -197,16 +197,16 @@ namespace RageCoop.Client
if (!_lastTransformed)
{
_lastTransformed = true;
Function.Call(Hash._TRANSFORM_VEHICLE_TO_SUBMARINE, MainVehicle.Handle, false);
Function.Call(Hash.TRANSFORM_TO_SUBMARINE, MainVehicle.Handle, false);
}
}
else if (_lastTransformed)
{
_lastTransformed = false;
Function.Call(Hash._TRANSFORM_SUBMARINE_TO_VEHICLE, MainVehicle.Handle, false);
Function.Call(Hash.TRANSFORM_TO_CAR, MainVehicle.Handle, false);
}
}
else if(IsDeluxo)
else if (IsDeluxo)
{
MainVehicle.SetDeluxoHoverState(IsDeluxoHovering);
if (IsDeluxoHovering)
@ -219,9 +219,9 @@ namespace RageCoop.Client
}
MainVehicle.LockStatus=LockStatus;
MainVehicle.LockStatus = LockStatus;
if (LastFullSynced>=LastUpdated)
if (LastFullSynced >= LastUpdated)
{
if (Flags.HasVehFlag(VehicleDataFlags.Repaired))
{
@ -233,7 +233,7 @@ namespace RageCoop.Client
_lastVehicleColors = Colors;
}
MainVehicle.EngineHealth=EngineHealth;
MainVehicle.EngineHealth = EngineHealth;
if (Mods != null && !Mods.Compare(_lastVehicleMods))
{
Function.Call(Hash.SET_VEHICLE_MOD_KIT, MainVehicle, 0);
@ -246,21 +246,22 @@ namespace RageCoop.Client
_lastVehicleMods = Mods;
}
if (Function.Call<string>(Hash.GET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle)!=LicensePlate)
if (Function.Call<string>(Hash.GET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle) != LicensePlate)
{
Function.Call(Hash.SET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle, LicensePlate);
}
if (_lastLivery!=Livery)
if (_lastLivery != Livery)
{
Function.Call(Hash.SET_VEHICLE_LIVERY, MainVehicle, Livery);
_lastLivery=Livery;
_lastLivery = Livery;
}
MainVehicle.SetDamageModel(DamageModel);
}
LastUpdated=Main.Ticked;
LastUpdated = Main.Ticked;
}
void DisplayVehicle()
private void DisplayVehicle()
{
_predictedPosition = Predict(Position);
var current = MainVehicle.ReadPosition();
@ -274,37 +275,34 @@ namespace RageCoop.Client
MainVehicle.Quaternion = Quaternion;
return;
}
else if (dist > 0.03)
if (dist > 0.03)
{
MainVehicle.Velocity = Velocity + cali;
}
Vector3 calirot;
if (IsFlipped || (calirot = GetCalibrationRotation()).Length()>50)
if (IsFlipped || (calirot = GetCalibrationRotation()).Length() > 50)
{
MainVehicle.Quaternion = Quaternion.Slerp(MainVehicle.ReadQuaternion(), Quaternion, 0.5f);
MainVehicle.RotationVelocity = RotationVelocity;
return;
}
else
{
MainVehicle.RotationVelocity = RotationVelocity + calirot * 0.2f;
}
MainVehicle.RotationVelocity = RotationVelocity + calirot * 0.2f;
}
private Vector3 GetCalibrationRotation()
{
var rot = Quaternion.LookRotation(Quaternion*Vector3.RelativeFront, Quaternion*Vector3.RelativeTop).ToEulerAngles();
var curRot = Quaternion.LookRotation(MainVehicle.ReadQuaternion()*Vector3.RelativeFront, MainVehicle.ReadQuaternion()*Vector3.RelativeTop).ToEulerAngles();
var rot = Quaternion.LookRotation(Quaternion * Vector3.RelativeFront, Quaternion * Vector3.RelativeTop).ToEulerAngles();
var curRot = Quaternion.LookRotation(MainVehicle.ReadQuaternion() * Vector3.RelativeFront, MainVehicle.ReadQuaternion() * Vector3.RelativeTop).ToEulerAngles();
var r = (rot-curRot).ToDegree();
if (r.X>180) { r.X=r.X-360; }
else if (r.X<-180) { r.X=360+r.X; }
var r = (rot - curRot).ToDegree();
if (r.X > 180) { r.X = r.X - 360; }
else if (r.X < -180) { r.X = 360 + r.X; }
if (r.Y>180) { r.Y=r.Y-360; }
else if (r.Y<-180) { r.Y=360+r.Y; }
if (r.Y > 180) { r.Y = r.Y - 360; }
else if (r.Y < -180) { r.Y = 360 + r.Y; }
if (r.Z>180) { r.Z=r.Z-360; }
else if (r.Z<-180) { r.Z=360+r.Z; }
if (r.Z > 180) { r.Z = r.Z - 360; }
else if (r.Z < -180) { r.Z = 360 + r.Z; }
return r;
}
private bool CreateVehicle()
@ -316,7 +314,7 @@ namespace RageCoop.Client
// GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
return false;
}
else if (MainVehicle==null)
if (MainVehicle == null)
{
Model.Request();
return false;
@ -328,18 +326,18 @@ namespace RageCoop.Client
MainVehicle.Quaternion = Quaternion;
if (MainVehicle.HasRoof)
{
MainVehicle.RoofState=RoofState;
MainVehicle.RoofState = RoofState;
}
foreach(var w in MainVehicle.Wheels)
foreach (var w in MainVehicle.Wheels)
{
w.Fix();
}
if (IsInvincible) { MainVehicle.IsInvincible=true; }
if (IsInvincible) { MainVehicle.IsInvincible = true; }
SetUpFixedData();
Model.MarkAsNoLongerNeeded();
return true;
}
#region -- PEDALING --
#region -- PEDALING --
/*
* Thanks to @oldnapalm.
*/
@ -366,7 +364,7 @@ namespace RageCoop.Client
private void StartPedalingAnim(bool fast)
{
MainVehicle.Driver?.Task.PlayAnimation(PedalingAnimDict(), PedalingAnimName(fast), 8.0f, -8.0f, -1, AnimationFlags.Loop | AnimationFlags.AllowRotation, 1.0f);
MainVehicle.Driver?.Task.PlayAnimation(PedalingAnimDict(), PedalingAnimName(fast), 8.0f, -8.0f, -1, AnimationFlags.Loop | AnimationFlags.Secondary, 1.0f);
}
@ -374,8 +372,6 @@ namespace RageCoop.Client
{
MainVehicle.Driver.Task.ClearAnimation(PedalingAnimDict(), PedalingAnimName(fast));
}
#endregion
#endregion
}
}

View File

@ -1,18 +1,17 @@
using GTA;
using GTA.Native;
using Lidgren.Network;
using RageCoop.Client.Scripting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using Lidgren.Network;
namespace RageCoop.Client
{
internal class EntityPool
{
public static object PedsLock = new object();
public static int CharactersCount { get { return PedsByID.Count; } }
#if BENCHMARK
private static Stopwatch PerfCounter=new Stopwatch();
private static Stopwatch PerfCounter2=Stopwatch.StartNew();
@ -44,17 +43,17 @@ namespace RageCoop.Client
#endregion
public static void Cleanup(bool keepPlayer = true, bool keepMine = true)
{
foreach (int id in new List<int>(PedsByID.Keys))
foreach (var ped in PedsByID.Values.ToArray())
{
if (keepPlayer && (id==Main.LocalPlayerID)|| keepMine && (PedsByID[id].OwnerID == Main.LocalPlayerID)) { continue; }
RemovePed(id);
if ((keepPlayer && (ped.ID == Main.LocalPlayerID)) || (keepMine && (ped.OwnerID == Main.LocalPlayerID))) { continue; }
RemovePed(ped.ID);
}
PedsByID.Clear();
PedsByHandle.Clear();
foreach (int id in new List<int>(VehiclesByID.Keys))
{
if (keepMine&&(VehiclesByID[id].OwnerID==Main.LocalPlayerID)) { continue; }
if (keepMine && (VehiclesByID[id].OwnerID == Main.LocalPlayerID)) { continue; }
RemoveVehicle(id);
}
VehiclesByID.Clear();
@ -62,7 +61,7 @@ namespace RageCoop.Client
foreach (var p in ProjectilesByID.Values)
{
if (p.Shooter.ID!=Main.LocalPlayerID && p.MainProjectile!=null && p.MainProjectile.Exists())
if (p.Shooter.ID != Main.LocalPlayerID && p.MainProjectile != null && p.MainProjectile.Exists())
{
p.MainProjectile.Delete();
}
@ -96,7 +95,7 @@ namespace RageCoop.Client
// var clipset=p.Gender==Gender.Male? "MOVE_M@TOUGH_GUY@" : "MOVE_F@TOUGH_GUY@";
// Function.Call(Hash.SET_PED_MOVEMENT_CLIPSET,p,clipset,1f);
SyncedPed player = GetPedByID(Main.LocalPlayerID);
if (player==null)
if (player == null)
{
Main.Logger.Debug($"Creating SyncEntity for player, handle:{p.Handle}");
SyncedPed c = new SyncedPed(p);
@ -133,16 +132,16 @@ namespace RageCoop.Client
{
if (PedsByID.ContainsKey(c.ID))
{
PedsByID[c.ID]=c;
PedsByID[c.ID] = c;
}
else
{
PedsByID.Add(c.ID, c);
}
if (c.MainPed==null) { return; }
if (c.MainPed == null) { return; }
if (PedsByHandle.ContainsKey(c.MainPed.Handle))
{
PedsByHandle[c.MainPed.Handle]=c;
PedsByHandle[c.MainPed.Handle] = c;
}
else
{
@ -159,7 +158,7 @@ namespace RageCoop.Client
{
SyncedPed c = PedsByID[id];
var p = c.MainPed;
if (p!=null)
if (p != null)
{
if (PedsByHandle.ContainsKey(p.Handle))
{
@ -184,23 +183,23 @@ namespace RageCoop.Client
#endregion
#region VEHICLES
public static SyncedVehicle GetVehicleByID(int id) => VehiclesByID.TryGetValue(id,out var v) ? v : null;
public static SyncedVehicle GetVehicleByHandle(int handle) => VehiclesByHandle.TryGetValue(handle,out var v) ? v : null;
public static SyncedVehicle GetVehicleByID(int id) => VehiclesByID.TryGetValue(id, out var v) ? v : null;
public static SyncedVehicle GetVehicleByHandle(int handle) => VehiclesByHandle.TryGetValue(handle, out var v) ? v : null;
public static List<int> GetVehicleIDs() => new List<int>(VehiclesByID.Keys);
public static void Add(SyncedVehicle v)
{
if (VehiclesByID.ContainsKey(v.ID))
{
VehiclesByID[v.ID]=v;
VehiclesByID[v.ID] = v;
}
else
{
VehiclesByID.Add(v.ID, v);
}
if (v.MainVehicle==null) { return; }
if (v.MainVehicle == null) { return; }
if (VehiclesByHandle.ContainsKey(v.MainVehicle.Handle))
{
VehiclesByHandle[v.MainVehicle.Handle]=v;
VehiclesByHandle[v.MainVehicle.Handle] = v;
}
else
{
@ -217,7 +216,7 @@ namespace RageCoop.Client
{
SyncedVehicle v = VehiclesByID[id];
var veh = v.MainVehicle;
if (veh!=null)
if (veh != null)
{
if (VehiclesByHandle.ContainsKey(veh.Handle))
{
@ -239,27 +238,27 @@ namespace RageCoop.Client
#region PROJECTILES
public static SyncedProjectile GetProjectileByID(int id)
{
return ProjectilesByID.TryGetValue(id,out var p) ? p : null;
return ProjectilesByID.TryGetValue(id, out var p) ? p : null;
}
public static void Add(SyncedProjectile p)
{
if (!p.IsValid) { return; }
if (p.WeaponHash==(WeaponHash)VehicleWeaponHash.Tank)
if (p.WeaponHash == (WeaponHash)VehicleWeaponHash.Tank)
{
Networking.SendBullet(p.Position, p.Position+p.Velocity, (uint)VehicleWeaponHash.Tank, ((SyncedVehicle)p.Shooter).MainVehicle.Driver.GetSyncEntity().ID);
Networking.SendBullet(p.Position, p.Position + p.Velocity, (uint)VehicleWeaponHash.Tank, ((SyncedVehicle)p.Shooter).MainVehicle.Driver.GetSyncEntity().ID);
}
if (ProjectilesByID.ContainsKey(p.ID))
{
ProjectilesByID[p.ID]=p;
ProjectilesByID[p.ID] = p;
}
else
{
ProjectilesByID.Add(p.ID, p);
}
if (p.MainProjectile==null) { return; }
if (p.MainProjectile == null) { return; }
if (ProjectilesByHandle.ContainsKey(p.MainProjectile.Handle))
{
ProjectilesByHandle[p.MainProjectile.Handle]=p;
ProjectilesByHandle[p.MainProjectile.Handle] = p;
}
else
{
@ -272,14 +271,14 @@ namespace RageCoop.Client
{
SyncedProjectile sp = ProjectilesByID[id];
var p = sp.MainProjectile;
if (p!=null)
if (p != null)
{
if (ProjectilesByHandle.ContainsKey(p.Handle))
{
ProjectilesByHandle.Remove(p.Handle);
}
Main.Logger.Debug($"Removing projectile {sp.ID}. Reason:{reason}");
p.Explode();
//Main.Logger.Debug($"Removing projectile {sp.ID}. Reason:{reason}");
if (sp.Exploded) p.Explode();
}
ProjectilesByID.Remove(id);
}
@ -289,11 +288,11 @@ namespace RageCoop.Client
public static bool VehicleExists(int id) => VehiclesByID.ContainsKey(id);
public static bool ProjectileExists(int id) => ProjectilesByID.ContainsKey(id);
#endregion
static int vehStateIndex;
static int pedStateIndex;
static int vehStatesPerFrame;
static int pedStatesPerFrame;
static int i;
private static int vehStateIndex;
private static int pedStateIndex;
private static int vehStatesPerFrame;
private static int pedStatesPerFrame;
private static int i;
public static Ped[] allPeds = new Ped[0];
public static Vehicle[] allVehicles = new Vehicle[0];
public static Projectile[] allProjectiles = new Projectile[0];
@ -306,21 +305,10 @@ namespace RageCoop.Client
Debug.TimeStamps[TimeStamp.CheckProjectiles]=PerfCounter.ElapsedTicks;
#endif
allPeds = World.GetAllPeds();
allVehicles=World.GetAllVehicles();
allProjectiles=World.GetAllProjectiles();
vehStatesPerFrame=allVehicles.Length*2/(int)Game.FPS+1;
pedStatesPerFrame=allPeds.Length*2/(int)Game.FPS+1;
/*
if (Main.Ticked%50==0)
{
bool flag1 = allVehicles.Length>Main.Settings.WorldVehicleSoftLimit && Main.Settings.WorldVehicleSoftLimit>-1;
bool flag2 = allPeds.Length>Main.Settings.WorldPedSoftLimit && Main.Settings.WorldPedSoftLimit>-1;
if ((flag1||flag2) && _trafficSpawning)
{ SetBudget(0); _trafficSpawning=false; }
else if(!_trafficSpawning)
{ SetBudget(1); _trafficSpawning=true; }
}
*/
allVehicles = World.GetAllVehicles();
allProjectiles = World.GetAllProjectiles();
vehStatesPerFrame = allVehicles.Length * 2 / (int)Game.FPS + 1;
pedStatesPerFrame = allPeds.Length * 2 / (int)Game.FPS + 1;
#if BENCHMARK
Debug.TimeStamps[TimeStamp.GetAllEntities]=PerfCounter.ElapsedTicks;
@ -342,10 +330,10 @@ namespace RageCoop.Client
// Outgoing sync
if (p.IsLocal)
{
if (p.MainProjectile.AttachedEntity==null)
if (p.MainProjectile.AttachedEntity == null)
{
// Prevent projectiles from exploding next to vehicle
if (p.WeaponHash==(WeaponHash)VehicleWeaponHash.Tank || p.MainProjectile.Position.DistanceTo(p.Origin)<2)
if (p.WeaponHash == (WeaponHash)VehicleWeaponHash.Tank || (p.MainProjectile.OwnerEntity?.EntityType == EntityType.Vehicle && p.MainProjectile.Position.DistanceTo(p.Origin) < 2))
{
continue;
}
@ -366,26 +354,27 @@ namespace RageCoop.Client
}
}
i=-1;
i = -1;
lock (PedsLock)
{
EntityPool.AddPlayer();
AddPlayer();
foreach (Ped p in allPeds)
{
SyncedPed c = EntityPool.GetPedByHandle(p.Handle);
if (c==null && (p!=Game.Player.Character))
SyncedPed c = GetPedByHandle(p.Handle);
List<PedHash> mainCharacters = new List<PedHash> { PedHash.Michael, PedHash.Franklin, PedHash.Franklin02, PedHash.Trevor };
if (c == null && p != Game.Player.Character && !mainCharacters.Contains((PedHash)p.Model.Hash))
{
if (allPeds.Length>Main.Settings.WorldPedSoftLimit && p.PopulationType != EntityPopulationType.RandomAmbient)
if (allPeds.Length > Main.Settings.WorldPedSoftLimit && p.PopulationType == EntityPopulationType.RandomAmbient && !p.IsInVehicle())
{
p.Delete();
continue;
}
// 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
@ -393,18 +382,18 @@ namespace RageCoop.Client
Debug.TimeStamps[TimeStamp.AddPeds]=PerfCounter.ElapsedTicks;
#endif
var ps = PedsByID.Values.ToArray();
pedStateIndex+=pedStatesPerFrame;
if (pedStateIndex>=ps.Length)
pedStateIndex += pedStatesPerFrame;
if (pedStateIndex >= ps.Length)
{
pedStateIndex=0;
pedStateIndex = 0;
}
foreach (SyncedPed c in ps)
{
i++;
if ((c.MainPed!=null)&&(!c.MainPed.Exists()))
if ((c.MainPed != null) && (!c.MainPed.Exists()))
{
EntityPool.RemovePed(c.ID, "non-existent");
RemovePed(c.ID, "non-existent");
continue;
}
@ -417,7 +406,7 @@ namespace RageCoop.Client
// event check
SyncEvents.Check(c);
Networking.SendPed(c, (i-pedStateIndex)<pedStatesPerFrame);
Networking.SendPed(c, (i - pedStateIndex) < pedStatesPerFrame);
#if BENCHMARK
Debug.TimeStamps[TimeStamp.SendPed]=PerfCounter2.ElapsedTicks-start;
#endif
@ -441,27 +430,26 @@ namespace RageCoop.Client
Debug.TimeStamps[TimeStamp.PedTotal]=PerfCounter.ElapsedTicks;
#endif
}
i=-1;
var check = Main.Ticked % 100 == 0;
i = -1;
lock (VehiclesLock)
{
foreach (Vehicle veh in allVehicles)
{
if (!VehiclesByHandle.ContainsKey(veh.Handle))
{
if (allVehicles.Length>Main.Settings.WorldVehicleSoftLimit)
if (allVehicles.Length > Main.Settings.WorldVehicleSoftLimit)
{
var type = veh.PopulationType;
if (type==EntityPopulationType.RandomAmbient || type==EntityPopulationType.RandomParked)
if (type == EntityPopulationType.RandomAmbient || type == EntityPopulationType.RandomParked)
{
foreach (var p in veh.Occupants)
{
p.Delete();
var c = EntityPool.GetPedByHandle(p.Handle);
if (c!=null)
var c = GetPedByHandle(p.Handle);
if (c != null)
{
EntityPool.RemovePed(c.ID, "ThrottleTraffic");
RemovePed(c.ID, "ThrottleTraffic");
}
}
veh.Delete();
@ -477,28 +465,31 @@ namespace RageCoop.Client
Debug.TimeStamps[TimeStamp.AddVehicles]=PerfCounter.ElapsedTicks;
#endif
var vs = VehiclesByID.Values.ToArray();
vehStateIndex+=vehStatesPerFrame;
if (vehStateIndex>=vs.Length)
vehStateIndex += vehStatesPerFrame;
if (vehStateIndex >= vs.Length)
{
vehStateIndex=0;
vehStateIndex = 0;
}
foreach (SyncedVehicle v in vs)
{
i++;
if ((v.MainVehicle!=null)&&(!v.MainVehicle.Exists()))
if ((v.MainVehicle != null) && (!v.MainVehicle.Exists()))
{
EntityPool.RemoveVehicle(v.ID, "non-existent");
RemoveVehicle(v.ID, "non-existent");
continue;
}
if (check)
{
v.SetUpFixedData();
}
// Outgoing sync
if (v.IsLocal)
{
if (!v.MainVehicle.IsVisible) { continue; }
SyncEvents.Check(v);
Networking.SendVehicle(v, (i-vehStateIndex)<vehStatesPerFrame);
Networking.SendVehicle(v, (i - vehStateIndex) < vehStatesPerFrame);
}
else // Incoming sync
{
@ -516,12 +507,13 @@ namespace RageCoop.Client
}
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())
{
if (p.HasDirectConnection && p.Position.DistanceTo(Main.PlayerPosition)<500)
if (p.HasDirectConnection && p.Position.DistanceTo(Main.PlayerPosition) < 500)
{
Networking.Targets.Add(p.Connection);
}
@ -532,7 +524,7 @@ namespace RageCoop.Client
{
foreach (SyncedPed p in PedsByID.Values.ToArray())
{
if (p.OwnerID==playerPedId)
if (p.OwnerID == playerPedId)
{
RemovePed(p.ID);
}
@ -540,7 +532,7 @@ namespace RageCoop.Client
foreach (SyncedVehicle v in VehiclesByID.Values.ToArray())
{
if (v.OwnerID==playerPedId)
if (v.OwnerID == playerPedId)
{
RemoveVehicle(v.ID);
}
@ -550,7 +542,7 @@ namespace RageCoop.Client
public static int RequestNewID()
{
int ID = 0;
while ((ID==0) || PedsByID.ContainsKey(ID) || VehiclesByID.ContainsKey(ID) || ProjectilesByID.ContainsKey(ID))
while ((ID == 0) || PedsByID.ContainsKey(ID) || VehiclesByID.ContainsKey(ID) || ProjectilesByID.ContainsKey(ID))
{
byte[] rngBytes = new byte[4];
@ -581,21 +573,21 @@ namespace RageCoop.Client
{
public static void Add(SyncedVehicle v)
{
lock (EntityPool.VehiclesLock)
lock (VehiclesLock)
{
EntityPool.Add(v);
}
}
public static void Add(SyncedPed p)
{
lock (EntityPool.PedsLock)
lock (PedsLock)
{
EntityPool.Add(p);
}
}
public static void Add(SyncedProjectile sp)
{
lock (EntityPool.ProjectilesLock)
lock (ProjectilesLock)
{
EntityPool.Add(sp);
}

View File

@ -1,10 +1,8 @@
using GTA;
using GTA.Math;
using Lidgren.Network;
using RageCoop.Core;
using System;
using System.Threading;
using System.Threading.Tasks;
using Lidgren.Network;
namespace RageCoop.Client
{
@ -13,7 +11,7 @@ namespace RageCoop.Client
#region TRIGGER
public static void TriggerPedKilled(SyncedPed victim)
{
Networking.SendSync(new Packets.PedKilled() { VictimID=victim.ID }, ConnectionChannel.SyncEvents);
Networking.SendSync(new Packets.PedKilled() { VictimID = victim.ID }, ConnectionChannel.SyncEvents);
}
public static void TriggerChangeOwner(int vehicleID, int newOwnerID)
@ -21,9 +19,9 @@ namespace RageCoop.Client
Networking.SendSync(new Packets.OwnerChanged()
{
ID= vehicleID,
NewOwnerID= newOwnerID,
}, ConnectionChannel.SyncEvents,NetDeliveryMethod.ReliableOrdered);
ID = vehicleID,
NewOwnerID = newOwnerID,
}, ConnectionChannel.SyncEvents, NetDeliveryMethod.ReliableOrdered);
}
@ -33,11 +31,11 @@ namespace RageCoop.Client
var start = owner.MainPed.GetMuzzlePosition();
if (owner.MainPed.IsOnTurretSeat()) { start=owner.MainPed.Bones[Bone.SkelHead].Position; }
if (start.DistanceTo(impactPosition)>10)
if (owner.MainPed.IsOnTurretSeat()) { start = owner.MainPed.Bones[Bone.SkelHead].Position; }
if (start.DistanceTo(impactPosition) > 10)
{
// Reduce latency
start=impactPosition-(impactPosition-start).Normalized*10;
start = impactPosition - (impactPosition - start).Normalized * 10;
}
Networking.SendBullet(start, impactPosition, hash, owner.ID);
}
@ -47,14 +45,14 @@ namespace RageCoop.Client
int i;
// ANNIHL
if (veh.Model.Hash==837858166)
if (veh.Model.Hash == 837858166)
{
Networking.SendVehicleBullet(hash, owner, veh.Bones[35]);
Networking.SendVehicleBullet(hash, owner, veh.Bones[36]);
Networking.SendVehicleBullet(hash, owner, veh.Bones[37]);
Networking.SendVehicleBullet(hash, owner, veh.Bones[38]);
}
else if((i = veh.GetMuzzleIndex())!=-1)
else if ((i = veh.GetMuzzleIndex()) != -1)
{
Networking.SendVehicleBullet(hash, owner, veh.Bones[i]);
}
@ -65,7 +63,7 @@ namespace RageCoop.Client
}
public static void TriggerNozzleTransform(int vehID, bool hover)
{
Networking.SendSync(new Packets.NozzleTransform() { VehicleID=vehID, Hover=hover }, ConnectionChannel.SyncEvents);
Networking.SendSync(new Packets.NozzleTransform() { VehicleID = vehID, Hover = hover }, ConnectionChannel.SyncEvents);
}
#endregion
@ -73,9 +71,8 @@ namespace RageCoop.Client
#region HANDLE
public static ParticleEffectAsset CorePFXAsset = new ParticleEffectAsset("core");
static WeaponAsset _weaponAsset = default;
static uint _lastWeaponHash;
private static WeaponAsset _weaponAsset = default;
private static uint _lastWeaponHash;
private static void HandlePedKilled(Packets.PedKilled p)
{
@ -84,11 +81,11 @@ namespace RageCoop.Client
private static void HandleOwnerChanged(Packets.OwnerChanged p)
{
var v = EntityPool.GetVehicleByID(p.ID);
if (v==null) { return; }
v.OwnerID=p.NewOwnerID;
v.LastSynced=Main.Ticked;
v.Position=v.MainVehicle.Position;
v.Quaternion=v.MainVehicle.Quaternion;
if (v == null) { return; }
v.OwnerID = p.NewOwnerID;
v.LastSynced = Main.Ticked;
v.Position = v.MainVehicle.Position;
v.Quaternion = v.MainVehicle.Quaternion;
}
private static void HandleNozzleTransform(Packets.NozzleTransform p)
{
@ -100,47 +97,47 @@ namespace RageCoop.Client
{
// Minigun, not working for some reason
case (uint)WeaponHash.Minigun:
weaponHash=1176362416;
weaponHash = 1176362416;
break;
// Valkyire, not working for some reason
case 2756787765:
weaponHash=1176362416;
weaponHash = 1176362416;
break;
// Tampa3, not working for some reason
case 3670375085:
weaponHash=1176362416;
weaponHash = 1176362416;
break;
// Ruiner2, not working for some reason
case 50118905:
weaponHash=1176362416;
weaponHash = 1176362416;
break;
// SAVAGE
case 1638077257:
weaponHash=(uint)VehicleWeaponHash.PlayerLazer;
weaponHash = (uint)VehicleWeaponHash.PlayerLazer;
break;
case (uint)VehicleWeaponHash.PlayerBuzzard:
weaponHash=1176362416;
weaponHash = 1176362416;
break;
}
var p = EntityPool.GetPedByID(ownerID)?.MainPed;
if (p == null) { p=Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); }
if (p == null) { return; /* p = Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); */ }
if (!CorePFXAsset.IsLoaded) { CorePFXAsset.Request(); }
if (_lastWeaponHash!=weaponHash)
if (_lastWeaponHash != weaponHash)
{
_weaponAsset.MarkAsNoLongerNeeded();
_weaponAsset=new WeaponAsset(weaponHash);
_lastWeaponHash=weaponHash;
_weaponAsset = new WeaponAsset(weaponHash);
_lastWeaponHash = weaponHash;
}
if (!_weaponAsset.IsLoaded) { _weaponAsset.Request(); }
World.ShootBullet(start, end, p, _weaponAsset, (int)p.GetWeaponDamage(weaponHash));
Prop w;
if (((w = p.Weapons.CurrentWeaponObject) != null)&&(p.VehicleWeapon==VehicleWeaponHash.Invalid))
if (((w = p.Weapons.CurrentWeaponObject) != null) && (p.VehicleWeapon == VehicleWeaponHash.Invalid))
{
if (p.Weapons.Current.Components.GetSuppressorComponent().Active)
{
@ -154,52 +151,47 @@ namespace RageCoop.Client
}
public static void HandleVehicleBulletShot(Packets.VehicleBulletShot p)
{
HandleBulletShot(p.StartPosition,p.EndPosition,p.WeaponHash,p.OwnerID);
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
var v = EntityPool.GetPedByID(p.OwnerID)?.MainPed.CurrentVehicle;
if(v == null) { return; }
if (v == null) { return; }
var b = v.Bones[p.Bone];
World.CreateParticleEffectNonLooped(CorePFXAsset,
WeaponUtil.GetFlashFX((WeaponHash)p.WeaponHash),
b.Position,b.ForwardVector.ToEulerRotation(v.Bones[35].UpVector),1);
b.Position, b.ForwardVector.ToEulerRotation(v.Bones[35].UpVector), 1);
}
public static void HandleEvent(PacketType type, byte[] data)
public static void HandleEvent(PacketType type, NetIncomingMessage msg)
{
switch (type)
{
case PacketType.BulletShot:
{
Packets.BulletShot p = new Packets.BulletShot();
p.Deserialize(data);
p.Deserialize(msg);
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
break;
}
case PacketType.VehicleBulletShot:
{
HandleVehicleBulletShot(data.GetPacket<Packets.VehicleBulletShot>());
HandleVehicleBulletShot(msg.GetPacket<Packets.VehicleBulletShot>());
break;
}
case PacketType.OwnerChanged:
{
Packets.OwnerChanged packet = new Packets.OwnerChanged();
packet.Deserialize(data);
HandleOwnerChanged(packet);
HandleOwnerChanged(msg.GetPacket<Packets.OwnerChanged>());
}
break;
case PacketType.PedKilled:
{
var packet = new Packets.PedKilled();
packet.Deserialize(data);
HandlePedKilled(packet);
HandlePedKilled(msg.GetPacket<Packets.PedKilled>());
}
break;
case PacketType.NozzleTransform:
{
var packet = new Packets.NozzleTransform();
packet.Deserialize(data);
HandleNozzleTransform(packet);
HandleNozzleTransform(msg.GetPacket<Packets.NozzleTransform>());
break;
}
}
Networking.Peer.Recycle(msg);
}
#endregion
@ -220,9 +212,9 @@ namespace RageCoop.Client
Func<bool> getBulletImpact = (() =>
{
Vector3 endPos = subject.LastWeaponImpactPosition;
if (endPos==default)
if (endPos == default)
{
if (++i<=5) { return false; }
if (++i <= 5) { return false; }
endPos = subject.GetAimCoord();
if (subject.IsInVehicle() && subject.VehicleWeapon != VehicleWeaponHash.Invalid)
@ -267,7 +259,7 @@ namespace RageCoop.Client
Main.QueueAction(getBulletImpact);
}
}
else if (subject.VehicleWeapon==VehicleWeaponHash.Tank && subject.LastWeaponImpactPosition!=default)
else if (subject.VehicleWeapon == VehicleWeaponHash.Tank && subject.LastWeaponImpactPosition != default)
{
TriggerBulletShot((uint)VehicleWeaponHash.Tank, c, subject.LastWeaponImpactPosition);
}
@ -276,7 +268,7 @@ namespace RageCoop.Client
public static void Check(SyncedVehicle v)
{
if (v.MainVehicle==null||!v.MainVehicle.HasNozzle())
if (v.MainVehicle == null || !v.MainVehicle.HasNozzle())
{
return;
}

View File

@ -1,6 +1,5 @@
using System.Threading;
using NAudio.Wave;
using NAudio.Wave;
using System.Threading;
namespace RageCoop.Client
{

View File

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

View File

@ -1,18 +1,19 @@

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

View File

@ -1,152 +1,145 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA;
using GTA.Math;
using GTA.Native;
using GTA.Math;
using System;
using System.Runtime.InteropServices;
using LemonUI.Elements;
using System.Drawing;
namespace RageCoop.Client
{
[StructLayout(LayoutKind.Explicit, Size = 80)]
public struct HeadBlendData
{
[FieldOffset(0)]
public int ShapeFirst;
[StructLayout(LayoutKind.Explicit, Size = 80)]
public struct HeadBlendData
{
[FieldOffset(0)]
public int ShapeFirst;
[FieldOffset(8)]
public int ShapeSecond;
[FieldOffset(8)]
public int ShapeSecond;
[FieldOffset(16)]
public int ShapeThird;
[FieldOffset(16)]
public int ShapeThird;
[FieldOffset(24)]
public int SkinFirst;
[FieldOffset(24)]
public int SkinFirst;
[FieldOffset(32)]
public int SkinSecond;
[FieldOffset(32)]
public int SkinSecond;
[FieldOffset(40)]
public int SkinThird;
[FieldOffset(40)]
public int SkinThird;
[FieldOffset(48)]
public float ShapeMix;
[FieldOffset(48)]
public float ShapeMix;
[FieldOffset(56)]
public float SkinMix;
[FieldOffset(56)]
public float SkinMix;
[FieldOffset(64)]
public float ThirdMix;
}
[FieldOffset(64)]
public float ThirdMix;
}
[StructLayout(LayoutKind.Explicit, Size = 24)]
public struct NativeVector3
{
[FieldOffset(0)]
public float X;
[StructLayout(LayoutKind.Explicit, Size = 24)]
public struct NativeVector3
{
[FieldOffset(0)]
public float X;
[FieldOffset(8)]
public float Y;
[FieldOffset(8)]
public float Y;
[FieldOffset(16)]
public float Z;
[FieldOffset(16)]
public float Z;
public static implicit operator Vector3(NativeVector3 vec)
public static implicit operator Vector3(NativeVector3 vec)
{
return new Vector3() { X=vec.X, Y=vec.Y, Z=vec.Z };
return new Vector3() { X = vec.X, Y = vec.Y, Z = vec.Z };
}
public static implicit operator NativeVector3(Vector3 vec)
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")]
static extern void NativeInit(ulong hash);
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")]
static extern void NativePush64(ulong val);
[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")]
static extern unsafe ulong* NativeCall();
[DllImport("ScriptHookV.dll", ExactSpelling = true, EntryPoint = "?nativeCall@@YAPEA_KXZ")]
private static extern unsafe ulong* NativeCall();
// These are from ScriptHookV's nativeCaller.h
static unsafe void NativePush<T>(T val) where T : unmanaged
{
ulong val64 = 0;
*(T*)(&val64) = val;
NativePush64(val64);
}
// 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);
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());
}
return *(R*)(NativeCall());
}
/// <summary>
/// Helper function that converts an array of primitive values to a native stack.
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
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] = (ulong)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;
}
/// <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));
}
throw new ArgumentException("Unknown primitive type in native argument list", nameof(args));
}
return result;
}
}
return result;
}
}
}

View File

@ -2,8 +2,8 @@
using GTA.Math;
using GTA.Native;
using RageCoop.Core;
using System.Collections.Generic;
using System;
using System.Collections.Generic;
namespace RageCoop.Client
{
@ -80,9 +80,9 @@ namespace RageCoop.Client
var result = new byte[36];
for (byte i = 0; i < 12; i++)
{
result[i]=(byte)Function.Call<short>(Hash.GET_PED_DRAWABLE_VARIATION, ped.Handle, i);
result[i+12]=(byte)Function.Call<short>(Hash.GET_PED_TEXTURE_VARIATION, ped.Handle, i);
result[i+24]=(byte)Function.Call<short>(Hash.GET_PED_PALETTE_VARIATION, ped.Handle, i);
result[i] = (byte)Function.Call<short>(Hash.GET_PED_DRAWABLE_VARIATION, ped.Handle, i);
result[i + 12] = (byte)Function.Call<short>(Hash.GET_PED_TEXTURE_VARIATION, ped.Handle, i);
result[i + 24] = (byte)Function.Call<short>(Hash.GET_PED_PALETTE_VARIATION, ped.Handle, i);
}
return result;
}
@ -108,7 +108,7 @@ namespace RageCoop.Client
}
// Fake death
if (ped.IsRagdoll || (ped.Health==1 && ped.IsPlayer))
if (ped.IsRagdoll || (ped.Health == 1 && ped.IsPlayer))
{
flags |= PedDataFlags.IsRagdoll;
}
@ -144,14 +144,15 @@ namespace RageCoop.Client
flags |= PedDataFlags.IsInCover;
if (ped.IsInCoverFacingLeft)
{
flags |=PedDataFlags.IsInCover;
flags |= PedDataFlags.IsInCover;
}
if (!Function.Call<bool>(Hash.IS_PED_IN_HIGH_COVER, ped)){
flags|=PedDataFlags.IsInLowCover;
if (!Function.Call<bool>(Hash.IS_PED_IN_HIGH_COVER, ped))
{
flags |= PedDataFlags.IsInLowCover;
}
if (ped.IsTaskActive(TaskType.CTaskAimGunBlindFire))
{
flags|=PedDataFlags.IsBlindFiring;
flags |= PedDataFlags.IsBlindFiring;
}
}
@ -276,7 +277,7 @@ namespace RageCoop.Client
veh,
veh.Bones[text].Index
}));
bool flag2 = (num2 < distanceToignoreDoors) && (num2 < num)&& IsSeatUsableByPed(ped, veh, dictionary[text]);
bool flag2 = (num2 < distanceToignoreDoors) && (num2 < num) && IsSeatUsableByPed(ped, veh, dictionary[text]);
if (flag2)
{
num = num2;
@ -295,7 +296,7 @@ namespace RageCoop.Client
{
result = true;
}
else
else if (veh.GetPedOnSeat(seat) != null)
{
bool isDead = veh.GetPedOnSeat(seat).IsDead;
@ -330,29 +331,29 @@ namespace RageCoop.Client
var v = p.CurrentVehicle;
// Rhino
if (v!=null && v.Model.Hash==782665360)
if (v != null && v.Model.Hash == 782665360)
{
return v.Bones[35].Position+v.Bones[35].ForwardVector*100;
return v.Bones[35].Position + v.Bones[35].ForwardVector * 100;
}
if (p.IsOnTurretSeat()) { return p.GetLookingCoord(); }
if (weapon!=null)
if (weapon != null)
{
// Not very accurate, but doesn't matter
Vector3 dir = weapon.RightVector;
return weapon.Position+dir*20;
return weapon.Position + dir * 20;
}
return GetLookingCoord(p);
}
public static Vector3 GetLookingCoord(this Ped p)
{
if (p==Main.P && Function.Call<int>(Hash.GET_FOLLOW_PED_CAM_VIEW_MODE)==4)
if (p == Main.P && Function.Call<int>(Hash.GET_FOLLOW_PED_CAM_VIEW_MODE) == 4)
{
return RaycastEverything(default);
}
EntityBone b = p.Bones[Bone.FacialForehead];
Vector3 v = b.UpVector.Normalized;
return b.Position+200*v;
return b.Position + 200 * v;
}
public static VehicleSeat GetSeatTryingToEnter(this Ped p)
{
@ -475,7 +476,7 @@ namespace RageCoop.Client
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus3;
case 0:
return (VehicleHash)veh.Model.Hash == VehicleHash.Apc
|| (VehicleHash)veh.Model.Hash==VehicleHash.Dune3;
|| (VehicleHash)veh.Model.Hash == VehicleHash.Dune3;
case 1:
return (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie
|| (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie2

View File

@ -6,13 +6,10 @@ using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("RageCoop.Client.Installer")]
namespace RageCoop.Client
@ -42,7 +39,7 @@ namespace RageCoop.Client
var res = ResolutionMaintainRatio;
if (Function.Call<bool>(Hash.GET_SCREEN_COORD_FROM_WORLD_COORD, pos.X, pos.Y, pos.Z, &x, &y))
{
screenPos =new Point((int)(res.Width*x), (int)(y*1080));
screenPos = new Point((int)(res.Width * x), (int)(y * 1080));
return true;
}
}
@ -114,7 +111,7 @@ namespace RageCoop.Client
#endregion
public static string SettingsPath = "Scripts\\RageCoop\\Data\\RageCoop.Client.Settings.xml";
public static Settings ReadSettings(string path=null)
public static Settings ReadSettings(string path = null)
{
path = path ?? SettingsPath;
XmlSerializer ser = new XmlSerializer(typeof(Settings));
@ -139,7 +136,7 @@ namespace RageCoop.Client
return settings;
}
public static bool SaveSettings(string path = null,Settings settings=null)
public static bool SaveSettings(string path = null, Settings settings = null)
{
try
{
@ -192,7 +189,7 @@ namespace RageCoop.Client
{
if (p == null) { return null; }
var c = EntityPool.GetPedByHandle(p.Handle);
if (c==null) { EntityPool.Add(c=new SyncedPed(p)); }
if (c == null) { EntityPool.Add(c = new SyncedPed(p)); }
return c;
}
@ -200,7 +197,7 @@ namespace RageCoop.Client
{
if (veh == null) { return null; }
var v = EntityPool.GetVehicleByHandle(veh.Handle);
if (v==null) { EntityPool.Add(v=new SyncedVehicle(veh)); }
if (v == null) { EntityPool.Add(v = new SyncedVehicle(veh)); }
return v;
}
@ -219,7 +216,7 @@ namespace RageCoop.Client
#region WIN32
const UInt32 WM_KEYDOWN = 0x0100;
private const UInt32 WM_KEYDOWN = 0x0100;
public static void Reload()
{
string reloadKey = "None";
@ -227,18 +224,19 @@ namespace RageCoop.Client
foreach (var l in lines)
{
var ss = l.Split('=');
if (ss.Length > 0 && ss[0]=="ReloadKey")
if (ss.Length > 0 && ss[0] == "ReloadKey")
{
reloadKey = ss[1];
}
}
var lineList = lines.ToList();
if (reloadKey=="None")
if (reloadKey == "None")
{
foreach (var l in lines)
{
var ss = l.Split('=');
if (ss.Length > 0 && ss[0]=="ReloadKey")
ss.ForEach(s => s.Replace(" ", ""));
if (ss.Length > 0 && ss[0] == "ReloadKey")
{
reloadKey = ss[1];
lineList.Remove(l);
@ -253,7 +251,7 @@ namespace RageCoop.Client
// Move log file so it doesn't get deleted
Main.Logger.Dispose();
var path = Main.Logger.LogPath+".last.log";
var path = Main.Logger.LogPath + ".last.log";
try
{
if (File.Exists(path)) { File.Delete(path); }
@ -268,7 +266,7 @@ namespace RageCoop.Client
}
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
private static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
[DllImport("kernel32.dll")]

View File

@ -12,7 +12,7 @@ namespace RageCoop.Client
public static VehicleDataFlags GetVehicleFlags(this SyncedVehicle v)
{
var veh=v.MainVehicle;
var veh = v.MainVehicle;
VehicleDataFlags flags = 0;
if (veh.IsEngineRunning)
@ -50,51 +50,58 @@ namespace RageCoop.Client
flags |= VehicleDataFlags.IsHornActive;
}
if (v.IsSubmarineCar && Function.Call<bool>(Hash._GET_IS_SUBMARINE_VEHICLE_TRANSFORMED, veh.Handle))
if (v.IsSubmarineCar && Function.Call<bool>(Hash.IS_VEHICLE_IN_SUBMARINE_MODE, veh.Handle))
{
flags |= VehicleDataFlags.IsTransformed;
}
if (v.IsAircraft)
{
flags |= VehicleDataFlags.IsAircraft;
}
if (v.IsDeluxo && veh.IsDeluxoHovering())
{
flags|= VehicleDataFlags.IsDeluxoHovering;
}
if (v.HasRoof)
{
flags|=VehicleDataFlags.HasRoof;
}
if (v.HasRocketBoost && veh.IsRocketBoostActive())
{
flags|=VehicleDataFlags.IsRocketBoostActive;
}
if(v.HasParachute && veh.IsParachuteActive()){
flags|=VehicleDataFlags.IsParachuteActive;
}
if (veh.IsOnFire)
{
flags|=VehicleDataFlags.IsOnFire;
flags |= VehicleDataFlags.IsDeluxoHovering;
}
if (v.HasRoof)
{
flags |= VehicleDataFlags.HasRoof;
}
if (v.HasRocketBoost && veh.IsRocketBoostActive())
{
flags |= VehicleDataFlags.IsRocketBoostActive;
}
if (v.HasParachute && veh.IsParachuteActive())
{
flags |= VehicleDataFlags.IsParachuteActive;
}
if (veh.IsOnFire)
{
flags |= VehicleDataFlags.IsOnFire;
}
return flags;
}
public static bool IsRocketBoostActive(this Vehicle veh)
{
return Function.Call<bool>(Hash._IS_VEHICLE_ROCKET_BOOST_ACTIVE,veh);
return Function.Call<bool>(Hash.IS_ROCKET_BOOST_ACTIVE, veh);
}
public static bool IsParachuteActive(this Vehicle veh){
return Function.Call<bool>((Hash)0x3DE51E9C80B116CF,veh);
}
public static void SetRocketBoostActive(this Vehicle veh,bool toggle)
public static bool IsParachuteActive(this Vehicle veh)
{
Function.Call(Hash._SET_VEHICLE_ROCKET_BOOST_ACTIVE,veh,toggle);
return Function.Call<bool>((Hash)0x3DE51E9C80B116CF, veh);
}
public static void SetParachuteActive(this Vehicle veh,bool toggle)
public static void SetRocketBoostActive(this Vehicle veh, bool toggle)
{
Function.Call((Hash)0x0BFFB028B3DD0A97,veh,toggle);
Function.Call(Hash.SET_ROCKET_BOOST_ACTIVE, veh, toggle);
}
public static void SetParachuteActive(this Vehicle veh, bool toggle)
{
Function.Call((Hash)0x0BFFB028B3DD0A97, veh, toggle);
}
public static Dictionary<int, int> GetVehicleMods(this VehicleModCollection mods)
{
@ -133,7 +140,6 @@ namespace RageCoop.Client
}
}
// Bursted tires
short burstedTires = 0;
foreach (VehicleWheel wheel in veh.Wheels.GetAllWheels())
@ -176,7 +182,7 @@ namespace RageCoop.Client
}
if ((model.OpenedDoors & (byte)(1 << i)) != 0)
{
if ((!door.IsOpen)&&(!door.IsBroken))
if ((!door.IsOpen) && (!door.IsBroken))
{
door.Open();
}
@ -220,7 +226,7 @@ namespace RageCoop.Client
{
Dictionary<int, int> ps = new Dictionary<int, int>();
var d = veh.Driver;
if (d!=null&&d.IsSittingInVehicle())
if (d != null && d.IsSittingInVehicle())
{
ps.Add(-1, d.GetSyncEntity().ID);
}
@ -228,32 +234,31 @@ namespace RageCoop.Client
{
if (p.IsSittingInVehicle())
{
ps.Add((int)p.SeatIndex, (int)p.GetSyncEntity().ID);
ps.Add((int)p.SeatIndex, p.GetSyncEntity().ID);
}
}
return ps;
}
public static void SetDeluxoHoverState(this Vehicle deluxo, bool hover)
{
Function.Call(Hash._SET_VEHICLE_HOVER_TRANSFORM_PERCENTAGE, deluxo, hover ? 1f : 0f);
Function.Call(Hash.SET_SPECIAL_FLIGHT_MODE_TARGET_RATIO, deluxo, hover ? 1f : 0f);
}
public static bool IsDeluxoHovering(this Vehicle deluxo)
{
return Math.Abs(deluxo.Bones[27].ForwardVector.GetCosTheta(deluxo.ForwardVector)-1)>0.05;
return Math.Abs(deluxo.Bones[27].ForwardVector.GetCosTheta(deluxo.ForwardVector) - 1) > 0.05;
}
public static void SetDeluxoWingRatio(this Vehicle v, float ratio)
{
Function.Call(Hash._SET_SPECIALFLIGHT_WING_RATIO, v, ratio);
Function.Call(Hash.SET_HOVER_MODE_WING_RATIO, v, ratio);
}
public static float GetDeluxoWingRatio(this Vehicle v)
{
return v.Bones[99].Position.DistanceTo(v.Bones[92].Position)-1.43f;
return v.Bones[99].Position.DistanceTo(v.Bones[92].Position) - 1.43f;
}
public static float GetNozzleAngel(this Vehicle plane)
{
return Function.Call<float>(Hash._GET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane);
return Function.Call<float>(Hash.GET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane);
}
public static bool HasNozzle(this Vehicle v)
{
@ -283,8 +288,6 @@ namespace RageCoop.Client
{
Function.Call(Hash.SET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane, ratio);
}
#endregion
}
}

View File

@ -2,7 +2,6 @@
using GTA.Math;
using GTA.Native;
using System.Collections.Generic;
using System.Xml;
namespace RageCoop.Client
{
@ -11,7 +10,7 @@ namespace RageCoop.Client
public MuzzleInfo(Vector3 pos, Vector3 forward)
{
Position = pos;
ForawardVector=forward;
ForawardVector = forward;
}
public Vector3 Position;
public Vector3 ForawardVector;
@ -38,7 +37,7 @@ namespace RageCoop.Client
public static Vector3 GetMuzzlePosition(this Ped p)
{
var w = p.Weapons.CurrentWeaponObject;
if (w!=null)
if (w != null)
{
var hash = p.Weapons.Current.Hash;
if (MuzzleBoneIndexes.ContainsKey(hash)) { return w.Bones[MuzzleBoneIndexes[hash]].Position; }
@ -46,7 +45,8 @@ namespace RageCoop.Client
}
return p.Bones[Bone.SkelRightHand].Position;
}
static long BulletsShot = 0;
private static long BulletsShot = 0;
public static float GetWeaponDamage(this Ped P, uint hash)
{
@ -103,49 +103,49 @@ namespace RageCoop.Client
// ISSI6
case 1239571361:
return BulletsShot%2==0 ? 12 : 14;
return BulletsShot % 2 == 0 ? 12 : 14;
// ISSI5
case 1537277726:
return BulletsShot%2==0 ? 30 : 32;
return BulletsShot % 2 == 0 ? 30 : 32;
// ISSI4
case 628003514:
return BulletsShot%2==0 ? 14 : 12;
return BulletsShot % 2 == 0 ? 14 : 12;
// DOMINATOR6
case -1293924613:
return BulletsShot%2==0 ? 51 : 55;
return BulletsShot % 2 == 0 ? 51 : 55;
// IMPALER4
case -1744505657:
return BulletsShot%2==0 ? 64 : 63;
return BulletsShot % 2 == 0 ? 64 : 63;
// IMPERATOR3
case -755532233:
return BulletsShot%2==0 ? 86 : 88;
return BulletsShot % 2 == 0 ? 86 : 88;
// SLAMVAN6
case 1742022738:
return BulletsShot%2==0 ? 78 : 76;
return BulletsShot % 2 == 0 ? 78 : 76;
// CHAMPION
case -915234475:
return BulletsShot%2==0 ? 60 : 61;
return BulletsShot % 2 == 0 ? 60 : 61;
// MONSTER4
case 840387324:
return BulletsShot%2==0 ? 63 : 65;
return BulletsShot % 2 == 0 ? 63 : 65;
// BRUTUS2
@ -154,7 +154,7 @@ namespace RageCoop.Client
// BRUISER2
case -1694081890:
return BulletsShot%2==0 ? 45 : 51;
return BulletsShot % 2 == 0 ? 45 : 51;
// TECHNICAL3
@ -171,11 +171,11 @@ namespace RageCoop.Client
// PATRIOT3
case -670086588:
return BulletsShot%2==0 ? 87 : 89;
return BulletsShot % 2 == 0 ? 87 : 89;
// NIGHTSHARK
case 433954513:
return BulletsShot%2==0 ? 1 : 2;
return BulletsShot % 2 == 0 ? 1 : 2;
/*
// NIGHTSHARK (second)
@ -185,7 +185,7 @@ namespace RageCoop.Client
// MENACER
case 2044532910:
return BulletsShot%2==0 ? 91 : 90;
return BulletsShot % 2 == 0 ? 91 : 90;
/*
// MENACER
case 2044532910:
@ -222,11 +222,11 @@ namespace RageCoop.Client
// BLAZER5
case -1590337689:
return BulletsShot%2==0 ? 17 : 18;
return BulletsShot % 2 == 0 ? 17 : 18;
// BRUISER
case 668439077:
return BulletsShot%2==0 ? 66 : 68;
return BulletsShot % 2 == 0 ? 66 : 68;
// BRUTUS
@ -236,12 +236,12 @@ namespace RageCoop.Client
// MONSTER3
case 1721676810:
return BulletsShot%2==0 ? 53 : 55;
return BulletsShot % 2 == 0 ? 53 : 55;
// BRUISER3
case -2042350822:
return BulletsShot%2==0 ? 52 : 50;
return BulletsShot % 2 == 0 ? 52 : 50;
// BRUTUS3
case 2038858402:
@ -249,34 +249,34 @@ namespace RageCoop.Client
// MONSTER5
case -715746948:
return BulletsShot%2==0 ? 63 : 65;
return BulletsShot % 2 == 0 ? 63 : 65;
// JB7002
case 394110044:
return BulletsShot%2==0 ? 54 : 53;
return BulletsShot % 2 == 0 ? 54 : 53;
// DOMINATOR5
case -1375060657:
return BulletsShot%2==0 ? 35 : 36;
return BulletsShot % 2 == 0 ? 35 : 36;
// IMPALER3
case -1924800695:
return BulletsShot%2==0 ? 75 : 76;
return BulletsShot % 2 == 0 ? 75 : 76;
// IMPERATOR2
case 1637620610:
return BulletsShot%2==0 ? 97 : 99;
return BulletsShot % 2 == 0 ? 97 : 99;
// SLAMVAN5
case 373261600:
return BulletsShot%2==0 ? 51 : 53;
return BulletsShot % 2 == 0 ? 51 : 53;
// RUINER2
case 941494461:
return BulletsShot%2==0 ? 65 : 66;
return BulletsShot % 2 == 0 ? 65 : 66;
// TAMPA3
@ -285,52 +285,52 @@ namespace RageCoop.Client
// SCRAMJET
case -638562243:
return BulletsShot%2==0 ? 44 : 45;
return BulletsShot % 2 == 0 ? 44 : 45;
// VIGILANTE
case -1242608589:
return BulletsShot%2==0 ? 42 : 43;
return BulletsShot % 2 == 0 ? 42 : 43;
// ZR380
case 540101442:
return BulletsShot%2==0 ? 57 : 63;
return BulletsShot % 2 == 0 ? 57 : 63;
// ZR3802
case -1106120762:
return BulletsShot%2==0 ? 57 : 63;
return BulletsShot % 2 == 0 ? 57 : 63;
// ZR3803
case -1478704292:
return BulletsShot%2==0 ? 53 : 59;
return BulletsShot % 2 == 0 ? 53 : 59;
// STROMBERG
case 886810209:
return BulletsShot%2==0 ? 85 : 84;
return BulletsShot % 2 == 0 ? 85 : 84;
// SLAMVAN4
case -2061049099:
return BulletsShot%2==0 ? 76 : 78;
return BulletsShot % 2 == 0 ? 76 : 78;
// IMPERATOR
case 444994115:
return BulletsShot%2==0 ? 88 : 86;
return BulletsShot % 2 == 0 ? 88 : 86;
// IMPALER2
case 1009171724:
return BulletsShot%2==0 ? 63 : 64;
return BulletsShot % 2 == 0 ? 63 : 64;
// DOMINATOR4
case -688189648:
return BulletsShot%2==0 ? 59 : 60;
return BulletsShot % 2 == 0 ? 59 : 60;
// SAVAGE
@ -339,22 +339,22 @@ namespace RageCoop.Client
// BUZZARD
case 788747387:
return BulletsShot%2==0 ? 28 : 23;
return BulletsShot % 2 == 0 ? 28 : 23;
// ANNIHL
case 837858166:
return (int)BulletsShot%4+35;
return (int)BulletsShot % 4 + 35;
// HYDRA
case 970385471:
return BulletsShot%2==0 ? 29 : 28;
return BulletsShot % 2 == 0 ? 29 : 28;
// STARLING
case -1700874274:
return BulletsShot%2==0 ? 24 : 12;
return BulletsShot % 2 == 0 ? 24 : 12;
// RHINO
@ -362,26 +362,20 @@ namespace RageCoop.Client
return 30;
default:
return -1;
return AddOnDataProvider.GetMuzzleIndex(v.Model.Hash);
}
}
public static bool IsUsingProjectileWeapon(this Ped p)
{
var vp = p.VehicleWeapon;
var type = Function.Call<int>(Hash.GET_WEAPON_DAMAGE_TYPE, vp);
if (vp!=VehicleWeaponHash.Invalid)
if (vp != VehicleWeaponHash.Invalid)
{
if (type==3)
{
return false;
}
return VehicleProjectileWeapons.Contains(vp) || (type==5 && !ExplosiveBullets.Contains((uint)vp));
}
else
{
var w = p.Weapons.Current;
return w.Group==WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
return type == 3 ? false : VehicleProjectileWeapons.Contains(vp) || (type == 5 && !ExplosiveBullets.Contains((uint)vp));
}
var w = p.Weapons.Current;
return w.Group == WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
}
public static readonly HashSet<uint> ExplosiveBullets = new HashSet<uint>
@ -460,7 +454,6 @@ namespace RageCoop.Client
};
public static readonly HashSet<WeaponHash> ProjectileWeapons = new HashSet<WeaponHash> {
WeaponHash.HomingLauncher,
WeaponHash.RPG,

View File

@ -1,8 +1,6 @@
using GTA;
using GTA.Native;
using System;
using System.Threading.Tasks;
using System.Threading;
namespace RageCoop.Client
{
@ -22,28 +20,11 @@ namespace RageCoop.Client
{
ChangeTraffic(true);
};
Task.Run(() =>
{
while (true)
{
Thread.Sleep(5000);
Main.QueueAction(() => { ChangeTraffic(_trafficEnabled); });
}
});
}
static bool _trafficEnabled;
private static bool _trafficEnabled;
private void OnTick(object sender, EventArgs e)
{
if (!_trafficEnabled)
{
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 0);
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
Function.Call(Hash.SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
Function.Call(Hash.SET_RANDOM_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
Function.Call(Hash.SET_PARKED_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
Function.Call(Hash.SUPPRESS_SHOCKING_EVENTS_NEXT_FRAME);
Function.Call(Hash.SUPPRESS_AGITATION_EVENTS_NEXT_FRAME);
}
if (Game.IsLoading || !Networking.IsOnServer)
{
return;
@ -84,6 +65,16 @@ namespace RageCoop.Client
}
}
}
if (!_trafficEnabled)
{
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 0);
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
Function.Call(Hash.SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
Function.Call(Hash.SET_RANDOM_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
Function.Call(Hash.SET_PARKED_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
Function.Call(Hash.SUPPRESS_SHOCKING_EVENTS_NEXT_FRAME);
Function.Call(Hash.SUPPRESS_AGITATION_EVENTS_NEXT_FRAME);
}
}
public static void Traffic(bool enable)
{
@ -94,7 +85,7 @@ namespace RageCoop.Client
{
if (enable)
{
// Function.Call(Hash.REMOVE_SCENARIO_BLOCKING_AREAS);
Function.Call(Hash.REMOVE_SCENARIO_BLOCKING_AREAS);
Function.Call(Hash.SET_CREATE_RANDOM_COPS, true);
Function.Call(Hash.SET_RANDOM_TRAINS, true);
Function.Call(Hash.SET_RANDOM_BOATS, true);
@ -107,9 +98,9 @@ namespace RageCoop.Client
Function.Call(Hash.SET_DISTANT_CARS_ENABLED, true);
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, false);
}
else
else if (Networking.IsOnServer)
{
// Function.Call(Hash.ADD_SCENARIO_BLOCKING_AREA, -10000.0f, -10000.0f, -1000.0f, 10000.0f, 10000.0f, 1000.0f, 0, 1, 1, 1);
Function.Call(Hash.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_RANDOM_TRAINS, false);
Function.Call(Hash.SET_RANDOM_BOATS, false);
@ -122,64 +113,33 @@ namespace RageCoop.Client
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, 0);
Function.Call(Hash.SET_DISTANT_CARS_ENABLED, false);
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, true);
if (Networking.IsOnServer)
foreach (Ped ped in World.GetAllPeds())
{
foreach (Ped ped in World.GetAllPeds())
if (ped == Game.Player.Character) { continue; }
SyncedPed c = EntityPool.GetPedByHandle(ped.Handle);
if ((c == null) || (c.IsLocal && (ped.Handle != Game.Player.Character.Handle) && ped.PopulationType != EntityPopulationType.Mission))
{
SyncedPed c = EntityPool.GetPedByHandle(ped.Handle);
if ((c == null) || (c.IsLocal && (ped.Handle != Game.Player.Character.Handle) && ped.PopulationType != EntityPopulationType.Mission))
{
if (ped.Handle == Game.Player.Character.Handle) { continue; }
// Main.Logger.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
ped.CurrentVehicle?.Delete();
ped.Kill();
ped.Delete();
}
}
foreach (Vehicle veh in World.GetAllVehicles())
{
SyncedVehicle v = veh.GetSyncEntity();
if (v.MainVehicle == Game.Player.LastVehicle)
{
// Don't delete player's vehicle
continue;
}
if ((v == null) || (v.IsLocal && veh.PopulationType != EntityPopulationType.Mission))
{
// Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
veh.Delete();
}
Main.Logger.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
ped.CurrentVehicle?.Delete();
ped.Kill();
ped.Delete();
}
}
else
foreach (Vehicle veh in World.GetAllVehicles())
{
foreach (Ped ped in World.GetAllPeds())
SyncedVehicle v = veh.GetSyncEntity();
if (v.MainVehicle == Game.Player.LastVehicle || v.MainVehicle == Game.Player.Character.CurrentVehicle)
{
if ((ped != Game.Player.Character) && (ped.PopulationType != EntityPopulationType.Mission))
{
// Main.Logger.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
ped.CurrentVehicle?.Delete();
ped.Kill();
ped.Delete();
}
// Don't delete player's vehicle
continue;
}
var last = Game.Player.Character.LastVehicle;
var current = Game.Player.Character.CurrentVehicle;
foreach (Vehicle veh in World.GetAllVehicles())
if ((v == null) || (v.IsLocal && veh.PopulationType != EntityPopulationType.Mission))
{
if (veh.PopulationType != EntityPopulationType.Mission && veh != last && veh!=current)
{
// Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
// Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
veh.Delete();
}
veh.Delete();
}
}
}

View File

@ -1,15 +1,13 @@
using System;
using System.Text;
using System.Linq;
using GTA.Math;
using GTA.Math;
using System.IO;
using System.Text;
namespace RageCoop.Core
{
internal class BitReader:BinaryReader
internal class BitReader : BinaryReader
{
public BitReader(byte[] array):base(new MemoryStream(array))
public BitReader(byte[] array) : base(new MemoryStream(array))
{
}

View File

@ -1,17 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA.Math;
using System.Security.Cryptography;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.IO;
using System.Runtime.CompilerServices;
using GTA.Math;
using Lidgren.Network;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
[assembly: InternalsVisibleTo("RageCoop.Server")]
[assembly: InternalsVisibleTo("RageCoop.Client")]
@ -33,43 +34,44 @@ namespace RageCoop.Core
{
return ToIgnore.Contains(name);
}
public static (byte, byte[]) GetBytesFromObject(object obj)
public static void GetBytesFromObject(object obj, NetOutgoingMessage m)
{
switch (obj)
{
case byte _:
return (0x01, new byte[] { (byte)obj });
case short _:
return (0x02, BitConverter.GetBytes((short)obj));
case ushort _:
return (0x03, BitConverter.GetBytes((ushort)obj));
case int _:
return (0x04, BitConverter.GetBytes((int)obj));
case uint _:
return (0x05, BitConverter.GetBytes((uint)obj));
case long _:
return (0x06, BitConverter.GetBytes((long)obj));
case ulong _:
return (0x07, BitConverter.GetBytes((ulong)obj));
case float _:
return (0x08, BitConverter.GetBytes((float)obj));
case bool _:
return (0x09, BitConverter.GetBytes((bool)obj));
case string _:
return (0x10, ((string)obj).GetBytesWithLength());
case Vector3 _:
return (0x11,((Vector3)obj).GetBytes());
case Quaternion _:
return (0x12, ((Quaternion)obj).GetBytes());
case GTA.Model _:
return (0x13, BitConverter.GetBytes((GTA.Model)obj));
case Vector2 _:
return (0x14, ((Vector2)obj).GetBytes());
case Tuple<byte, byte[]> _:
var tup = (Tuple<byte, byte[]>)obj;
return (tup.Item1, tup.Item2);
case byte value:
m.Write((byte)0x01); m.Write(value); break;
case short value:
m.Write((byte)0x02); m.Write(value); break;
case ushort value:
m.Write((byte)0x03); m.Write(value); break;
case int value:
m.Write((byte)0x04); m.Write(value); break;
case uint value:
m.Write((byte)0x05); m.Write(value); break;
case long value:
m.Write((byte)0x06); m.Write(value); break;
case ulong value:
m.Write((byte)0x07); m.Write(value); break;
case float value:
m.Write((byte)0x08); m.Write(value); break;
case bool value:
m.Write((byte)0x09); m.Write(value); break;
case string value:
m.Write((byte)0x10); m.Write(value); break;
case Vector3 value:
m.Write((byte)0x11); m.Write(value); break;
case Quaternion value:
m.Write((byte)0x12); m.Write(value); break;
case GTA.Model value:
m.Write((byte)0x13); m.Write(value); break;
case Vector2 value:
m.Write((byte)0x14); m.Write(value); break;
case byte[] value:
m.Write((byte)0x15); m.WriteByteArray(value); break;
case Tuple<byte, byte[]> value:
m.Write(value.Item1); m.Write(value.Item2); break;
default:
return (0x0, null);
throw new Exception("Unsupported object type: " + obj.GetType());
}
}
public static IPEndPoint StringToEndPoint(string endpointstring)
@ -136,9 +138,8 @@ namespace RageCoop.Core
private static int getPort(string p)
{
int port;
if (!int.TryParse(p, out port)
if (!int.TryParse(p, out int port)
|| port < IPEndPoint.MinPort
|| port > IPEndPoint.MaxPort)
{
@ -147,7 +148,7 @@ namespace RageCoop.Core
return port;
}
public static IPAddress GetLocalAddress(string target= "8.8.8.8")
public static IPAddress GetLocalAddress(string target = "8.8.8.8")
{
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
{
@ -190,7 +191,40 @@ namespace RageCoop.Core
foreach (FileInfo file in source.GetFiles())
file.CopyTo(Path.Combine(target.FullName, file.Name), true);
}
public static string GetInvariantRID()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return "win-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return "linux-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return "osx-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
}
return "unknown";
}
/// <summary>
/// Get local ip addresses on all network interfaces
/// </summary>
/// <returns></returns>
public static List<IPAddress> GetLocalAddress()
{
var addresses = new List<IPAddress>();
foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
{
IPInterfaceProperties ipProps = netInterface.GetIPProperties();
foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
{
addresses.Add(addr.Address);
}
}
return addresses;
}
}
internal class IpInfo
{
@ -202,74 +236,10 @@ namespace RageCoop.Core
}
internal static class Extensions
{
public static void AddVector3(this List<byte> bytes, Vector3 vec3)
{
bytes.AddRange(BitConverter.GetBytes(vec3.X));
bytes.AddRange(BitConverter.GetBytes(vec3.Y));
bytes.AddRange(BitConverter.GetBytes(vec3.Z));
}
public static void AddQuaternion(this List<byte> bytes, Quaternion quat)
{
bytes.AddRange(BitConverter.GetBytes(quat.X));
bytes.AddRange(BitConverter.GetBytes(quat.Y));
bytes.AddRange(BitConverter.GetBytes(quat.Z));
bytes.AddRange(BitConverter.GetBytes(quat.W));
}
public static void AddInt(this List<byte> bytes,int i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddUint(this List<byte> bytes, uint i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddShort(this List<byte> bytes, short i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddUshort(this List<byte> bytes, ushort i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddLong(this List<byte> bytes, long i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddUlong(this List<byte> bytes, ulong i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddFloat(this List<byte> bytes, float i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddBool(this List<byte> bytes, bool b)
{
bytes.Add(b? (byte)1 :(byte)0);
}
public static void AddString(this List<byte> bytes, string s)
{
var sb = Encoding.UTF8.GetBytes(s);
bytes.AddInt(sb.Length);
bytes.AddRange(sb);
}
public static void AddArray(this List<byte> bytes, byte[] toadd)
{
bytes.AddInt(toadd.Length);
bytes.AddRange(toadd);
}
public static byte[] GetBytes(this string s)
{
return Encoding.UTF8.GetBytes(s);
}
public static byte[] GetBytesWithLength(this string s)
{
var data = new List<byte>(100);
var sb = Encoding.UTF8.GetBytes(s);
data.AddInt(sb.Length);
data.AddRange(sb);
return data.ToArray();
}
public static string GetString(this byte[] data)
{
return Encoding.UTF8.GetString(data);
@ -296,35 +266,28 @@ namespace RageCoop.Core
// 16 bytes
return new List<byte[]>() { BitConverter.GetBytes(qua.X), BitConverter.GetBytes(qua.Y), BitConverter.GetBytes(qua.Z), BitConverter.GetBytes(qua.W) }.Join(4);
}
public static T GetPacket<T>(this NetIncomingMessage msg, T existingPacket = null) where T : Packet, new()
public static T GetPacket<T>(this NetIncomingMessage msg) where T : Packet, new()
{
msg.ReadByte();
return GetPacket<T>(msg.ReadBytes(msg.ReadInt32()),existingPacket);
}
public static T GetPacket<T>(this byte[] data, T existingPacket=null) where T : Packet, new()
{
var p = existingPacket??new T();
p.Deserialize(data);
var p = new T();
p.Deserialize(msg);
return p;
}
public static bool HasPedFlag(this PedDataFlags flagToCheck, PedDataFlags flag)
{
return (flagToCheck & flag)!=0;
return (flagToCheck & flag) != 0;
}
public static bool HasProjDataFlag(this ProjectileDataFlags flagToCheck, ProjectileDataFlags flag)
{
return (flagToCheck & flag)!=0;
return (flagToCheck & flag) != 0;
}
public static bool HasVehFlag(this VehicleDataFlags flagToCheck, VehicleDataFlags flag)
{
return (flagToCheck & flag)!=0;
return (flagToCheck & flag) != 0;
}
public static bool HasConfigFlag(this PlayerConfigFlags flagToCheck, PlayerConfigFlags flag)
{
return (flagToCheck & flag)!=0;
return (flagToCheck & flag) != 0;
}
public static Type GetActualType(this TypeCode code)
{
@ -391,19 +354,19 @@ namespace RageCoop.Core
public static string DumpWithType(this IEnumerable<object> objects)
{
StringBuilder sb = new StringBuilder();
foreach(var obj in objects)
foreach (var obj in objects)
{
sb.Append(obj.GetType()+":"+obj.ToString()+"\n");
sb.Append(obj.GetType() + ":" + obj.ToString() + "\n");
}
return sb.ToString();
}
public static string Dump<T>(this IEnumerable<T> objects)
{
return "{"+string.Join(",",objects)+"}";
return $"{{{string.Join(",", objects)}}}";
}
public static void ForEach<T>(this IEnumerable<T> objects,Action<T> action)
public static void ForEach<T>(this IEnumerable<T> objects, Action<T> action)
{
foreach(var obj in objects)
foreach (var obj in objects)
{
action(obj);
}
@ -425,10 +388,10 @@ namespace RageCoop.Core
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]; }
var output = lengthPerArray== -1 ? new byte[arrays.Sum(arr => arr.Length)] : new byte[arrays.Count*lengthPerArray];
if (arrays.Count == 1) { return arrays[0]; }
var output = lengthPerArray == -1 ? new byte[arrays.Sum(arr => arr.Length)] : new byte[arrays.Count * lengthPerArray];
int writeIdx = 0;
foreach (var byteArr in arrays)
{
@ -482,5 +445,6 @@ namespace RageCoop.Core
{
return IPAddress.Parse(ip);
}
}
}

View File

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

View File

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

View File

@ -1,7 +1,6 @@
using System;
using Lidgren.Network;
using System;
using System.Collections.Generic;
using System.Text;
using Lidgren.Network;
using System.Threading;
namespace RageCoop.Core
@ -10,22 +9,22 @@ namespace RageCoop.Core
{
public EventHandler<NetIncomingMessage> OnMessageReceived;
private readonly Thread ListenerThread;
private bool _stopping=false;
public CoopPeer(NetPeerConfiguration config):base(config)
private bool _stopping = false;
public CoopPeer(NetPeerConfiguration config) : base(config)
{
Start();
NetIncomingMessage msg;
ListenerThread=new Thread(() =>
{
while (!_stopping)
{
msg=WaitMessage(200);
if (msg!=null)
{
OnMessageReceived?.Invoke(this,msg);
}
}
});
ListenerThread = new Thread(() =>
{
while (!_stopping)
{
msg = WaitMessage(200);
if (msg != null)
{
OnMessageReceived?.Invoke(this, msg);
}
}
});
ListenerThread.Start();
}
@ -34,7 +33,7 @@ namespace RageCoop.Core
/// </summary>
public void Dispose()
{
_stopping=true;
_stopping = true;
Shutdown("Bye!");
ListenerThread.Join();
}
@ -51,12 +50,11 @@ namespace RageCoop.Core
p.Pack(outgoingMessage);
SendMessage(outgoingMessage, connections, method, (int)channel);
}
public void Send(Packet p,IList<NetConnection> cons, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
public void Send(Packet p, IList<NetConnection> cons, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
{
NetOutgoingMessage outgoingMessage = CreateMessage();
p.Pack(outgoingMessage);
SendMessage(outgoingMessage, cons, method, (int)channel);
}
}
}

View File

@ -1,18 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Threading;
using System.IO;
namespace RageCoop.Core
{
internal static class HttpHelper
{
public static void DownloadFile(string url,string destination,Action<int> progressCallback)
public static void DownloadFile(string url, string destination, Action<int> progressCallback)
{
if (File.Exists(destination)) { File.Delete(destination); }
AutoResetEvent ae=new AutoResetEvent(false);
AutoResetEvent ae = new AutoResetEvent(false);
WebClient client = new WebClient();
// TLS only
@ -32,7 +30,9 @@ namespace RageCoop.Core
{
// TLS only
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 |
SecurityProtocolType.Tls11 |
SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
WebClient client = new WebClient();

View File

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

View File

@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
namespace RageCoop.Core
namespace RageCoop.Core
{
internal class ServerInfo
/// <summary>
/// A json object representing a server's information as annouced to master server.
/// </summary>
public class ServerInfo
{
#pragma warning disable 1591
public string address { get; set; }
public string port { get; set; }
public string name { get; set; }
@ -27,8 +25,8 @@ namespace RageCoop.Core
public string ztID { get; set; }
public string ztAddress { get; set; }
public string publicKeyModulus{get;set;}
public string publicKeyExponent{get;set;}
public string publicKeyModulus { get; set; }
public string publicKeyExponent { get; set; }
}
}

View File

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

View File

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

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using Lidgren.Network;
using Lidgren.Network;
using System;
namespace RageCoop.Core
{
@ -10,9 +9,9 @@ namespace RageCoop.Core
internal class ChatMessage : Packet
{
public override PacketType Type => PacketType.ChatMessage;
private Func<string, byte[]> crypt;
private Func<byte[], byte[]> decrypt;
public override PacketType Type => PacketType.ChatMessage;
private readonly Func<string, byte[]> crypt;
private readonly Func<byte[], byte[]> decrypt;
public ChatMessage(Func<string, byte[]> crypter)
{
crypt = crypter;
@ -25,33 +24,31 @@ namespace RageCoop.Core
public string Message { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// Write Username
byteArray.AddString(Username);
m.Write(Username);
// Write Message
byteArray.AddArray(crypt(Message));
return byteArray.ToArray();
m.WriteByteArray(crypt(Message));
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read username
Username = reader.ReadString();
Username = m.ReadString();
Message = decrypt(reader.ReadByteArray()).GetString();
Message = decrypt(m.ReadByteArray()).GetString();
#endregion
}
}

View File

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

View File

@ -1,18 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;

using Lidgren.Network;
namespace RageCoop.Core
{
internal enum FileResponse:byte
internal enum FileResponse : byte
{
NeedToDownload=0,
AlreadyExists=1,
Completed=2,
Loaded=3,
LoadFailed=4,
NeedToDownload = 0,
AlreadyExists = 1,
Completed = 2,
Loaded = 3,
LoadFailed = 4,
}
internal partial class Packets
{
@ -25,34 +22,30 @@ namespace RageCoop.Core
public long FileLength { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// The ID from the download
byteArray.AddInt(ID);
m.Write(ID);
// The name of the file
byte[] nameBytes = Encoding.UTF8.GetBytes(Name);
byteArray.AddRange(BitConverter.GetBytes(nameBytes.Length));
byteArray.AddRange(nameBytes);
m.Write(Name);
// The length of the file
byteArray.AddRange(BitConverter.GetBytes(FileLength));
return byteArray.ToArray();
m.Write(FileLength);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
BitReader reader = new BitReader(array);
ID = reader.ReadInt32();
Name = reader.ReadString();
FileLength = reader.ReadInt64();
ID = m.ReadInt32();
Name = m.ReadString();
FileLength = m.ReadInt64();
}
}
@ -61,86 +54,74 @@ namespace RageCoop.Core
public override PacketType Type => PacketType.FileTransferResponse;
public int ID { get; set; }
public FileResponse Response { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// The ID from the download
byteArray.AddInt(ID);
m.Write(ID);
byteArray.Add((byte)Response);
m.Write((byte)Response);
return byteArray.ToArray();
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
BitReader reader = new BitReader(array);
ID = reader.ReadInt32();
Response = (FileResponse)reader.ReadByte();
ID = m.ReadInt32();
Response = (FileResponse)m.ReadByte();
}
}
internal class FileTransferChunk : Packet
{
public override PacketType Type => PacketType.FileTransferChunk;
public override PacketType Type => PacketType.FileTransferChunk;
public int ID { get; set; }
public byte[] FileChunk { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// The ID from the download
byteArray.AddInt(ID);
// The chunk of the file
byteArray.AddInt(FileChunk.Length);
byteArray.AddRange(FileChunk);
return byteArray.ToArray();
m.Write(ID);
m.WriteByteArray(FileChunk);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
BitReader reader = new BitReader(array);
ID = reader.ReadInt32();
FileChunk = reader.ReadByteArray();
ID = m.ReadInt32();
FileChunk = m.ReadByteArray();
}
}
internal class FileTransferComplete : Packet
{
public override PacketType Type => PacketType.FileTransferComplete;
public override PacketType Type => PacketType.FileTransferComplete;
public int ID { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// The ID for the download
byteArray.AddInt(ID);
return byteArray.ToArray();
m.Write(ID);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
BitReader reader = new BitReader(array);
ID = reader.ReadInt32();
ID = m.ReadInt32();
}
}
internal class AllResourcesSent : Packet
{
public override PacketType Type => PacketType.AllResourcesSent;
public override PacketType Type => PacketType.AllResourcesSent;
}
}
}

View File

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using Lidgren.Network;
using Lidgren.Network;
namespace RageCoop.Core
{
@ -14,26 +12,26 @@ namespace RageCoop.Core
public string TargetInternal { get; set; }
public string TargetExternal { get; set; }
public bool Connect { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
byteArray.AddInt(TargetID);
byteArray.AddString(TargetInternal);
byteArray.AddString(TargetExternal);
byteArray.AddBool(Connect);
return byteArray.ToArray();
m.Write(TargetID);
m.Write(TargetInternal);
m.Write(TargetExternal);
m.Write(Connect);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
TargetID = reader.ReadInt32();
TargetInternal = reader.ReadString();
TargetExternal = reader.ReadString();
Connect=reader.ReadBoolean();
TargetID = m.ReadInt32();
TargetInternal = m.ReadString();
TargetExternal = m.ReadString();
Connect = m.ReadBoolean();
#endregion
}
}
@ -45,23 +43,23 @@ namespace RageCoop.Core
/// <summary>
/// 1:initial, 2:acknowledged, 3:confirmed
/// </summary>
public byte Status { get;set;}
public override byte[] Serialize()
public byte Status { get; set; }
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
byteArray.AddInt(Puncher);
byteArray.Add(Status);
return byteArray.ToArray();
m.Write(Puncher);
m.Write(Status);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
Puncher = reader.ReadInt32();
Status = reader.ReadByte();
Puncher = m.ReadInt32();
Status = m.ReadByte();
#endregion
}
}

View File

@ -1,4 +1,4 @@
using System;
using Lidgren.Network;
using System.Collections.Generic;
namespace RageCoop.Core
@ -12,16 +12,15 @@ namespace RageCoop.Core
{
public int TargetID { get; set; }
public override PacketType Type => PacketType.ConnectionRequest;
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
var data=new List<byte>(10);
data.AddInt(TargetID);
return data.ToArray();
var data = new List<byte>(10);
m.Write(TargetID);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
var reader=new BitReader(array);
TargetID = reader.ReadInt32();
TargetID = m.ReadInt32();
}
}
@ -33,16 +32,16 @@ namespace RageCoop.Core
{
public int ID { get; set; }
public override PacketType Type => PacketType.P2PConnect;
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
var data = new List<byte>(10);
data.AddInt(ID);
return data.ToArray();
m.Write(ID);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
var reader = new BitReader(array);
ID = reader.ReadInt32();
ID = m.ReadInt32();
}
}
}

View File

@ -1,68 +1,56 @@
using System;
using System.Collections.Generic;
using System.Text;
using Lidgren.Network;
using Newtonsoft.Json;
using GTA.Math;
using Lidgren.Network;
using System;
namespace RageCoop.Core
{
internal enum PacketType:byte
internal enum PacketType : byte
{
Handshake=0,
PlayerConnect=1,
PlayerDisconnect=2,
PlayerInfoUpdate=3,
PublicKeyRequest=4,
PublicKeyResponse=5,
Request=6,
Response=7,
Handshake = 0,
PlayerConnect = 1,
PlayerDisconnect = 2,
PlayerInfoUpdate = 3,
PublicKeyRequest = 4,
PublicKeyResponse = 5,
Request = 6,
Response = 7,
PingPong = 8,
HandshakeSuccess = 9,
ChatMessage =10,
ChatMessage = 10,
FileTransferChunk=11,
FileTransferRequest=12,
FileTransferChunk = 11,
FileTransferRequest = 12,
FileTransferResponse = 13,
FileTransferComplete =14,
AllResourcesSent=15,
FileTransferComplete = 14,
AllResourcesSent = 15,
CustomEvent = 16,
CustomEventQueued = 17,
ConnectionRequest=18,
ConnectionRequest = 18,
P2PConnect = 19,
HolePunchInit=20,
HolePunch=21,
HolePunchInit = 20,
HolePunch = 21,
Voice = 22,
#region Sync
PedSync = 23,
VehicleSync = 24,
ProjectileSync =25,
ProjectileSync = 25,
#endregion
#region EVENT
PedKilled=30,
BulletShot=31,
PedKilled = 30,
BulletShot = 31,
VehicleBulletShot = 32,
OwnerChanged =35,
NozzleTransform=37,
OwnerChanged = 35,
NozzleTransform = 37,
#endregion
Unknown=255
Unknown = 255
}
internal static class PacketExtensions
{
internal static bool IsSyncEvent(this PacketType p)
{
return (30<=(byte)p)&&((byte)p<=40);
}
}
internal enum ConnectionChannel
{
Default = 0,
@ -72,18 +60,18 @@ namespace RageCoop.Core
Mod = 4,
File = 5,
Event = 6,
RequestResponse=7,
RequestResponse = 7,
PingPong = 8,
VehicleSync = 9,
PedSync= 10,
PedSync = 10,
ProjectileSync = 11,
SyncEvents = 12,
}
[Flags]
internal enum PedDataFlags:ushort
internal enum PedDataFlags : ushort
{
None=0,
None = 0,
IsAiming = 1 << 0,
IsInStealthMode = 1 << 1,
IsReloading = 1 << 2,
@ -99,10 +87,10 @@ namespace RageCoop.Core
IsInCoverFacingLeft = 1 << 12,
IsBlindFiring = 1 << 13,
IsInvincible = 1 << 14,
IsFullSync = 1<<15 ,
IsFullSync = 1 << 15,
}
internal enum ProjectileDataFlags:byte
internal enum ProjectileDataFlags : byte
{
None = 0,
Exploded = 1 << 0,
@ -111,9 +99,9 @@ namespace RageCoop.Core
IsShotByVehicle = 1 << 3,
}
#region ===== VEHICLE DATA =====
internal enum VehicleDataFlags:ushort
internal enum VehicleDataFlags : ushort
{
None=0,
None = 0,
IsEngineRunning = 1 << 0,
AreLightsOn = 1 << 1,
AreBrakeLightsOn = 1 << 2,
@ -125,18 +113,18 @@ namespace RageCoop.Core
IsParachuteActive = 1 << 8,
IsRocketBoostActive = 1 << 9,
IsAircraft = 1 << 10,
IsDeluxoHovering=1 << 11,
HasRoof=1 << 12,
IsFullSync = 1<<13,
IsOnFire = 1<<14,
Repaired = 1<<15,
IsDeluxoHovering = 1 << 11,
HasRoof = 1 << 12,
IsFullSync = 1 << 13,
IsOnFire = 1 << 14,
Repaired = 1 << 15,
}
internal enum PlayerConfigFlags : byte
{
None = 0,
ShowBlip= 1 << 0,
ShowNameTag= 1 << 1
ShowBlip = 1 << 0,
ShowNameTag = 1 << 1
}
internal struct VehicleDamageModel
@ -153,25 +141,19 @@ namespace RageCoop.Core
internal interface IPacket
{
PacketType Type { get; }
byte[] Serialize();
void Deserialize(byte[] data);
void Deserialize(NetIncomingMessage m);
}
internal abstract class Packet : IPacket
{
public abstract PacketType Type { get; }
public virtual byte[] Serialize()
public void Pack(NetOutgoingMessage m)
{
return new byte[0];
}
public virtual void Deserialize(byte[] array) { }
public void Pack(NetOutgoingMessage message)
{
var d=Serialize();
message.Write((byte)Type);
message.Write(d.Length);
message.Write(d);
m.Write((byte)Type);
Serialize(m);
}
protected virtual void Serialize(NetOutgoingMessage m) { }
public virtual void Deserialize(NetIncomingMessage m) { }
}
}

View File

@ -1,9 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using GTA;
using GTA.Math;
using GTA;
using Lidgren.Network;
using System.Collections.Generic;
namespace RageCoop.Core
{
@ -13,7 +11,7 @@ namespace RageCoop.Core
internal class PedSync : Packet
{
public override PacketType Type => PacketType.PedSync;
public override PacketType Type => PacketType.PedSync;
public int ID { get; set; }
public int OwnerID { get; set; }
@ -59,149 +57,149 @@ namespace RageCoop.Core
public BlipSprite BlipSprite { get; set; } = 0;
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);
byteArray.AddInt(OwnerID);
byteArray.AddRange(BitConverter.GetBytes((ushort)Flags));
byteArray.AddRange(BitConverter.GetBytes(Health));
byteArray.Add(Speed);
m.Write(ID);
m.Write(OwnerID);
m.Write((ushort)Flags);
m.Write(Health);
m.Write(Speed);
if (Flags.HasPedFlag(PedDataFlags.IsRagdoll))
{
byteArray.AddVector3(HeadPosition);
byteArray.AddVector3(RightFootPosition);
byteArray.AddVector3(LeftFootPosition);
m.Write(HeadPosition);
m.Write(RightFootPosition);
m.Write(LeftFootPosition);
}
else
{
if (Speed>=4)
if (Speed >= 4)
{
byteArray.AddInt(VehicleID);
byteArray.Add((byte)(Seat+3));
m.Write(VehicleID);
m.Write((byte)(Seat + 3));
}
byteArray.AddVector3(Position);
m.Write(Position);
}
byteArray.AddVector3(Rotation);
byteArray.AddVector3(Velocity);
m.Write(Rotation);
m.Write(Velocity);
if (Flags.HasPedFlag(PedDataFlags.IsAiming))
{
byteArray.AddVector3(AimCoords);
m.Write(AimCoords);
}
byteArray.AddFloat(Heading);
m.Write(Heading);
if (Flags.HasPedFlag(PedDataFlags.IsFullSync))
{
byteArray.AddInt(ModelHash);
byteArray.AddUint(CurrentWeaponHash);
byteArray.AddRange(Clothes);
m.Write(ModelHash);
m.Write(CurrentWeaponHash);
m.Write(Clothes);
if (WeaponComponents != null)
{
byteArray.Add(0x01);
byteArray.AddRange(BitConverter.GetBytes((ushort)WeaponComponents.Count));
m.Write(true);
m.Write((ushort)WeaponComponents.Count);
foreach (KeyValuePair<uint, bool> component in WeaponComponents)
{
byteArray.AddRange(BitConverter.GetBytes(component.Key));
byteArray.AddRange(BitConverter.GetBytes(component.Value));
m.Write(component.Key);
m.Write(component.Value);
}
}
else
{
// Player weapon doesn't have any components
byteArray.Add(0x00);
m.Write(false);
}
byteArray.Add(WeaponTint);
m.Write(WeaponTint);
byteArray.Add((byte)BlipColor);
if ((byte)BlipColor!=255)
m.Write((byte)BlipColor);
if ((byte)BlipColor != 255)
{
byteArray.AddUshort((ushort)BlipSprite);
byteArray.AddFloat(BlipScale);
m.Write((ushort)BlipSprite);
m.Write(BlipScale);
}
}
return byteArray.ToArray();
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
ID = reader.ReadInt32();
OwnerID=reader.ReadInt32();
Flags = (PedDataFlags)reader.ReadUInt16();
Health = reader.ReadInt32();
Speed = reader.ReadByte();
ID = m.ReadInt32();
OwnerID = m.ReadInt32();
Flags = (PedDataFlags)m.ReadUInt16();
Health = m.ReadInt32();
Speed = m.ReadByte();
if (Flags.HasPedFlag(PedDataFlags.IsRagdoll))
{
HeadPosition=reader.ReadVector3();
RightFootPosition=reader.ReadVector3();
LeftFootPosition=reader.ReadVector3();
Position=HeadPosition;
HeadPosition = m.ReadVector3();
RightFootPosition = m.ReadVector3();
LeftFootPosition = m.ReadVector3();
Position = HeadPosition;
}
else
{
// Vehicle related
if (Speed>=4)
if (Speed >= 4)
{
VehicleID=reader.ReadInt32();
Seat=(VehicleSeat)(reader.ReadByte()-3);
VehicleID = m.ReadInt32();
Seat = (VehicleSeat)(m.ReadByte() - 3);
}
// Read player position
Position = reader.ReadVector3();
Position = m.ReadVector3();
}
Rotation = reader.ReadVector3();
Velocity = reader.ReadVector3();
Rotation = m.ReadVector3();
Velocity = m.ReadVector3();
if (Flags.HasPedFlag(PedDataFlags.IsAiming))
{
// Read player aim coords
AimCoords = reader.ReadVector3();
AimCoords = m.ReadVector3();
}
Heading=reader.ReadSingle();
Heading = m.ReadFloat();
if (Flags.HasPedFlag(PedDataFlags.IsFullSync))
{
// Read player model hash
ModelHash = reader.ReadInt32();
ModelHash = m.ReadInt32();
// Read player weapon hash
CurrentWeaponHash = reader.ReadUInt32();
CurrentWeaponHash = m.ReadUInt32();
// Read player clothes
Clothes =reader.ReadBytes(36);
Clothes = m.ReadBytes(36);
// Read player weapon components
if (reader.ReadBoolean())
if (m.ReadBoolean())
{
WeaponComponents = new Dictionary<uint, bool>();
ushort comCount = reader.ReadUInt16();
ushort comCount = m.ReadUInt16();
for (ushort i = 0; i < comCount; i++)
{
WeaponComponents.Add(reader.ReadUInt32(), reader.ReadBoolean());
WeaponComponents.Add(m.ReadUInt32(), m.ReadBoolean());
}
}
WeaponTint=reader.ReadByte();
WeaponTint = m.ReadByte();
BlipColor=(BlipColor)reader.ReadByte();
BlipColor = (BlipColor)m.ReadByte();
if ((byte)BlipColor!=255)
if ((byte)BlipColor != 255)
{
BlipSprite=(BlipSprite)reader.ReadUInt16();
BlipScale=reader.ReadSingle();
BlipSprite = (BlipSprite)m.ReadUInt16();
BlipScale = m.ReadFloat();
}
}
#endregion

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using GTA.Math;
using GTA.Math;
using Lidgren.Network;
using System.Net;
namespace RageCoop.Core
@ -15,7 +13,7 @@ namespace RageCoop.Core
}
public class Handshake : Packet
{
public override PacketType Type => PacketType.Handshake;
public override PacketType Type => PacketType.Handshake;
public int PedID { get; set; }
public string Username { get; set; }
@ -38,62 +36,55 @@ namespace RageCoop.Core
public byte[] PasswordEncrypted { get; set; }
public IPEndPoint InternalEndPoint { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// Write Player Ped ID
byteArray.AddRange(BitConverter.GetBytes(PedID));
m.Write(PedID);
// Write Username
byte[] usernameBytes = Encoding.UTF8.GetBytes(Username);
byteArray.AddRange(BitConverter.GetBytes(usernameBytes.Length));
byteArray.AddRange(usernameBytes);
m.Write(Username);
// Write ModVersion
byte[] modVersionBytes = Encoding.UTF8.GetBytes(ModVersion);
byteArray.AddRange(BitConverter.GetBytes(modVersionBytes.Length));
byteArray.AddRange(modVersionBytes);
m.Write(ModVersion);
byteArray.AddString(InternalEndPoint.ToString());
m.Write(InternalEndPoint.ToString());
// Write AesKeyCrypted
byteArray.AddArray(AesKeyCrypted);
m.WriteByteArray(AesKeyCrypted);
// Write AesIVCrypted
byteArray.AddArray(AesIVCrypted);
m.WriteByteArray(AesIVCrypted);
// Write PassHash
byteArray.AddArray(PasswordEncrypted);
m.WriteByteArray(PasswordEncrypted);
return byteArray.ToArray();
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read player netHandle
PedID = reader.ReadInt32();
PedID = m.ReadInt32();
// Read Username
Username = reader.ReadString();
Username = m.ReadString();
// Read ModVersion
ModVersion = reader.ReadString();
ModVersion = m.ReadString();
InternalEndPoint=CoreUtils.StringToEndPoint(reader.ReadString());
InternalEndPoint = CoreUtils.StringToEndPoint(m.ReadString());
AesKeyCrypted=reader.ReadByteArray();
AesKeyCrypted = m.ReadByteArray();
AesIVCrypted=reader.ReadByteArray();
AesIVCrypted = m.ReadByteArray();
PasswordEncrypted=reader.ReadByteArray();
PasswordEncrypted = m.ReadByteArray();
#endregion
}
}
@ -101,99 +92,81 @@ namespace RageCoop.Core
{
public PlayerData[] Players { get; set; }
public override PacketType Type => PacketType.HandshakeSuccess;
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
var data = new List<byte>();
data.AddInt(Players.Length);
foreach(var p in Players)
m.Write(Players.Length);
foreach (var p in Players)
{
data.AddInt(p.ID);
data.AddString(p.Username);
m.Write(p.ID);
m.Write(p.Username);
}
return data.ToArray();
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
var reader = new BitReader(array);
Players=new PlayerData[reader.ReadInt32()];
for(int i = 0; i<Players.Length; i++)
Players = new PlayerData[m.ReadInt32()];
for (int i = 0; i < Players.Length; i++)
{
Players[i]=new PlayerData()
Players[i] = new PlayerData()
{
ID=reader.ReadInt32(),
Username=reader.ReadString(),
ID = m.ReadInt32(),
Username = m.ReadString(),
};
}
}
}
public class PlayerConnect : Packet
{
public override PacketType Type => PacketType.PlayerConnect;
public override PacketType Type => PacketType.PlayerConnect;
public int PedID { get; set; }
public string Username { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// Write NetHandle
byteArray.AddRange(BitConverter.GetBytes(PedID));
m.Write(PedID);
// Get Username bytes
byte[] usernameBytes = Encoding.UTF8.GetBytes(Username);
// Write UsernameLength
byteArray.AddRange(BitConverter.GetBytes(usernameBytes.Length));
// Write Username
byteArray.AddRange(usernameBytes);
return byteArray.ToArray();
m.Write(Username);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read player netHandle
PedID = reader.ReadInt32();
PedID = m.ReadInt32();
// Read Username
Username = reader.ReadString();
Username = m.ReadString();
#endregion
}
}
public class PlayerDisconnect : Packet
{
public override PacketType Type => PacketType.PlayerDisconnect;
public override PacketType Type => PacketType.PlayerDisconnect;
public int PedID { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
m.Write(PedID);
byteArray.AddRange(BitConverter.GetBytes(PedID));
return byteArray.ToArray();
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
PedID = reader.ReadInt32();
PedID = m.ReadInt32();
#endregion
}
}
public class PlayerInfoUpdate : Packet
{
public override PacketType Type => PacketType.PlayerInfoUpdate;
public override PacketType Type => PacketType.PlayerInfoUpdate;
/// <summary>
/// Ped ID for this Player
@ -203,70 +176,66 @@ namespace RageCoop.Core
public float Latency { get; set; }
public Vector3 Position { get; set; }
public bool IsHost;
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// Write ID
byteArray.AddRange(BitConverter.GetBytes(PedID));
m.Write(PedID);
// Write Username
byteArray.AddString(Username);
m.Write(Username);
// Write Latency
byteArray.AddFloat(Latency);
m.Write(Latency);
byteArray.AddVector3(Position);
m.Write(Position);
byteArray.AddBool(IsHost);
return byteArray.ToArray();
m.Write(IsHost);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
BitReader reader = new BitReader(array);
// Read player ID
PedID = reader.ReadInt32();
PedID = m.ReadInt32();
// Read Username
Username = reader.ReadString();
Username = m.ReadString();
Latency=reader.ReadSingle();
Latency = m.ReadFloat();
Position=reader.ReadVector3();
Position = m.ReadVector3();
IsHost=reader.ReadBoolean();
IsHost = m.ReadBoolean();
}
}
public class PublicKeyResponse : Packet
{
public override PacketType Type => PacketType.PublicKeyResponse;
public override PacketType Type => PacketType.PublicKeyResponse;
public byte[] Modulus;
public byte[] Exponent;
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
byteArray.AddArray(Modulus);
byteArray.AddArray(Exponent);
return byteArray.ToArray();
m.WriteByteArray(Modulus);
m.WriteByteArray(Exponent);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
var reader=new BitReader(array);
Modulus=reader.ReadByteArray();
Exponent=reader.ReadByteArray();
Modulus = m.ReadByteArray();
Exponent = m.ReadByteArray();
#endregion
}
@ -274,7 +243,7 @@ namespace RageCoop.Core
public class PublicKeyRequest : Packet
{
public override PacketType Type => PacketType.PublicKeyRequest;
public override PacketType Type => PacketType.PublicKeyRequest;
}
}
}

View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using GTA.Math;
using GTA.Math;
using Lidgren.Network;
namespace RageCoop.Core
@ -10,7 +7,7 @@ namespace RageCoop.Core
{
internal class ProjectileSync : Packet
{
public override PacketType Type => PacketType.ProjectileSync;
public override PacketType Type => PacketType.ProjectileSync;
public int ID { get; set; }
public int ShooterID { get; set; }
@ -26,57 +23,57 @@ namespace RageCoop.Core
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// Write id
byteArray.AddInt(ID);
m.Write(ID);
// Write ShooterID
byteArray.AddInt(ShooterID);
m.Write(ShooterID);
byteArray.AddUint(WeaponHash);
m.Write(WeaponHash);
// Write position
byteArray.AddVector3(Position);
m.Write(Position);
// Write rotation
byteArray.AddVector3(Rotation);
m.Write(Rotation);
// Write velocity
byteArray.AddVector3(Velocity);
byteArray.Add((byte)Flags);
m.Write(Velocity);
m.Write((byte)Flags);
return byteArray.ToArray();
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read id
ID = reader.ReadInt32();
ID = m.ReadInt32();
// Read ShooterID
ShooterID= reader.ReadInt32();
ShooterID = m.ReadInt32();
WeaponHash= reader.ReadUInt32();
WeaponHash = m.ReadUInt32();
// Read position
Position = reader.ReadVector3();
Position = m.ReadVector3();
// Read rotation
Rotation = reader.ReadVector3();
Rotation = m.ReadVector3();
// Read velocity
Velocity =reader.ReadVector3();
Velocity = m.ReadVector3();
Flags=(ProjectileDataFlags)reader.ReadByte();
Flags = (ProjectileDataFlags)m.ReadByte();
#endregion
}

View File

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

View File

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

using Lidgren.Network;
namespace RageCoop.Core
@ -10,29 +7,29 @@ namespace RageCoop.Core
{
internal class NozzleTransform : Packet
{
public override PacketType Type => PacketType.NozzleTransform;
public override PacketType Type => PacketType.NozzleTransform;
public int VehicleID { get; set; }
public bool Hover { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
byteArray.AddInt(VehicleID);
byteArray.AddBool(Hover);
return byteArray.ToArray();
m.Write(VehicleID);
m.Write(Hover);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
VehicleID=reader.ReadInt32();
Hover=reader.ReadBoolean();
VehicleID = m.ReadInt32();
Hover = m.ReadBoolean();
#endregion
}

View File

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

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

View File

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

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

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using GTA.Math;
using GTA.Math;
using Lidgren.Network;
namespace RageCoop.Core
{
@ -18,31 +16,31 @@ namespace RageCoop.Core
public Vector3 StartPosition { get; set; }
public Vector3 EndPosition { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
byteArray.AddInt(OwnerID);
byteArray.AddUshort(Bone);
byteArray.AddUint(WeaponHash);
byteArray.AddVector3(StartPosition);
byteArray.AddVector3(EndPosition);
return byteArray.ToArray();
m.Write(OwnerID);
m.Write(Bone);
m.Write(WeaponHash);
m.Write(StartPosition);
m.Write(EndPosition);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
OwnerID=reader.ReadInt32();
Bone=reader.ReadUInt16();
WeaponHash=reader.ReadUInt32();
StartPosition=reader.ReadVector3();
EndPosition=reader.ReadVector3();
OwnerID = m.ReadInt32();
Bone = m.ReadUInt16();
WeaponHash = m.ReadUInt32();
StartPosition = m.ReadVector3();
EndPosition = m.ReadVector3();
#endregion
}
}

View File

@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using GTA;
using GTA;
using GTA.Math;
using Lidgren.Network;
using System.Linq;
using System.Collections.Generic;
namespace RageCoop.Core
{
@ -13,7 +10,7 @@ namespace RageCoop.Core
public class VehicleSync : Packet
{
public override PacketType Type => PacketType.VehicleSync;
public override PacketType Type => PacketType.VehicleSync;
public int ID { get; set; }
public int OwnerID { get; set; }
@ -58,200 +55,170 @@ namespace RageCoop.Core
public string LicensePlate { get; set; }
#endregion
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>(100);
byteArray.AddInt(ID);
byteArray.AddInt(OwnerID);
byteArray.AddUshort((ushort)Flags);
byteArray.AddVector3(Position);
byteArray.AddQuaternion(Quaternion);
byteArray.AddVector3(Velocity);
byteArray.AddVector3(RotationVelocity);
byteArray.AddFloat(ThrottlePower);
byteArray.AddFloat(BrakePower);
byteArray.AddFloat(SteeringAngle);
m.Write(ID);
m.Write(OwnerID);
m.Write((ushort)Flags);
m.Write(Position);
m.Write(Quaternion);
m.Write(Velocity);
m.Write(RotationVelocity);
m.Write(ThrottlePower);
m.Write(BrakePower);
m.Write(SteeringAngle);
if (Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering))
{
byteArray.AddFloat(DeluxoWingRatio);
m.Write(DeluxoWingRatio);
}
if (Flags.HasVehFlag(VehicleDataFlags.IsFullSync))
{
byteArray.AddInt(ModelHash);
byteArray.AddFloat(EngineHealth);
m.Write(ModelHash);
m.Write(EngineHealth);
// Check
if (Flags.HasVehFlag(VehicleDataFlags.IsAircraft))
{
// Write the vehicle landing gear
byteArray.Add(LandingGear);
m.Write(LandingGear);
}
if (Flags.HasVehFlag(VehicleDataFlags.HasRoof))
{
byteArray.Add(RoofState);
m.Write(RoofState);
}
// Write vehicle colors
byteArray.Add(Colors[0]);
byteArray.Add(Colors[1]);
m.Write(Colors[0]);
m.Write(Colors[1]);
// Write vehicle mods
// Write the count of mods
byteArray.AddRange(BitConverter.GetBytes((short)Mods.Count));
m.Write((short)Mods.Count);
// Loop the dictionary and add the values
foreach (KeyValuePair<int, int> mod in Mods)
{
// Write the mod value
byteArray.AddRange(BitConverter.GetBytes(mod.Key));
byteArray.AddRange(BitConverter.GetBytes(mod.Value));
m.Write(mod.Key);
m.Write(mod.Value);
}
if (!DamageModel.Equals(default(VehicleDamageModel)))
{
// Write boolean = true
byteArray.Add(0x01);
m.Write(true);
// Write vehicle damage model
byteArray.Add(DamageModel.BrokenDoors);
byteArray.Add(DamageModel.OpenedDoors);
byteArray.Add(DamageModel.BrokenWindows);
byteArray.AddRange(BitConverter.GetBytes(DamageModel.BurstedTires));
byteArray.Add(DamageModel.LeftHeadLightBroken);
byteArray.Add(DamageModel.RightHeadLightBroken);
m.Write(DamageModel.BrokenDoors);
m.Write(DamageModel.OpenedDoors);
m.Write(DamageModel.BrokenWindows);
m.Write(DamageModel.BurstedTires);
m.Write(DamageModel.LeftHeadLightBroken);
m.Write(DamageModel.RightHeadLightBroken);
}
else
{
// Write boolean = false
byteArray.Add(0x00);
m.Write(false);
}
// Write LockStatus
byteArray.Add((byte)LockStatus);
m.Write((byte)LockStatus);
// Write RadioStation
byteArray.Add(RadioStation);
m.Write(RadioStation);
// Write LicensePlate
while (LicensePlate.Length<8)
{
LicensePlate+=" ";
}
if (LicensePlate.Length>8)
{
LicensePlate=new string(LicensePlate.Take(8).ToArray());
}
byteArray.AddRange(Encoding.ASCII.GetBytes(LicensePlate));
m.Write(LicensePlate);
byteArray.Add((byte)(Livery+1));
m.Write((byte)(Livery + 1));
}
return byteArray.ToArray();
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read vehicle id
ID = reader.ReadInt32();
OwnerID = reader.ReadInt32();
Flags=(VehicleDataFlags)reader.ReadUInt16();
// Read position
Position = reader.ReadVector3();
// Read quaternion
Quaternion=reader.ReadQuaternion();
// Read velocity
Velocity =reader.ReadVector3();
// Read rotation velocity
RotationVelocity=reader.ReadVector3();
// Read throttle power
ThrottlePower=reader.ReadSingle();
// Read brake power
BrakePower=reader.ReadSingle();
// Read steering angle
SteeringAngle = reader.ReadSingle();
ID = m.ReadInt32();
OwnerID = m.ReadInt32();
Flags = (VehicleDataFlags)m.ReadUInt16();
Position = m.ReadVector3();
Quaternion = m.ReadQuaternion();
Velocity = m.ReadVector3();
RotationVelocity = m.ReadVector3();
ThrottlePower = m.ReadFloat();
BrakePower = m.ReadFloat();
SteeringAngle = m.ReadFloat();
if (Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering))
{
DeluxoWingRatio = reader.ReadSingle();
DeluxoWingRatio = m.ReadFloat();
}
if (Flags.HasVehFlag(VehicleDataFlags.IsFullSync))
{
// Read vehicle model hash
ModelHash = reader.ReadInt32();
ModelHash = m.ReadInt32();
// Read vehicle engine health
EngineHealth = reader.ReadSingle();
EngineHealth = m.ReadFloat();
// Check
if (Flags.HasVehFlag(VehicleDataFlags.IsAircraft))
{
// Read vehicle landing gear
LandingGear = reader.ReadByte();
LandingGear = m.ReadByte();
}
if (Flags.HasVehFlag(VehicleDataFlags.HasRoof))
{
RoofState=reader.ReadByte();
RoofState = m.ReadByte();
}
// Read vehicle colors
byte vehColor1 = reader.ReadByte();
byte vehColor2 = reader.ReadByte();
byte vehColor1 = m.ReadByte();
byte vehColor2 = m.ReadByte();
Colors = new byte[] { vehColor1, vehColor2 };
// Read vehicle mods
// Create new Dictionary
Mods = new Dictionary<int, int>();
// Read count of mods
short vehModCount = reader.ReadInt16();
short vehModCount = m.ReadInt16();
// Loop
for (int i = 0; i < vehModCount; i++)
{
// Read the mod value
Mods.Add(reader.ReadInt32(), reader.ReadInt32());
Mods.Add(m.ReadInt32(), m.ReadInt32());
}
if (reader.ReadBoolean())
if (m.ReadBoolean())
{
// Read vehicle damage model
DamageModel = new VehicleDamageModel()
{
BrokenDoors = reader.ReadByte(),
OpenedDoors=reader.ReadByte(),
BrokenWindows = reader.ReadByte(),
BurstedTires = reader.ReadInt16(),
LeftHeadLightBroken = reader.ReadByte(),
RightHeadLightBroken = reader.ReadByte()
BrokenDoors = m.ReadByte(),
OpenedDoors = m.ReadByte(),
BrokenWindows = m.ReadByte(),
BurstedTires = m.ReadInt16(),
LeftHeadLightBroken = m.ReadByte(),
RightHeadLightBroken = m.ReadByte()
};
}
// Read LockStatus
LockStatus=(VehicleLockStatus)reader.ReadByte();
LockStatus = (VehicleLockStatus)m.ReadByte();
// Read RadioStation
RadioStation=reader.ReadByte();
RadioStation = m.ReadByte();
LicensePlate=Encoding.ASCII.GetString(reader.ReadBytes(8));
LicensePlate = m.ReadString();
Livery=(int)(reader.ReadByte()-1);
Livery = m.ReadByte() - 1;
}
#endregion
}

View File

@ -1,4 +1,4 @@
using System.Collections.Generic;
using Lidgren.Network;
namespace RageCoop.Core
{
@ -10,20 +10,19 @@ namespace RageCoop.Core
public byte[] Buffer { get; set; }
public int Recorded { get; set; }
public override PacketType Type => PacketType.Voice;
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
var data = new List<byte>();
data.AddInt(ID);
data.AddArray(Buffer);
data.AddInt(Recorded);
return data.ToArray();
m.Write(ID);
m.Write(Buffer);
m.Write(Recorded);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
var reader = new BitReader(array);
ID = reader.ReadInt32();
Buffer = reader.ReadByteArray();
Recorded = reader.ReadInt32();
ID = m.ReadInt32();
Buffer = m.ReadByteArray();
Recorded = m.ReadInt32();
}
}
}

View File

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.Text;
namespace RageCoop.Core.Scripting
{
@ -10,8 +10,8 @@ namespace RageCoop.Core.Scripting
/// </summary>
public static class CustomEvents
{
static MD5 Hasher = MD5.Create();
static Dictionary<int,string> Hashed=new Dictionary<int,string>();
private static readonly MD5 Hasher = MD5.Create();
private static readonly Dictionary<int, string> Hashed = new Dictionary<int, string>();
internal static readonly int OnPlayerDied = Hash("RageCoop.OnPlayerDied");
internal static readonly int SetWeather = Hash("RageCoop.SetWeather");
internal static readonly int OnPedDeleted = Hash("RageCoop.OnPedDeleted");
@ -40,25 +40,20 @@ namespace RageCoop.Core.Scripting
public static int Hash(string s)
{
var hash = BitConverter.ToInt32(Hasher.ComputeHash(Encoding.UTF8.GetBytes(s)), 0);
string name;
lock (Hashed)
{
if (Hashed.TryGetValue(hash, out name))
if (Hashed.TryGetValue(hash, out string name))
{
if (name!=s)
if (name != s)
{
throw new ArgumentException($"Hashed value has collision with another name:{name}, hashed value:{hash}");
}
else
{
return hash;
}
}
else
{
Hashed.Add(hash, s);
return hash;
}
Hashed.Add(hash, s);
return hash;
}
}
}

View File

@ -1,25 +1,24 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace RageCoop.Core.Scripting
{
/// <summary>
///
/// </summary>
public class ResourceFile
/// <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; }
/// <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; }
}
}

View File

@ -1,17 +1,17 @@
using System;
using System.Threading;
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
public class Worker : IDisposable
{
private SemaphoreSlim _semaphoreSlim;
private Thread _workerThread;
private bool _stopping=false;
private readonly SemaphoreSlim _semaphoreSlim;
private readonly Thread _workerThread;
private bool _stopping = false;
/// <summary>
/// Name of the worker
/// </summary>
@ -19,37 +19,37 @@ namespace RageCoop.Core
/// <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)
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;
});
_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>
@ -66,7 +66,7 @@ namespace RageCoop.Core
/// </summary>
public void Stop()
{
_stopping=true;
_stopping = true;
QueueJob(() => { });
if (_workerThread.IsAlive)
{
@ -81,6 +81,6 @@ namespace RageCoop.Core
Stop();
_semaphoreSlim.Dispose();
}
private ConcurrentQueue<Action> Jobs=new ConcurrentQueue<Action>();
private readonly ConcurrentQueue<Action> Jobs = new ConcurrentQueue<Action>();
}
}

View File

@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
using Lidgren.Network;
using RageCoop.Core;
using Lidgren.Network;
using System.Diagnostics;
using RageCoop.Core.Scripting;
using System.Security.Cryptography;
using RageCoop.Server.Scripting;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Security.Cryptography;
namespace RageCoop.Server
{
@ -18,7 +18,7 @@ namespace RageCoop.Server
private readonly Server Server;
internal Client(Server server)
{
Server=server;
Server = server;
}
/// <summary>
@ -28,7 +28,7 @@ namespace RageCoop.Server
/// <summary>
/// Th client's IP address and port.
/// </summary>
public IPEndPoint EndPoint { get { return Connection?.RemoteEndPoint; } }
public IPEndPoint EndPoint => Connection?.RemoteEndPoint;
/// <summary>
/// Internal(LAN) address of this client, used for NAT hole-punching
@ -36,7 +36,7 @@ namespace RageCoop.Server
public IPEndPoint InternalEndPoint { get; internal set; }
internal long NetHandle = 0;
internal NetConnection Connection { get;set; }
internal NetConnection Connection { get; set; }
/// <summary>
/// The <see cref="ServerPed"/> instance representing the client's main character.
/// </summary>
@ -44,45 +44,47 @@ namespace RageCoop.Server
/// <summary>
/// The client's latency in seconds.
/// </summary>
public float Latency => Connection.AverageRoundtripTime/2;
public float Latency => Connection.AverageRoundtripTime / 2;
internal readonly Dictionary<int, Action<object>> Callbacks = new();
internal byte[] PublicKey { get; set; }
/// <summary>
/// Indicates whether the client has succefully loaded all resources.
/// </summary>
public bool IsReady { get; internal set; }=false;
public bool IsReady { get; internal set; } = false;
/// <summary>
/// The client's username.
/// </summary>
public string Username { get;internal set; } = "N/A";
public string Username { get; internal set; } = "N/A";
private bool _autoRespawn=true;
private bool _autoRespawn = true;
/// <summary>
/// Gets or sets whether to enable automatic respawn for this client's main ped.
/// </summary>
public bool EnableAutoRespawn {
get { return _autoRespawn; }
set {
BaseScript.SetAutoRespawn(this,value);
_autoRespawn=value;
public bool EnableAutoRespawn
{
get => _autoRespawn;
set
{
BaseScript.SetAutoRespawn(this, value);
_autoRespawn = value;
}
}
private bool _displayNameTag=true;
private Stopwatch _latencyWatch = new Stopwatch();
private bool _displayNameTag = true;
private readonly Stopwatch _latencyWatch = new Stopwatch();
/// <summary>
/// Gets or sets whether to enable automatic respawn for this client's main ped.
/// </summary>
public bool DisplayNameTag
{
get { return _displayNameTag; }
get => _displayNameTag;
set
{
Server.BaseScript.SetNameTag(this,value);
_displayNameTag=value;
Server.BaseScript.SetNameTag(this, value);
_displayNameTag = value;
}
}
#region FUNCTIONS
@ -90,7 +92,7 @@ namespace RageCoop.Server
/// Kick this client
/// </summary>
/// <param name="reason"></param>
public void Kick(string reason="You have been kicked!")
public void Kick(string reason = "You have been kicked!")
{
Connection?.Disconnect(reason);
}
@ -129,7 +131,7 @@ namespace RageCoop.Server
/// <param name="args"></param>
public void SendNativeCall<T>(Action<object> callBack, GTA.Native.Hash hash, params object[] args)
{
var argsList= new List<object>(args);
var argsList = new List<object>(args);
argsList.InsertRange(0, new object[] { (byte)Type.GetTypeCode(typeof(T)), RequestNativeCallID<T>(callBack), (ulong)hash });
SendCustomEventQueued(CustomEvents.NativeCall, argsList.ToArray());
@ -142,7 +144,7 @@ namespace RageCoop.Server
public void SendNativeCall(GTA.Native.Hash hash, params object[] args)
{
var argsList = new List<object>(args);
argsList.InsertRange(0, new object[] { (byte)TypeCode.Empty,(ulong)hash });
argsList.InsertRange(0, new object[] { (byte)TypeCode.Empty, (ulong)hash });
// Server.Logger?.Debug(argsList.DumpWithType());
SendCustomEventQueued(CustomEvents.NativeCall, argsList.ToArray());
}
@ -151,7 +153,7 @@ namespace RageCoop.Server
int ID = 0;
lock (Callbacks)
{
while ((ID==0)
while ((ID == 0)
|| Callbacks.ContainsKey(ID))
{
byte[] rngBytes = new byte[4];
@ -170,7 +172,7 @@ namespace RageCoop.Server
/// </summary>
/// <param name="hash">An unique identifier of the event, you can use <see cref="CustomEvents.Hash(string)"/> to get it from a string</param>
/// <param name="args">Arguments</param>
public void SendCustomEvent(int hash,params object[] args)
public void SendCustomEvent(int hash, params object[] args)
{
if (!IsReady)
{
@ -183,8 +185,8 @@ namespace RageCoop.Server
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
new Packets.CustomEvent()
{
Hash=hash,
Args=args
Hash = hash,
Args = args
}.Pack(outgoingMessage);
Server.MainNetServer.SendMessage(outgoingMessage, Connection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Event);
@ -211,10 +213,10 @@ namespace RageCoop.Server
{
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
new Packets.CustomEvent(null,true)
new Packets.CustomEvent(null, true)
{
Hash=hash,
Args=args
Hash = hash,
Args = args
}.Pack(outgoingMessage);
Server.MainNetServer.SendMessage(outgoingMessage, Connection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Event);

View File

@ -1,16 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RageCoop.Server
namespace RageCoop.Server
{
internal class FileTransfer
{
public int ID { get; set; }
public float Progress { get; set; }
public string Name { get; set; }
public bool Cancel { get; set; }=false;
public bool Cancel { get; set; } = false;
}
}

View File

@ -1,12 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using RageCoop.Core;
namespace RageCoop.Server
namespace RageCoop.Server
{
internal class HolePunch
{

View File

@ -1,25 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.SharpZipLib.Zip;
using Lidgren.Network;
using Newtonsoft.Json;
using RageCoop.Core;
using RageCoop.Server.Scripting;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using Newtonsoft.Json;
using RageCoop.Core.Scripting;
using RageCoop.Server.Scripting;
using System.Threading;
using System.Runtime.InteropServices;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using System.Diagnostics;
using System.Text;
using System.Threading;
namespace RageCoop.Server
{
public partial class Server
{
const string _versionURL = "https://raw.githubusercontent.com/RAGECOOP/RAGECOOP-V/main/RageCoop.Server/Properties/AssemblyInfo.cs";
private const string _versionURL = "https://raw.githubusercontent.com/RAGECOOP/RAGECOOP-V/main/RageCoop.Server/Properties/AssemblyInfo.cs";
private void SendPlayerUpdate()
{
foreach (var c in ClientsByNetHandle.Values.ToArray())
@ -44,6 +42,7 @@ namespace RageCoop.Server
}
}
private IpInfo IpInfo = null;
private bool CanAnnounce = false;
private void Announce()
{
HttpResponseMessage response = null;
@ -54,7 +53,10 @@ namespace RageCoop.Server
{
// TLS only
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 |
SecurityProtocolType.Tls12 |
SecurityProtocolType.Tls11 |
SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
try
@ -77,6 +79,19 @@ namespace RageCoop.Server
Logger?.Error($"MasterServer: {ex.Message}");
}
}
if (!CanAnnounce)
{
var existing = JsonConvert.DeserializeObject<List<ServerInfo>>(HttpHelper.DownloadString(Util.GetFinalRedirect(Settings.MasterServer))).Where(x => x.address == IpInfo.Address && x.port == Settings.Port.ToString()).FirstOrDefault();
if(existing != null)
{
Logger.Warning("Server info already present in master server, waiting for 10 seconds...");
return;
}
else
{
CanAnnounce = true;
}
}
try
{
Security.GetPublicKey(out var pModulus, out var pExpoenet);
@ -144,7 +159,7 @@ namespace RageCoop.Server
Thread.Sleep(10 * 60 * 1000);
API.SendChatMessage("downloading update...");
var downloadURL = $"https://github.com/RAGECOOP/RAGECOOP-V/releases/download/nightly/RageCoop.Server-{GetRID()}.zip";
var downloadURL = $"https://github.com/RAGECOOP/RAGECOOP-V/releases/download/nightly/RageCoop.Server-{CoreUtils.GetInvariantRID()}.zip";
if (Directory.Exists("Update")) { Directory.Delete("Update", true); }
HttpHelper.DownloadFile(downloadURL, "Update.zip", null);
Logger?.Info("Installing update");
@ -153,31 +168,20 @@ namespace RageCoop.Server
MainNetServer.Shutdown("Server updating");
Logger.Info("Server shutting down!");
Logger.Flush();
Process.Start(Path.Combine("Update", RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "RageCoop.Server.exe": "RageCoop.Server"), "update \"" + AppDomain.CurrentDomain.BaseDirectory[0..^1] + "\"");
Process.Start(Path.Combine("Update", RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "RageCoop.Server.exe" : "RageCoop.Server"), "update \"" + AppDomain.CurrentDomain.BaseDirectory[0..^1] + "\"");
Environment.Exit(0);
}
catch(Exception ex)
catch (Exception ex)
{
Logger?.Error("Update",ex);
Logger?.Error("Update", ex);
}
}
static string GetRID()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return "win-"+RuntimeInformation.OSArchitecture.ToString().ToLower();
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return "linux-"+RuntimeInformation.OSArchitecture.ToString().ToLower();
}
return "unknown";
}
private void KickAssholes()
{
foreach(var c in ClientsByNetHandle.Values.ToArray())
foreach (var c in ClientsByNetHandle.Values.ToArray())
{
if (c.EntitiesCount > 100 && Settings.KickSpamming)
if (c.EntitiesCount > Settings.SpamLimit && Settings.KickSpamming)
{
c.Kick("Bye bye asshole: spamming");
API.SendChatMessage($"Asshole {c.Username} was kicked: Spamming");

View File

@ -1,12 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Lidgren.Network;
using Lidgren.Network;
using RageCoop.Core;
using RageCoop.Core.Scripting;
using RageCoop.Server.Scripting;
using System;
using System.Linq;
using System.Text;
namespace RageCoop.Server
{
@ -43,16 +41,17 @@ namespace RageCoop.Server
connection.Deny("Username is already taken!");
return;
}
try
{
Security.AddConnection(connection.RemoteEndPoint, packet.AesKeyCrypted, packet.AesIVCrypted);
var args = new HandshakeEventArgs()
{
EndPoint=connection.RemoteEndPoint,
ID=packet.PedID,
Username=packet.Username,
PasswordHash=Security.Decrypt(packet.PasswordEncrypted, connection.RemoteEndPoint).GetString().GetSHA256Hash().ToHexString(),
EndPoint = connection.RemoteEndPoint,
ID = packet.PedID,
Username = packet.Username,
PasswordHash = Security.Decrypt(packet.PasswordEncrypted, connection.RemoteEndPoint).GetString().GetSHA256Hash().ToHexString(),
};
API.Events.InvokePlayerHandshake(args);
if (args.Cancel)
@ -68,20 +67,22 @@ namespace RageCoop.Server
connection.Deny("Malformed handshak packet!");
return;
}
var handshakeSuccess = MainNetServer.CreateMessage();
var currentClients = ClientsByID.Values.ToArray();
var players = new Packets.PlayerData[currentClients.Length];
for (int i = 0; i<players.Length; i++)
for (int i = 0; i < players.Length; i++)
{
players[i]=new Packets.PlayerData()
players[i] = new Packets.PlayerData()
{
ID=currentClients[i].Player.ID,
Username=currentClients[i].Username,
ID = currentClients[i].Player.ID,
Username = currentClients[i].Username,
};
}
new Packets.HandshakeSuccess()
{
Players=players
Players = players
}.Pack(handshakeSuccess);
connection.Approve(handshakeSuccess);
Client tmpClient;
@ -91,25 +92,25 @@ namespace RageCoop.Server
{
var player = new ServerPed(this)
{
ID= packet.PedID,
ID = packet.PedID,
};
Entities.Add(player);
ClientsByNetHandle.Add(connection.RemoteUniqueIdentifier,
tmpClient = new Client(this)
{
NetHandle = connection.RemoteUniqueIdentifier,
Connection=connection,
Username=packet.Username,
Connection = connection,
Username = packet.Username,
Player = player,
InternalEndPoint=packet.InternalEndPoint,
InternalEndPoint = packet.InternalEndPoint,
}
);
player.Owner=tmpClient;
player.Owner = tmpClient;
ClientsByName.Add(packet.Username.ToLower(), tmpClient);
ClientsByID.Add(player.ID, tmpClient);
if (ClientsByNetHandle.Count==1)
if (ClientsByNetHandle.Count == 1)
{
_hostClient=tmpClient;
_hostClient = tmpClient;
}
}
@ -120,19 +121,19 @@ namespace RageCoop.Server
// The connection has been approved, now we need to send all other players to the new player and the new player to all players
private void PlayerConnected(Client newClient)
{
if (newClient==_hostClient)
if (newClient == _hostClient)
{
API.SendCustomEvent(new() { newClient }, CustomEvents.IsHost, true);
}
// Send new client to all players
var cons = MainNetServer.Connections.Exclude(newClient.Connection);
if (cons.Count!=0)
if (cons.Count != 0)
{
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
new Packets.PlayerConnect()
{
PedID=newClient.Player.ID,
PedID = newClient.Player.ID,
Username = newClient.Username
}.Pack(outgoingMessage);
@ -146,15 +147,13 @@ namespace RageCoop.Server
// Send all blips to this player
BaseScript.SendServerBlipsTo(new(Entities.Blips.Values), new() { newClient });
// Create P2P connection
if (Settings.UseP2P)
{
ClientsByNetHandle.Values.ForEach(target =>
{
if (target==newClient) { return; }
HolePunch(target,newClient);
if (target == newClient) { return; }
HolePunch(target, newClient);
});
}
@ -170,23 +169,23 @@ namespace RageCoop.Server
private void PlayerDisconnected(Client localClient)
{
var cons = MainNetServer.Connections.Exclude(localClient.Connection);
if (cons.Count!=0)
if (cons.Count != 0)
{
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
new Packets.PlayerDisconnect()
{
PedID=localClient.Player.ID,
PedID = localClient.Player.ID,
}.Pack(outgoingMessage);
MainNetServer.SendMessage(outgoingMessage, cons, NetDeliveryMethod.ReliableOrdered, 0);
}
Entities.CleanUp(localClient);
_worker.QueueJob(() => API.Events.InvokePlayerDisconnected(localClient));
QueueJob(() => API.Events.InvokePlayerDisconnected(localClient));
Logger?.Info($"Player {localClient.Username} disconnected! ID:{localClient.Player.ID}");
if (ClientsByNetHandle.ContainsKey(localClient.NetHandle)) { ClientsByNetHandle.Remove(localClient.NetHandle); }
if (ClientsByName.ContainsKey(localClient.Username.ToLower())) { ClientsByName.Remove(localClient.Username.ToLower()); }
if (ClientsByID.ContainsKey(localClient.Player.ID)) { ClientsByID.Remove(localClient.Player.ID); }
if (localClient==_hostClient)
if (localClient == _hostClient)
{
_hostClient = ClientsByNetHandle.Values.FirstOrDefault();

View File

@ -1,11 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Lidgren.Network;
using Lidgren.Network;
using RageCoop.Core;
using RageCoop.Core.Scripting;
using RageCoop.Server.Scripting;
namespace RageCoop.Server
@ -14,12 +8,12 @@ namespace RageCoop.Server
{
private void PedSync(Packets.PedSync packet, Client client)
{
_worker.QueueJob(() => Entities.Update(packet, client));
QueueJob(() => Entities.Update(packet, client));
bool isPlayer = packet.ID==client.Player.ID;
bool isPlayer = packet.ID == client.Player.ID;
if (isPlayer)
{
_worker.QueueJob(() => API.Events.InvokePlayerUpdate(client));
QueueJob(() => API.Events.InvokePlayerUpdate(client));
}
if (Settings.UseP2P) { return; }
@ -27,17 +21,17 @@ namespace RageCoop.Server
{
// Don't send data back
if (c.NetHandle==client.NetHandle) { continue; }
if (c.NetHandle == client.NetHandle) { continue; }
// Check streaming distance
if (isPlayer)
{
if ((Settings.PlayerStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.PlayerStreamingDistance))
if ((Settings.PlayerStreamingDistance != -1) && (packet.Position.DistanceTo(c.Player.Position) > Settings.PlayerStreamingDistance))
{
continue;
}
}
else if ((Settings.NpcStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.NpcStreamingDistance))
else if ((Settings.NpcStreamingDistance != -1) && (packet.Position.DistanceTo(c.Player.Position) > Settings.NpcStreamingDistance))
{
continue;
}
@ -49,35 +43,33 @@ namespace RageCoop.Server
}
private void VehicleSync(Packets.VehicleSync packet, Client client)
{
_worker.QueueJob(() => Entities.Update(packet, client));
bool isPlayer = packet.ID==client.Player?.LastVehicle?.ID;
QueueJob(() => Entities.Update(packet, client));
bool isPlayer = packet.ID == client.Player?.LastVehicle?.ID;
if (Settings.UseP2P) { return; }
foreach (var c in ClientsByNetHandle.Values)
{
if (c.NetHandle==client.NetHandle) { continue; }
if (c.NetHandle == client.NetHandle) { continue; }
if (isPlayer)
{
// Player's vehicle
if ((Settings.PlayerStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.PlayerStreamingDistance))
if ((Settings.PlayerStreamingDistance != -1) && (packet.Position.DistanceTo(c.Player.Position) > Settings.PlayerStreamingDistance))
{
continue;
}
}
else if ((Settings.NpcStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>Settings.NpcStreamingDistance))
else if ((Settings.NpcStreamingDistance != -1) && (packet.Position.DistanceTo(c.Player.Position) > Settings.NpcStreamingDistance))
{
continue;
}
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
packet.Pack(outgoingMessage);
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.VehicleSync);
}
}
private void ProjectileSync(Packets.ProjectileSync packet, Client client)
{
if (Settings.UseP2P) { return; }
Forward(packet, client, ConnectionChannel.ProjectileSync);
}

View File

@ -1,12 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Lidgren.Network;
using Lidgren.Network;
using RageCoop.Core;
using RageCoop.Core.Scripting;
using RageCoop.Server.Scripting;
namespace RageCoop.Server
{
@ -17,19 +10,19 @@ namespace RageCoop.Server
// Send to host
Send(new Packets.HolePunchInit
{
Connect=false,
TargetID=client.Player.ID,
TargetInternal=client.InternalEndPoint.ToString(),
TargetExternal=client.EndPoint.ToString()
Connect = false,
TargetID = client.Player.ID,
TargetInternal = client.InternalEndPoint.ToString(),
TargetExternal = client.EndPoint.ToString()
}, host, ConnectionChannel.Default, NetDeliveryMethod.ReliableOrdered);
// Send to client
Send(new Packets.HolePunchInit
{
Connect=true,
TargetID=host.Player.ID,
TargetInternal=host.InternalEndPoint.ToString(),
TargetExternal=host.EndPoint.ToString()
Connect = true,
TargetID = host.Player.ID,
TargetInternal = host.InternalEndPoint.ToString(),
TargetExternal = host.EndPoint.ToString()
}, client, ConnectionChannel.Default, NetDeliveryMethod.ReliableOrdered);
}
}

View File

@ -1,12 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Lidgren.Network;
using Lidgren.Network;
using RageCoop.Core;
using RageCoop.Core.Scripting;
using RageCoop.Server.Scripting;
using System;
namespace RageCoop.Server
{
@ -56,9 +51,7 @@ namespace RageCoop.Server
{
try
{
int len = message.ReadInt32();
byte[] data = message.ReadBytes(len);
GetHandshake(message.SenderConnection, data.GetPacket<Packets.Handshake>());
GetHandshake(message.SenderConnection, message.GetPacket<Packets.Handshake>());
}
catch (Exception e)
{
@ -86,7 +79,7 @@ namespace RageCoop.Server
else if (status == NetConnectionStatus.Connected)
{
PlayerConnected(sender);
_worker.QueueJob(() => API.Events.InvokePlayerConnected(sender));
QueueJob(() => API.Events.InvokePlayerConnected(sender));
Resources.SendTo(sender);
}
break;
@ -106,7 +99,7 @@ namespace RageCoop.Server
int id = message.ReadInt32();
if (PendingResponses.TryGetValue(id, out var callback))
{
callback((PacketType)message.ReadByte(), message.ReadBytes(message.ReadInt32()));
callback((PacketType)message.ReadByte(), message);
PendingResponses.Remove(id);
}
break;
@ -114,19 +107,23 @@ namespace RageCoop.Server
case PacketType.Request:
{
int id = message.ReadInt32();
if (RequestHandlers.TryGetValue((PacketType)message.ReadByte(), out var handler))
var reqType = (PacketType)message.ReadByte();
if (RequestHandlers.TryGetValue(reqType, out var handler))
{
var response = MainNetServer.CreateMessage();
response.Write((byte)PacketType.Response);
response.Write(id);
handler(message.ReadBytes(message.ReadInt32()), sender).Pack(response);
handler(message, sender).Pack(response);
MainNetServer.SendMessage(response, message.SenderConnection, NetDeliveryMethod.ReliableOrdered);
}
else
{
Logger.Warning("Did not find a request handler of type: " + reqType);
}
break;
}
default:
{
byte[] data = message.ReadBytes(message.ReadInt32());
if (type.IsSyncEvent())
{
// Sync Events
@ -139,8 +136,7 @@ namespace RageCoop.Server
{
var outgoingMessage = MainNetServer.CreateMessage();
outgoingMessage.Write((byte)type);
outgoingMessage.Write(data.Length);
outgoingMessage.Write(data);
outgoingMessage.Write(message.ReadBytes(message.LengthBytes - 1));
MainNetServer.SendMessage(outgoingMessage, toSend, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.SyncEvents);
}
}
@ -151,7 +147,7 @@ namespace RageCoop.Server
}
else
{
HandlePacket(type, data, sender);
HandlePacket(type, message, sender);
}
break;
}
@ -191,22 +187,22 @@ namespace RageCoop.Server
MainNetServer.Recycle(message);
}
private void HandlePacket(PacketType type, byte[] data, Client sender)
private void HandlePacket(PacketType type, NetIncomingMessage msg, Client sender)
{
try
{
switch (type)
{
case PacketType.PedSync:
PedSync(data.GetPacket<Packets.PedSync>(), sender);
PedSync(msg.GetPacket<Packets.PedSync>(), sender);
break;
case PacketType.VehicleSync:
VehicleSync(data.GetPacket<Packets.VehicleSync>(), sender);
VehicleSync(msg.GetPacket<Packets.VehicleSync>(), sender);
break;
case PacketType.ProjectileSync:
ProjectileSync(data.GetPacket<Packets.ProjectileSync>(), sender);
ProjectileSync(msg.GetPacket<Packets.ProjectileSync>(), sender);
break;
case PacketType.ChatMessage:
@ -215,7 +211,7 @@ namespace RageCoop.Server
{
return Security.Decrypt(b, sender.EndPoint);
});
packet.Deserialize(data);
packet.Deserialize(msg);
ChatMessageReceived(packet.Username, packet.Message, sender);
}
break;
@ -224,7 +220,7 @@ namespace RageCoop.Server
{
if (Settings.UseVoice && !Settings.UseP2P)
{
Forward(data.GetPacket<Packets.Voice>(), sender, ConnectionChannel.Voice);
Forward(msg.GetPacket<Packets.Voice>(), sender, ConnectionChannel.Voice);
}
}
break;
@ -232,8 +228,8 @@ namespace RageCoop.Server
case PacketType.CustomEvent:
{
Packets.CustomEvent packet = new Packets.CustomEvent();
packet.Deserialize(data);
_worker.QueueJob(() => API.Events.InvokeCustomEventReceived(packet, sender));
packet.Deserialize(msg);
QueueJob(() => API.Events.InvokeCustomEventReceived(packet, sender));
}
break;
default:

View File

@ -1,23 +1,16 @@
using System;
using System.Diagnostics;
using System.Text;
using System.Net;
using System.Linq;
using System.Collections.Generic;
using System.Threading;
using System.Reflection;
using System.IO;
using System.Net.Http;
using Lidgren.Network;
using RageCoop.Core;
using Newtonsoft.Json;
using Lidgren.Network;
using System.Timers;
using System.Security.Cryptography;
using RageCoop.Server.Scripting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using Timer = System.Timers.Timer;
using System.Net.Sockets;
using System.Threading.Tasks;
using RageCoop.Core.Scripting;
namespace RageCoop.Server
{
@ -37,12 +30,12 @@ namespace RageCoop.Server
internal ServerEntities Entities;
internal readonly Dictionary<Command, Action<CommandContext>> Commands = new();
internal readonly Dictionary<long,Client> ClientsByNetHandle = new();
internal readonly Dictionary<long, Client> ClientsByNetHandle = new();
internal readonly Dictionary<string, Client> ClientsByName = new();
internal readonly Dictionary<int, Client> ClientsByID = new();
internal Client _hostClient;
private Dictionary<int,FileTransfer> InProgressFileTransfers=new();
private readonly Dictionary<int, FileTransfer> InProgressFileTransfers = new();
internal Resources Resources;
internal Logger Logger;
internal Security Security;
@ -54,8 +47,8 @@ namespace RageCoop.Server
private readonly Timer _updateTimer = new();
private readonly Worker _worker;
private readonly HashSet<char> _allowedCharacterSet;
private Dictionary<int,Action<PacketType,byte[]>> PendingResponses=new();
internal Dictionary<PacketType, Func<byte[],Client,Packet>> RequestHandlers=new();
private readonly Dictionary<int, Action<PacketType, NetIncomingMessage>> PendingResponses = new();
internal Dictionary<PacketType, Func<NetIncomingMessage, Client, Packet>> RequestHandlers = new();
/// <summary>
/// Get the current server version
/// </summary>
@ -66,23 +59,23 @@ namespace RageCoop.Server
/// <param name="settings"></param>
/// <param name="logger"></param>
/// <exception cref="ArgumentNullException"></exception>
public Server(Settings settings,Logger logger=null)
public Server(Settings settings, Logger logger = null)
{
Settings = settings;
if (settings==null) { throw new ArgumentNullException("Server settings cannot be null!"); }
Logger=logger;
if (Logger!=null) { Logger.LogLevel=Settings.LogLevel;}
API=new API(this);
Resources=new Resources(this);
Security=new Security(Logger);
Entities=new ServerEntities(this);
BaseScript=new BaseScript(this);
_allowedCharacterSet=new HashSet<char>(Settings.AllowedUsernameChars.ToCharArray());
if (settings == null) { throw new ArgumentNullException("Server settings cannot be null!"); }
Logger = logger;
if (Logger != null) { Logger.LogLevel = Settings.LogLevel; }
API = new API(this);
Resources = new Resources(this);
Security = new Security(Logger);
Entities = new ServerEntities(this);
BaseScript = new BaseScript(this);
_allowedCharacterSet = new HashSet<char>(Settings.AllowedUsernameChars.ToCharArray());
_worker=new Worker("ServerWorker", Logger);
_worker = new Worker("ServerWorker", Logger);
_listenerThread=new Thread(() => Listen());
_listenerThread = new Thread(() => Listen());
_announceTimer.Interval = 1;
_announceTimer.Elapsed += (s, e) =>
@ -104,7 +97,7 @@ namespace RageCoop.Server
_updateTimer.Interval = 1;
_updateTimer.Elapsed += (s, e) =>
{
_updateTimer.Interval= 1000 * 60 * 10; // 10 minutes
_updateTimer.Interval = 1000 * 60 * 10; // 10 minutes
_updateTimer.Stop();
CheckUpdate();
_updateTimer.Start();
@ -118,15 +111,26 @@ namespace RageCoop.Server
public void Start()
{
Logger?.Info("================");
Logger?.Info($"Server bound to: 0.0.0.0:{Settings.Port}");
Logger?.Info($"Listening port: {Settings.Port}");
Logger?.Info($"Server version: {Version}");
Logger?.Info($"Compatible RAGECOOP versions: {Version.ToString(3)}");
Logger?.Info($"Compatible client version: {Version.ToString(3)}");
Logger?.Info($"Runtime: {CoreUtils.GetInvariantRID()} => {System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier}");
Logger?.Info("================");
Logger?.Info($"Listening addresses:");
foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
{
Logger?.Info($"[{netInterface.Description}]:");
IPInterfaceProperties ipProps = netInterface.GetIPProperties();
foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
{
Logger.Info(string.Join(", ", addr.Address));
}
Logger.Info("");
}
if (Settings.UseZeroTier)
{
Logger?.Info($"Joining ZeroTier network: "+Settings.ZeroTierNetworkID);
if (ZeroTierHelper.Join(Settings.ZeroTierNetworkID)==null)
Logger?.Info($"Joining ZeroTier network: " + Settings.ZeroTierNetworkID);
if (ZeroTierHelper.Join(Settings.ZeroTierNetworkID) == null)
{
throw new Exception("Failed to obtain ZeroTier network IP");
}
@ -143,7 +147,7 @@ namespace RageCoop.Server
MaximumConnections = Settings.MaxPlayers,
EnableUPnP = false,
AutoFlushSendQueue = true,
PingInterval=5
PingInterval = 5
};
config.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
@ -151,16 +155,16 @@ namespace RageCoop.Server
MainNetServer = new NetServer(config);
MainNetServer.Start();
Logger?.Info(string.Format("Server listening on {0}:{1}", config.LocalAddress.ToString(), config.Port));
BaseScript.API=API;
BaseScript.API = API;
BaseScript.OnStart();
Resources.LoadAll();
_listenerThread.Start();
_playerUpdateTimer.Enabled=true;
Logger?.Info("Listening for clients");
_playerUpdateTimer.Enabled = true;
if (Settings.AnnounceSelf)
{
_announceTimer.Enabled=true;
_announceTimer.Enabled = true;
}
if (Settings.AutoUpdate)
{
@ -169,7 +173,6 @@ namespace RageCoop.Server
_antiAssholesTimer.Enabled = true;
Logger?.Info("Listening for clients");
}
/// <summary>
/// Terminate threads and stop the server
@ -190,20 +193,20 @@ namespace RageCoop.Server
}
// Send a message to targets or all players
internal void ChatMessageReceived(string name, string message,Client sender=null)
internal void ChatMessageReceived(string name, string message, Client sender = null)
{
if (message.StartsWith('/'))
{
string[] cmdArgs = message.Split(" ");
string cmdName = cmdArgs[0].Remove(0, 1);
_worker.QueueJob(()=>API.Events.InvokeOnCommandReceived(cmdName, cmdArgs, sender));
QueueJob(() => API.Events.InvokeOnCommandReceived(cmdName, cmdArgs, sender));
return;
}
message = message.Replace("~", "");
_worker.QueueJob(() => API.Events.InvokeOnChatMessage(message, sender));
QueueJob(() => API.Events.InvokeOnChatMessage(message, sender));
foreach(var c in ClientsByNetHandle.Values)
foreach (var c in ClientsByNetHandle.Values)
{
var msg = MainNetServer.CreateMessage();
var crypt = new Func<string, byte[]>((s) =>
@ -212,23 +215,23 @@ namespace RageCoop.Server
});
new Packets.ChatMessage(crypt)
{
Username=name,
Message=message
Username = name,
Message = message
}.Pack(msg);
MainNetServer.SendMessage(msg,c.Connection, NetDeliveryMethod.ReliableOrdered, (int)ConnectionChannel.Chat);
MainNetServer.SendMessage(msg, c.Connection, NetDeliveryMethod.ReliableOrdered, (int)ConnectionChannel.Chat);
}
}
internal void SendChatMessage(string name, string message, Client target)
{
if(target == null) { return; }
if (target == null) { return; }
var msg = MainNetServer.CreateMessage();
new Packets.ChatMessage(new Func<string, byte[]>((s) =>
{
return Security.Encrypt(s.GetBytes(), target.EndPoint);
}))
{
Username= name,
Message=message,
Username = name,
Message = message,
}.Pack(msg);
MainNetServer.SendMessage(msg, target.Connection, NetDeliveryMethod.ReliableOrdered, (int)ConnectionChannel.Chat);
}
@ -267,67 +270,60 @@ namespace RageCoop.Server
RegisterCommand(attribute.Name, attribute.Usage, attribute.ArgsLength, (Action<CommandContext>)Delegate.CreateDelegate(typeof(Action<CommandContext>), method));
}
}
internal T GetResponse<T>(Client client,Packet request, ConnectionChannel channel = ConnectionChannel.RequestResponse,int timeout=5000) where T:Packet, new()
internal T GetResponse<T>(Client client, Packet request, ConnectionChannel channel = ConnectionChannel.RequestResponse, int timeout = 5000) where T : Packet, new()
{
if (Thread.CurrentThread==_listenerThread)
if (Thread.CurrentThread == _listenerThread)
{
throw new InvalidOperationException("Cannot wait for response from the listener thread!");
}
var received=new AutoResetEvent(false);
byte[] response=null;
var received = new AutoResetEvent(false);
T response = new T();
var id = NewRequestID();
PendingResponses.Add(id, (type,p) =>
PendingResponses.Add(id, (type, m) =>
{
response=p;
response.Deserialize(m);
received.Set();
});
var msg = MainNetServer.CreateMessage();
msg.Write((byte)PacketType.Request);
msg.Write(id);
request.Pack(msg);
MainNetServer.SendMessage(msg,client.Connection,NetDeliveryMethod.ReliableOrdered,(int)channel);
MainNetServer.SendMessage(msg, client.Connection, NetDeliveryMethod.ReliableOrdered, (int)channel);
if (received.WaitOne(timeout))
{
var p = new T();
p.Deserialize(response);
return p;
}
else
{
return null;
return response;
}
return null;
}
internal void SendFile(string path,string name,Client client,Action<float> updateCallback=null)
internal void SendFile(string path, string name, Client client, Action<float> updateCallback = null)
{
var fs = File.OpenRead(path);
SendFile(fs, name,client,NewFileID(),updateCallback);
SendFile(fs, name, client, NewFileID(), updateCallback);
fs.Close();
fs.Dispose();
}
internal void SendFile(Stream stream, string name, Client client,int id=default, Action<float> updateCallback = null)
internal void SendFile(Stream stream, string name, Client client, int id = default, Action<float> updateCallback = null)
{
stream.Seek(0, SeekOrigin.Begin);
// Logger.Debug("1");
id = id ==default? NewFileID(): id ;
// Logger.Debug("2");
id = id == default ? NewFileID() : id;
var total = stream.Length;
// Logger.Debug("3");
Logger?.Debug($"Requesting file transfer:{name}, {total}");
if (GetResponse<Packets.FileTransferResponse>(client, new Packets.FileTransferRequest()
{
FileLength= total,
Name=name,
ID=id,
}, ConnectionChannel.File)?.Response!=FileResponse.NeedToDownload)
FileLength = total,
Name = name,
ID = id,
}, ConnectionChannel.File)?.Response != FileResponse.NeedToDownload)
{
Logger?.Info($"Skipping file transfer \"{name}\" to {client.Username}");
// stream.Close();
// stream.Dispose();
return;
}
Logger?.Debug($"Initiating file transfer:{name}, {total}");
FileTransfer transfer = new()
{
ID=id,
ID = id,
Name = name,
};
InProgressFileTransfers.Add(id, transfer);
@ -337,40 +333,38 @@ namespace RageCoop.Server
{
// 4 KB chunk
byte[] chunk = new byte[4096];
read += thisRead=stream.Read(chunk, 0, 4096);
if (thisRead!=chunk.Length)
read += thisRead = stream.Read(chunk, 0, 4096);
if (thisRead != chunk.Length)
{
if (thisRead==0) { break; }
if (thisRead == 0) { break; }
Logger?.Trace($"Purging chunk:{thisRead}");
Array.Resize(ref chunk, thisRead);
}
Send(
new Packets.FileTransferChunk()
{
ID=id,
FileChunk=chunk,
ID = id,
FileChunk = chunk,
},
client, ConnectionChannel.File, NetDeliveryMethod.ReliableOrdered);
transfer.Progress=read/stream.Length;
if (updateCallback!=null) { updateCallback(transfer.Progress); }
transfer.Progress = read / stream.Length;
if (updateCallback != null) { updateCallback(transfer.Progress); }
} while (thisRead>0);
} while (thisRead > 0);
if (GetResponse<Packets.FileTransferResponse>(client, new Packets.FileTransferComplete()
{
ID= id,
}, ConnectionChannel.File)?.Response!=FileResponse.Completed)
ID = id,
}, ConnectionChannel.File)?.Response != FileResponse.Completed)
{
Logger.Warning($"File trasfer to {client.Username} failed: "+name);
Logger.Warning($"File trasfer to {client.Username} failed: " + name);
}
// stream.Close();
// stream.Dispose();
Logger?.Debug($"All file chunks sent:{name}");
InProgressFileTransfers.Remove(id);
}
internal int NewFileID()
{
int ID = 0;
while ((ID==0)
while ((ID == 0)
|| InProgressFileTransfers.ContainsKey(ID))
{
byte[] rngBytes = new byte[4];
@ -385,7 +379,7 @@ namespace RageCoop.Server
private int NewRequestID()
{
int ID = 0;
while ((ID==0)
while ((ID == 0)
|| PendingResponses.ContainsKey(ID))
{
byte[] rngBytes = new byte[4];
@ -397,11 +391,11 @@ namespace RageCoop.Server
}
return ID;
}
internal void Send(Packet p,Client client, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
internal void Send(Packet p, Client client, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
{
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
p.Pack(outgoingMessage);
MainNetServer.SendMessage(outgoingMessage, client.Connection,method,(int)channel);
MainNetServer.SendMessage(outgoingMessage, client.Connection, method, (int)channel);
}
internal void Forward(Packet p, Client except, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
{

View File

@ -1,36 +1,33 @@
using System;
using RageCoop.Core;
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using RageCoop.Core;
using Newtonsoft.Json;
using System.Linq;
namespace RageCoop.Server
{
class Program
internal class Program
{
private static bool Stopping = false;
static Logger mainLogger;
static void Main(string[] args)
private static Logger mainLogger;
private static void Main(string[] args)
{
if (args.Length>=2 && args[0]=="update")
if (args.Length >= 2 && args[0] == "update")
{
var target = args[1];
int i =0;
while (i < 10)
int i = 0;
while (i++ < 10)
{
i++;
try
{
Console.WriteLine("Applying update to "+target);
Console.WriteLine("Applying update to " + target);
CoreUtils.CopyFilesRecursively(new(AppDomain.CurrentDomain.BaseDirectory), new(target));
Process.Start(Path.Combine(target, "RageCoop.Server"));
Environment.Exit(0);
}
catch(Exception ex)
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Thread.Sleep(3000);
@ -38,22 +35,22 @@ namespace RageCoop.Server
}
Environment.Exit(i);
}
AppDomain.CurrentDomain.UnhandledException+=UnhandledException;
AppDomain.CurrentDomain.UnhandledException += UnhandledException;
mainLogger = new Logger()
{
LogPath="RageCoop.Server.log",
UseConsole=true,
Name="Server"
LogPath = "RageCoop.Server.log",
UseConsole = true,
Name = "Server"
};
try
{
Console.Title = "RAGECOOP";
var setting = Util.Read<Settings>("Settings.xml");
#if DEBUG
setting.LogLevel=0;
setting.LogLevel = 0;
#endif
var server = new Server(setting, mainLogger);
Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e)
{
mainLogger.Info("Initiating shutdown sequence...");
mainLogger.Info("Press Ctrl+C again to commence an emergency shutdown.");
@ -83,8 +80,8 @@ namespace RageCoop.Server
while (true)
{
var s=Console.ReadLine();
if (!Stopping && s!=null)
var s = Console.ReadLine();
if (!Stopping && s != null)
{
server.ChatMessageReceived("Server", s, null);
}
@ -99,11 +96,11 @@ namespace RageCoop.Server
private static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
mainLogger.Error($"Unhandled exception thrown from user thread:",e.ExceptionObject as Exception);
mainLogger.Error($"Unhandled exception thrown from user thread", e.ExceptionObject as Exception);
mainLogger.Flush();
}
static void Fatal(Exception e)
private static void Fatal(Exception e)
{
mainLogger.Error(e);
mainLogger.Error($"Fatal error occurred, server shutting down.");

View File

@ -15,7 +15,7 @@ using System.Resources;
[assembly: AssemblyCulture("")]
// Version information
[assembly: AssemblyVersion("1.5.3.107")]
[assembly: AssemblyFileVersion("1.5.3.107")]
[assembly: AssemblyVersion("1.5.4.5")]
[assembly: AssemblyFileVersion("1.5.4.5")]
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]

View File

@ -49,12 +49,12 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Fody" Version="6.6.3">
<PackageReference Include="Fody" Version="6.8.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="6.0.8" />
<PackageReference Include="SharpZipLib" Version="1.3.3" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="7.0.9" />
<PackageReference Include="SharpZipLib" Version="1.4.2" />
</ItemGroup>
<ItemGroup>

View File

@ -1,13 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Lidgren.Network;
using Lidgren.Network;
using RageCoop.Core;
using RageCoop.Core.Scripting;
using System.Reflection;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace RageCoop.Server.Scripting
{
@ -54,14 +53,14 @@ namespace RageCoop.Server.Scripting
public event EventHandler<Client> OnPlayerUpdate;
internal void ClearHandlers()
{
OnChatMessage=null;
OnPlayerHandshake=null;
OnPlayerConnected=null;
OnPlayerReady=null;
OnPlayerDisconnected=null;
OnChatMessage = null;
OnPlayerHandshake = null;
OnPlayerConnected = null;
OnPlayerReady = null;
OnPlayerDisconnected = null;
// OnCustomEventReceived=null;
OnCommandReceived=null;
OnPlayerUpdate=null;
OnCommandReceived = null;
OnPlayerUpdate = null;
}
#region INVOKE
internal void InvokePlayerHandshake(HandshakeEventArgs args)
@ -70,9 +69,9 @@ namespace RageCoop.Server.Scripting
{
var args = new OnCommandEventArgs()
{
Name=cmdName,
Args=cmdArgs,
Client=sender
Name = cmdName,
Args = cmdArgs,
Client = sender
};
OnCommandReceived?.Invoke(this, args);
if (args.Cancel)
@ -99,27 +98,26 @@ namespace RageCoop.Server.Scripting
}
}
internal void InvokeOnChatMessage(string msg, Client sender, string clamiedSender=null)
internal void InvokeOnChatMessage(string msg, Client sender, string clamiedSender = null)
{
OnChatMessage?.Invoke(this, new ChatEventArgs()
{
Client=sender,
Message=msg,
ClaimedSender=clamiedSender
Client = sender,
Message = msg,
ClaimedSender = clamiedSender
});
}
internal void InvokePlayerConnected(Client client)
{ OnPlayerConnected?.Invoke(this,client); }
{ OnPlayerConnected?.Invoke(this, client); }
internal void InvokePlayerReady(Client client)
{ OnPlayerReady?.Invoke(this, client); }
internal void InvokePlayerDisconnected(Client client)
{ OnPlayerDisconnected?.Invoke(this,client); }
{ OnPlayerDisconnected?.Invoke(this, client); }
internal void InvokeCustomEventReceived(Packets.CustomEvent p, Client sender)
{
var args = new CustomEventReceivedArgs() { Hash=p.Hash, Args=p.Args, Client=sender };
List<Action<CustomEventReceivedArgs>> handlers;
if (CustomEventHandlers.TryGetValue(p.Hash, out handlers))
var args = new CustomEventReceivedArgs() { Hash = p.Hash, Args = p.Args, Client = sender };
if (CustomEventHandlers.TryGetValue(p.Hash, out List<Action<CustomEventReceivedArgs>> handlers))
{
handlers.ForEach((x) => { x.Invoke(args); });
}
@ -136,32 +134,32 @@ namespace RageCoop.Server.Scripting
public class API
{
internal readonly Server Server;
internal readonly Dictionary<string, Func<Stream>> RegisteredFiles=new Dictionary<string, Func<System.IO.Stream>>();
internal readonly Dictionary<string, Func<Stream>> RegisteredFiles = new Dictionary<string, Func<System.IO.Stream>>();
internal API(Server server)
{
Server=server;
Events=new(server);
Server.RequestHandlers.Add(PacketType.FileTransferRequest, (data,client) =>
Server = server;
Events = new(server);
Server.RequestHandlers.Add(PacketType.FileTransferRequest, (data, client) =>
{
var p = new Packets.FileTransferRequest();
p.Deserialize(data);
var id=Server.NewFileID();
if(RegisteredFiles.TryGetValue(p.Name,out var s))
var id = Server.NewFileID();
if (RegisteredFiles.TryGetValue(p.Name, out var s))
{
Task.Run(() =>
{
Server.SendFile(s(), p.Name, client,id);
Server.SendFile(s(), p.Name, client, id);
});
return new Packets.FileTransferResponse()
{
ID=id,
Response=FileResponse.Loaded
ID = id,
Response = FileResponse.Loaded
};
}
return new Packets.FileTransferResponse()
{
ID=id,
Response=FileResponse.LoadFailed
ID = id,
Response = FileResponse.LoadFailed
};
});
}
@ -173,7 +171,7 @@ namespace RageCoop.Server.Scripting
/// <summary>
/// All synchronized entities on this server.
/// </summary>
public ServerEntities Entities { get { return Server.Entities; } }
public ServerEntities Entities => Server.Entities;
#region FUNCTIONS
/// <summary>
@ -204,9 +202,9 @@ namespace RageCoop.Server.Scripting
/// <param name="username">The username which send this message (default = "Server")</param>
/// <param name="raiseEvent">Weather to raise the <see cref="ServerEvents.OnChatMessage"/> event defined in <see cref="API.Events"/></param>
/// <remarks>When <paramref name="raiseEvent"/> is unspecified and <paramref name="targets"/> is null or unspecified, <paramref name="raiseEvent"/> will be set to true</remarks>
public void SendChatMessage(string message, List<Client> targets = null, string username = "Server",bool? raiseEvent=null)
public void SendChatMessage(string message, List<Client> targets = null, string username = "Server", bool? raiseEvent = null)
{
raiseEvent ??= targets==null;
raiseEvent ??= targets == null;
try
{
if (Server.MainNetServer.ConnectionsCount != 0)
@ -233,7 +231,7 @@ namespace RageCoop.Server.Scripting
/// </summary>
/// <param name="name">name of this file</param>
/// <param name="path">path to this file</param>
public void RegisterSharedFile(string name,string path)
public void RegisterSharedFile(string name, string path)
{
RegisteredFiles.Add(name, () => { return File.OpenRead(path); });
}
@ -300,7 +298,7 @@ namespace RageCoop.Server.Scripting
/// <param name="hash"></param>
/// <param name="args"></param>
/// /// <param name="clients">Clients to send, null for all clients</param>
public void SendNativeCall(List<Client> clients , GTA.Native.Hash hash, params object[] args)
public void SendNativeCall(List<Client> clients, GTA.Native.Hash hash, params object[] args)
{
var argsList = new List<object>(args);
argsList.InsertRange(0, new object[] { (byte)TypeCode.Empty, (ulong)hash });
@ -314,14 +312,14 @@ namespace RageCoop.Server.Scripting
/// <param name="eventHash">An unique identifier of the event, you can use <see cref="CustomEvents.Hash(string)"/> to get it from a string</param>
/// <param name="args">The objects conataing your data, see <see cref="Scripting.CustomEventReceivedArgs.Args"/> for supported types.</param>
/// <param name="targets">The target clients to send. Leave it null to send to all clients</param>
public void SendCustomEvent(List<Client> targets, int eventHash, params object[] args)
public void SendCustomEvent(List<Client> targets, int eventHash, params object[] args)
{
targets ??= new(Server.ClientsByNetHandle.Values);
var p = new Packets.CustomEvent()
{
Args=args,
Hash=eventHash
Args = args,
Hash = eventHash
};
foreach (var c in targets)
{
@ -339,10 +337,10 @@ namespace RageCoop.Server.Scripting
{
targets ??= new(Server.ClientsByNetHandle.Values);
var p = new Packets.CustomEvent(null,true)
var p = new Packets.CustomEvent(null, true)
{
Args=args,
Hash=eventHash
Args = args,
Hash = eventHash
};
foreach (var c in targets)
{
@ -354,12 +352,11 @@ namespace RageCoop.Server.Scripting
/// </summary>
/// <param name="hash">An unique identifier of the event, you can hash your event name with <see cref="CustomEvents.Hash(string)"/></param>
/// <param name="handler">An handler to be invoked when the event is received from the server.</param>
public void RegisterCustomEventHandler(int hash,Action<CustomEventReceivedArgs> handler)
public void RegisterCustomEventHandler(int hash, Action<CustomEventReceivedArgs> handler)
{
List<Action<CustomEventReceivedArgs>> handlers;
lock (Events.CustomEventHandlers)
{
if (!Events.CustomEventHandlers.TryGetValue(hash,out handlers))
if (!Events.CustomEventHandlers.TryGetValue(hash, out List<Action<CustomEventReceivedArgs>> handlers))
{
Events.CustomEventHandlers.Add(hash, handlers = new List<Action<CustomEventReceivedArgs>>());
}
@ -385,11 +382,11 @@ namespace RageCoop.Server.Scripting
/// <returns>A <see langword="dynamic"/> object reprensenting the script, or <see langword="null"/> if not found.</returns>
/// <remarks>Explicitly casting the return value to orginal type will case a exception to be thrown due to the dependency isolation mechanism in resource system.
/// You shouldn't reference the target resource assemblies either, since it causes the referenced assembly to be loaded and started in your resource.</remarks>
public dynamic FindScript(string scriptFullName,string resourceName=null)
public dynamic FindScript(string scriptFullName, string resourceName = null)
{
if (resourceName==null)
if (resourceName == null)
{
foreach(var res in LoadedResources.Values)
foreach (var res in LoadedResources.Values)
{
if (res.Scripts.TryGetValue(scriptFullName, out var script))
{
@ -399,7 +396,7 @@ namespace RageCoop.Server.Scripting
}
else if (LoadedResources.TryGetValue(resourceName, out var res))
{
if(res.Scripts.TryGetValue(scriptFullName, out var script))
if (res.Scripts.TryGetValue(scriptFullName, out var script))
{
return script;
}
@ -415,7 +412,7 @@ namespace RageCoop.Server.Scripting
/// <summary>
/// Get a <see cref="Core.Logger"/> that the server is currently using, you should use <see cref="ServerResource.Logger"/> to display resource-specific information.
/// </summary>
public Logger Logger { get { return Server.Logger; } }
public Logger Logger => Server.Logger;
/// <summary>
@ -423,8 +420,9 @@ namespace RageCoop.Server.Scripting
/// </summary>
public Client Host
{
get { return Server._hostClient; }
set {
get => Server._hostClient;
set
{
if (Server._hostClient != value)
{
Server._hostClient?.SendCustomEvent(CustomEvents.IsHost, false);
@ -440,7 +438,7 @@ namespace RageCoop.Server.Scripting
/// <remarks>Accessing this property from script constructor is stronly discouraged since other scripts and resources might have yet been loaded.
/// Accessing from <see cref="ServerScript.OnStart"/> is not recommended either. Although all script assemblies will have been loaded to memory and instantiated, <see cref="ServerScript.OnStart"/> invocation of other scripts are not guaranteed.
/// </remarks>
public Dictionary<string,ServerResource> LoadedResources
public Dictionary<string, ServerResource> LoadedResources
{
get
{

View File

@ -1,17 +1,14 @@
using System;
using RageCoop.Core.Scripting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RageCoop.Core.Scripting;
using RageCoop.Core;
namespace RageCoop.Server.Scripting
{
internal class BaseScript:ServerScript
internal class BaseScript : ServerScript
{
private readonly Server Server;
public BaseScript(Server server) { Server=server; }
public BaseScript(Server server) { Server = server; }
public override void OnStart()
{
API.RegisterCustomEventHandler(CustomEvents.NativeResponse, NativeResponse);
@ -31,7 +28,7 @@ namespace RageCoop.Server.Scripting
foreach (var c in API.GetAllClients().Values)
{
if (c==e.Client)
if (c == e.Client)
{
continue;
}
@ -41,49 +38,49 @@ namespace RageCoop.Server.Scripting
});
API.RegisterCustomEventHandler(CustomEvents.OnPlayerDied, (e) =>
{
API.SendCustomEventQueued(API.GetAllClients().Values.Where(x=>x!=e.Client).ToList(),CustomEvents.OnPlayerDied,e.Client.Username);
API.SendCustomEventQueued(API.GetAllClients().Values.Where(x => x != e.Client).ToList(), CustomEvents.OnPlayerDied, e.Args);
});
API.Events.OnChatMessage+=(s,e) =>
Server.Logger?.Info((e.Client?.Username ?? e.ClaimedSender ?? "Unknown") + ": " + e.Message);
API.Events.OnChatMessage += (s, e) =>
Server.Logger?.Info((e.Client?.Username ?? e.ClaimedSender ?? "Unknown") + ": " + e.Message);
}
public override void OnStop()
{
}
public static void SetAutoRespawn(Client c,bool toggle)
public static void SetAutoRespawn(Client c, bool toggle)
{
c.SendCustomEvent(CustomEvents.SetAutoRespawn, toggle );
c.SendCustomEvent(CustomEvents.SetAutoRespawn, toggle);
}
public void SetNameTag(Client c, bool toggle)
{
foreach(var other in API.GetAllClients().Values)
foreach (var other in API.GetAllClients().Values)
{
if (c==other) { continue; }
other.SendCustomEvent(CustomEvents.SetDisplayNameTag,c.Player.ID, toggle);
if (c == other) { continue; }
other.SendCustomEvent(CustomEvents.SetDisplayNameTag, c.Player.ID, toggle);
}
}
public void SendServerPropsTo(List<ServerProp> objects,List<Client> clients=null)
public void SendServerPropsTo(List<ServerProp> objects, List<Client> clients = null)
{
foreach(var obj in objects)
foreach (var obj in objects)
{
API.SendCustomEventQueued(clients, CustomEvents.ServerPropSync,obj.ID, obj.Model ,obj.Position,obj.Rotation );
API.SendCustomEventQueued(clients, CustomEvents.ServerPropSync, obj.ID, obj.Model, obj.Position, obj.Rotation);
}
}
public void SendServerBlipsTo(List<ServerBlip> objects, List<Client> clients = null)
{
foreach (var obj in objects)
{
API.SendCustomEventQueued(clients, CustomEvents.ServerBlipSync, obj.ID, (ushort)obj.Sprite, (byte)obj.Color, obj.Scale,obj.Position,obj.Rotation,obj.Name );
API.SendCustomEventQueued(clients, CustomEvents.ServerBlipSync, obj.ID, (ushort)obj.Sprite, (byte)obj.Color, obj.Scale, obj.Position, obj.Rotation, obj.Name);
}
}
void NativeResponse(CustomEventReceivedArgs e)
private void NativeResponse(CustomEventReceivedArgs e)
{
try
{
int id = (int)e.Args[0];
Action<object> callback;
lock (e.Client.Callbacks)
{
if (e.Client.Callbacks.TryGetValue(id, out callback))
if (e.Client.Callbacks.TryGetValue(id, out Action<object> callback))
{
callback(e.Args[1]);
e.Client.Callbacks.Remove(id);

View File

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
namespace RageCoop.Server.Scripting
@ -97,10 +94,10 @@ namespace RageCoop.Server.Scripting
/// <param name="reason"></param>
public void Deny(string reason)
{
DenyReason=reason;
Cancel=true;
DenyReason = reason;
Cancel = true;
}
internal string DenyReason { get; set; }
internal bool Cancel { get; set; }=false;
internal bool Cancel { get; set; } = false;
}
}

View File

@ -1,83 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RageCoop.Core.Scripting;
using ICSharpCode.SharpZipLib.Zip;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using System.Reflection;
using McMaster.NETCore.Plugins;
using System.Threading.Tasks;
namespace RageCoop.Server.Scripting
{
internal class Resources
{
public Dictionary<string,ServerResource> LoadedResources=new();
private readonly Server Server;
private readonly Logger Logger;
public bool IsLoaded { get; private set; } = false;
public Resources(Server server)
{
Server = server;
Logger=server.Logger;
}
private Dictionary<string,Func<Stream>> ClientResources=new();
private Dictionary<string,Func<Stream>> ResourceStreams=new();
private List<MemoryStream> MemStreams = new();
public void LoadAll()
{
// Packages
{
var path = Path.Combine("Resources", "Packages");
Directory.CreateDirectory(path);
foreach (var pkg in Directory.GetFiles(path,"*.respkg",SearchOption.AllDirectories))
{
Logger?.Debug($"Adding resourece from package \"{Path.GetFileNameWithoutExtension(pkg)}\"");
var pkgZip = new ZipFile(pkg);
foreach (ZipEntry e in pkgZip)
{
if (!e.IsFile) { continue; }
if (e.Name.StartsWith("Client") && e.Name.EndsWith(".res"))
{
var stream = pkgZip.GetInputStream(e).ToMemStream();
MemStreams.Add(stream);
ClientResources.Add(Path.GetFileNameWithoutExtension(e.Name), () => stream);
Logger?.Debug("Resource added: "+ Path.GetFileNameWithoutExtension(e.Name));
}
else if (e.Name.StartsWith("Server") && e.Name.EndsWith(".res"))
{
var stream = pkgZip.GetInputStream(e).ToMemStream();
MemStreams.Add(stream);
ResourceStreams.Add(Path.GetFileNameWithoutExtension(e.Name), () => stream);
Logger?.Debug("Resource added: " + Path.GetFileNameWithoutExtension(e.Name));
}
}
pkgZip.Close();
}
}
// Client
internal class Resources
{
public Dictionary<string, ServerResource> LoadedResources = new();
private readonly Server Server;
private readonly Logger Logger;
public bool IsLoaded { get; private set; } = false;
public Resources(Server server)
{
Server = server;
Logger = server.Logger;
}
private readonly Dictionary<string, Stream> ClientResources = new();
private readonly Dictionary<string, Stream> ResourceStreams = new();
public void LoadAll()
{
// Packages
{
var path = Path.Combine("Resources", "Client");
var tmpDir = Path.Combine("Resources", "Temp","Client");
Directory.CreateDirectory(path);
if (Directory.Exists(tmpDir))
{
Directory.Delete(tmpDir, true);
}
Directory.CreateDirectory(tmpDir);
var resourceFolders = Directory.GetDirectories(path, "*", SearchOption.TopDirectoryOnly);
if (resourceFolders.Length!=0)
{
foreach (var resourceFolder in resourceFolders)
{
// Pack client side resource as a zip file
Logger?.Info("Packing client-side resource: "+resourceFolder);
var zipPath = Path.Combine(tmpDir, Path.GetFileName(resourceFolder))+".res";
try
{
var path = Path.Combine("Resources", "Packages");
Directory.CreateDirectory(path);
foreach (var pkg in Directory.GetFiles(path, "*.respkg", SearchOption.AllDirectories))
{
Logger?.Debug($"Adding resources from package \"{Path.GetFileNameWithoutExtension(pkg)}\"");
var pkgZip = new ZipFile(pkg);
foreach (ZipEntry e in pkgZip)
{
if (!e.IsFile) { continue; }
if (e.Name.StartsWith("Client") && e.Name.EndsWith(".res"))
{
var stream = pkgZip.GetInputStream(e).ToMemStream();
ClientResources.Add(Path.GetFileNameWithoutExtension(e.Name), stream);
Logger?.Debug("Resource added: " + Path.GetFileNameWithoutExtension(e.Name));
}
else if (e.Name.StartsWith("Server") && e.Name.EndsWith(".res"))
{
var stream = pkgZip.GetInputStream(e).ToMemStream();
ResourceStreams.Add(Path.GetFileNameWithoutExtension(e.Name), stream);
Logger?.Debug("Resource added: " + Path.GetFileNameWithoutExtension(e.Name));
}
}
pkgZip.Close();
}
}
// Client
{
var path = Path.Combine("Resources", "Client");
var tmpDir = Path.Combine("Resources", "Temp", "Client");
Directory.CreateDirectory(path);
if (Directory.Exists(tmpDir))
{
Directory.Delete(tmpDir, true);
}
Directory.CreateDirectory(tmpDir);
var resourceFolders = Directory.GetDirectories(path, "*", SearchOption.TopDirectoryOnly);
if (resourceFolders.Length != 0)
{
foreach (var resourceFolder in resourceFolders)
{
// Pack client side resource as a zip file
Logger?.Info("Packing client-side resource: " + resourceFolder);
var zipPath = Path.Combine(tmpDir, Path.GetFileName(resourceFolder)) + ".res";
try
{
using ZipFile zip = ZipFile.Create(zipPath);
zip.BeginUpdate();
foreach (var dir in Directory.GetDirectories(resourceFolder, "*", SearchOption.AllDirectories))
@ -91,169 +83,189 @@ namespace RageCoop.Server.Scripting
}
zip.CommitUpdate();
zip.Close();
ClientResources.Add(Path.GetFileNameWithoutExtension(zipPath), () => File.OpenRead(zipPath));
ClientResources.Add(Path.GetFileNameWithoutExtension(zipPath), File.OpenRead(zipPath));
}
catch (Exception ex)
{
Logger?.Error($"Failed to pack client resource:{resourceFolder}");
Logger?.Error(ex);
}
catch (Exception ex)
{
Logger?.Error($"Failed to pack client resource:{resourceFolder}");
Logger?.Error(ex);
}
}
}
var packed = Directory.GetFiles(path, "*.res", SearchOption.TopDirectoryOnly);
if (packed.Length>0)
{
foreach(var file in packed)
{
ClientResources.Add(Path.GetFileNameWithoutExtension(file),()=>File.OpenRead(file));
}
}
}
}
var packed = Directory.GetFiles(path, "*.res", SearchOption.TopDirectoryOnly);
if (packed.Length > 0)
{
foreach (var file in packed)
{
ClientResources.Add(Path.GetFileNameWithoutExtension(file), File.OpenRead(file));
}
}
}
// Server
// Server
{
var path = Path.Combine("Resources", "Server");
var dataFolder = Path.Combine(path, "data");
Directory.CreateDirectory(path);
foreach (var resource in Directory.GetDirectories(path))
{
var path = Path.Combine("Resources", "Server");
var dataFolder = Path.Combine(path, "data");
Directory.CreateDirectory(path);
foreach (var resource in Directory.GetDirectories(path))
{
try
{
var name = Path.GetFileName(resource);
if (LoadedResources.ContainsKey(name))
var name = Path.GetFileName(resource);
if (LoadedResources.ContainsKey(name))
{
Logger?.Warning($"Resource \"{name}\" has already been loaded, ignoring...");
continue;
}
if (name.ToLower()=="data") { continue; }
Logger?.Info($"Loading resource: {name}");
var r = ServerResource.LoadFrom(resource, dataFolder, Logger);
LoadedResources.Add(r.Name, r);
}
catch(Exception ex)
Logger?.Warning($"Resource \"{name}\" has already been loaded, ignoring...");
continue;
}
if (name.ToLower() == "data") { continue; }
Logger?.Info($"Loading resource: {name}");
var r = ServerResource.LoadFrom(resource, dataFolder, Logger);
LoadedResources.Add(r.Name, r);
}
catch (Exception ex)
{
Logger?.Error($"Failed to load resource: {Path.GetFileName(resource)}");
Logger?.Error(ex);
}
}
foreach (var res in Directory.GetFiles(path, "*.res", SearchOption.TopDirectoryOnly))
{
if (!ResourceStreams.TryAdd(Path.GetFileNameWithoutExtension(res),()=>File.OpenRead(res)))
{
Logger?.Warning($"Resource \"{res}\" cannot be loaded, ignoring...");
continue;
}
}
foreach(var res in ResourceStreams)
Logger?.Error($"Failed to load resource: {Path.GetFileName(resource)}");
Logger?.Error(ex);
}
}
foreach (var res in Directory.GetFiles(path, "*.res", SearchOption.TopDirectoryOnly))
{
try
if (!ResourceStreams.TryAdd(Path.GetFileNameWithoutExtension(res), File.OpenRead(res)))
{
var name = res.Key;
if (LoadedResources.ContainsKey(name))
{
Logger?.Warning($"Resource \"{name}\" has already been loaded, ignoring...");
continue;
}
Logger?.Info($"Loading resource: "+name);
var r = ServerResource.LoadFrom(res.Value(),name, Path.Combine("Resources", "Temp", "Server"), dataFolder, Logger);
LoadedResources.Add(r.Name, r);
}
catch(Exception ex)
Logger?.Warning($"Resource \"{res}\" cannot be loaded, ignoring...");
continue;
}
}
foreach (var res in ResourceStreams)
{
try
{
Logger?.Error($"Failed to load resource: {res.Key}");
Logger?.Error(ex);
var name = res.Key;
if (LoadedResources.ContainsKey(name))
{
Logger?.Warning($"Resource \"{name}\" has already been loaded, ignoring...");
continue;
}
Logger?.Info($"Loading resource: " + name);
var r = ServerResource.LoadFrom(res.Value, name, Path.Combine("Resources", "Temp", "Server"), dataFolder, Logger);
LoadedResources.Add(r.Name, r);
}
catch (Exception ex)
{
Logger?.Error($"Failed to load resource: {res.Key}");
Logger?.Error(ex);
}
}
// Start scripts
lock (LoadedResources)
{
foreach (var r in LoadedResources.Values)
{
foreach (ServerScript s in r.Scripts.Values)
{
s.API=Server.API;
try
{
Logger?.Debug("Starting script:"+s.CurrentFile.Name);
s.OnStart();
}
catch (Exception ex) { Logger?.Error($"Failed to start resource: {r.Name}"); Logger?.Error(ex); }
}
}
}
IsLoaded=true;
}
}
// Start scripts
lock (LoadedResources)
{
foreach (var r in LoadedResources.Values)
{
foreach (ServerScript s in r.Scripts.Values)
{
s.API = Server.API;
try
{
Logger?.Debug("Starting script:" + s.CurrentFile.Name);
s.OnStart();
}
catch (Exception ex) { Logger?.Error($"Failed to start resource: {r.Name}"); Logger?.Error(ex); }
}
}
}
IsLoaded = true;
}
}
public void UnloadAll()
{
lock (LoadedResources)
{
foreach (var d in LoadedResources.Values)
{
foreach (var s in d.Scripts.Values)
{
{
lock (LoadedResources)
{
foreach (var d in LoadedResources.Values)
{
foreach (var s in d.Scripts.Values)
{
try
{
s.OnStop();
}
catch(Exception ex)
s.OnStop();
}
catch (Exception ex)
{
Logger?.Error(ex);
Logger?.Error(ex);
}
}
try
{
d.Dispose();
}
catch(Exception ex)
{
Logger.Error($"Resource \"{d.Name}\" cannot be unloaded.");
Logger.Error(ex);
d.Dispose();
}
}
LoadedResources.Clear();
}
foreach(var s in MemStreams)
catch (Exception ex)
{
Logger.Error($"Resource \"{d.Name}\" cannot be unloaded.");
Logger.Error(ex);
}
}
LoadedResources.Clear();
}
foreach (var s in ResourceStreams.Values)
{
try
{
s.Close();
s.Dispose();
s.Close();
s.Dispose();
}
catch(Exception ex)
catch (Exception ex)
{
Logger?.Error("[Resources.CloseMemStream]",ex);
Logger?.Error("[Resources.CloseStream]", ex);
}
}
}
public void SendTo(Client client)
{
Task.Run(() =>
{
if (ClientResources.Count!=0)
{
Logger?.Info($"Sending resources to client:{client.Username}");
foreach (var rs in ClientResources)
{
Logger?.Debug(rs.Key);
Server.SendFile(rs.Value(),rs.Key+".res", client);
}
Logger?.Info($"Resources sent to:{client.Username}");
}
if (Server.GetResponse<Packets.FileTransferResponse>(client, new Packets.AllResourcesSent())?.Response==FileResponse.Loaded)
{
client.IsReady=true;
Server.API.Events.InvokePlayerReady(client);
}
else
foreach (var s in ClientResources.Values)
{
try
{
Logger?.Warning($"Client {client.Username} failed to load resource.");
s.Close();
s.Dispose();
}
});
}
}
catch (Exception ex)
{
Logger?.Error("[Resources.CloseStream]", ex);
}
}
}
public void SendTo(Client client)
{
Task.Run(() =>
{
try
{
if (ClientResources.Count != 0)
{
Logger?.Info($"Sending resources to client:{client.Username}");
foreach (var rs in ClientResources)
{
Logger?.Debug(rs.Key);
Server.SendFile(rs.Value, rs.Key + ".res", client);
}
Logger?.Info($"Resources sent to:{client.Username}");
}
if (Server.GetResponse<Packets.FileTransferResponse>(client, new Packets.AllResourcesSent())?.Response == FileResponse.Loaded)
{
client.IsReady = true;
Server.API.Events.InvokePlayerReady(client);
}
else
{
Logger?.Warning($"Client {client.Username} failed to load resource.");
}
}
catch (Exception ex)
{
Logger.Error("Failed to send resource to client: " + client.Username, ex);
client.Kick("Resource error!");
}
});
}
}
}

View File

@ -1,14 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA;
using GTA.Math;
using RageCoop.Core;
using RageCoop.Core.Scripting;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Security.Cryptography;
using GTA.Math;
using GTA;
namespace RageCoop.Server.Scripting
{
@ -25,76 +22,36 @@ namespace RageCoop.Server.Scripting
}
internal ConcurrentDictionary<int, ServerPed> Peds { get; set; } = new();
internal ConcurrentDictionary<int, ServerVehicle> Vehicles { get; set; } = new();
internal ConcurrentDictionary<int,ServerProp> ServerProps { get; set; }=new();
internal ConcurrentDictionary<int,ServerBlip> Blips { get; set; } = new();
internal ConcurrentDictionary<int, ServerProp> ServerProps { get; set; } = new();
internal ConcurrentDictionary<int, ServerBlip> Blips { get; set; } = new();
/// <summary>
/// Get a <see cref="ServerPed"/> by it's id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public ServerPed GetPedByID(int id)
{
if(Peds.TryGetValue(id,out var ped))
{
return ped;
}
else
{
return null;
}
}
public ServerPed GetPedByID(int id) => Peds.TryGetValue(id, out var ped) ? ped : null;
/// <summary>
/// Get a <see cref="ServerVehicle"/> by it's id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public ServerVehicle GetVehicleByID(int id)
{
if (Vehicles.TryGetValue(id, out var veh))
{
return veh;
}
else
{
return null;
}
}
public ServerVehicle GetVehicleByID(int id) => Vehicles.TryGetValue(id, out var veh) ? veh : null;
/// <summary>
/// Get a <see cref="ServerProp"/> owned by server from it's ID.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public ServerProp GetPropByID(int id)
{
if (ServerProps.TryGetValue(id, out var obj))
{
return obj;
}
else
{
return null;
}
}
public ServerProp GetPropByID(int id) => ServerProps.TryGetValue(id, out var obj) ? obj : null;
/// <summary>
/// Get a <see cref="ServerBlip"/> by it's id.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public ServerBlip GetBlipByID(int id)
{
if (Blips.TryGetValue(id, out var obj))
{
return obj;
}
else
{
return null;
}
}
public ServerBlip GetBlipByID(int id) => Blips.TryGetValue(id, out var obj) ? obj : null;
/// <summary>
/// Create a static prop owned by server.
@ -103,16 +60,16 @@ namespace RageCoop.Server.Scripting
/// <param name="pos"></param>
/// <param name="rot"></param>
/// <returns></returns>
public ServerProp CreateProp(Model model,Vector3 pos,Vector3 rot)
public ServerProp CreateProp(Model model, Vector3 pos, Vector3 rot)
{
int id = RequestNetworkID();
ServerProp prop;
ServerProps.TryAdd(id,prop=new ServerProp(Server)
ServerProps.TryAdd(id, prop = new ServerProp(Server)
{
ID=id,
Model=model,
_pos=pos,
_rot=rot
ID = id,
Model = model,
_pos = pos,
_rot = rot
});
prop.Update();
return prop;
@ -126,17 +83,17 @@ namespace RageCoop.Server.Scripting
/// <param name="pos">position</param>
/// <param name="heading">heading of this vehicle</param>
/// <returns></returns>
public ServerVehicle CreateVehicle(Client owner,Model model,Vector3 pos,float heading)
public ServerVehicle CreateVehicle(Client owner, Model model, Vector3 pos, float heading)
{
if(owner == null) { throw new ArgumentNullException("Owner cannot be null"); }
if (owner == null) { throw new ArgumentNullException("Owner cannot be null"); }
ServerVehicle veh = new(Server)
{
Owner=owner,
ID=RequestNetworkID(),
Model=model,
_pos= pos,
Owner = owner,
ID = RequestNetworkID(),
Model = model,
_pos = pos,
};
owner.SendCustomEventQueued(CustomEvents.CreateVehicle,veh.ID, model, pos, heading);
owner.SendCustomEventQueued(CustomEvents.CreateVehicle, veh.ID, model, pos, heading);
Vehicles.TryAdd(veh.ID, veh);
return veh;
}
@ -147,15 +104,15 @@ namespace RageCoop.Server.Scripting
/// <param name="pos"></param>
/// <param name="rotation"></param>
/// <returns></returns>
public ServerBlip CreateBlip(Vector3 pos,int rotation)
public ServerBlip CreateBlip(Vector3 pos, int rotation)
{
var b = new ServerBlip(Server)
{
ID=RequestNetworkID(),
Position=pos,
Rotation=rotation
ID = RequestNetworkID(),
Position = pos,
Rotation = rotation
};
Blips.TryAdd(b.ID,b);
Blips.TryAdd(b.ID, b);
b.Update();
return b;
}
@ -164,57 +121,44 @@ namespace RageCoop.Server.Scripting
/// Get all peds on this server
/// </summary>
/// <returns></returns>
public ServerPed[] GetAllPeds()
{
return Peds.Values.ToArray();
}
public ServerPed[] GetAllPeds() => Peds.Values.ToArray();
/// <summary>
/// Get all vehicles on this server
/// </summary>
/// <returns></returns>
public ServerVehicle[] GetAllVehicles()
{
return Vehicles.Values.ToArray();
}
public ServerVehicle[] GetAllVehicles() => Vehicles.Values.ToArray();
/// <summary>
/// Get all static prop objects owned by server
/// </summary>
/// <returns></returns>
public ServerProp[] GetAllProps()
{
return ServerProps.Values.ToArray();
}
public ServerProp[] GetAllProps() => ServerProps.Values.ToArray();
/// <summary>
/// Get all blips owned by server
/// </summary>
/// <returns></returns>
public ServerBlip[] GetAllBlips()
{
return Blips.Values.ToArray();
}
public ServerBlip[] GetAllBlips() => Blips.Values.ToArray();
/// <summary>
/// Not thread safe
/// </summary>
internal void Update(Packets.PedSync p,Client sender)
internal void Update(Packets.PedSync p, Client sender)
{
ServerPed ped;
if(!Peds.TryGetValue(p.ID,out ped))
if (!Peds.TryGetValue(p.ID, out ServerPed ped))
{
Peds.TryAdd(p.ID,ped=new ServerPed(Server));
ped.ID=p.ID;
Peds.TryAdd(p.ID, ped = new ServerPed(Server));
ped.ID = p.ID;
}
ped._pos = p.Position;
ped.Owner=sender;
ped.Health=p.Health;
ped._rot=p.Rotation;
ped.Owner = sender;
ped.Health = p.Health;
ped._rot = p.Rotation;
ped._isInvincible = p.Flags.HasPedFlag(PedDataFlags.IsInvincible);
if (p.Speed>=4 && Vehicles.TryGetValue(p.VehicleID,out var v))
if (p.Speed >= 4 && Vehicles.TryGetValue(p.VehicleID, out var v))
{
ped.LastVehicle=v;
ped.LastVehicle = v;
}
if (ped.Owner != sender)
@ -229,15 +173,14 @@ namespace RageCoop.Server.Scripting
}
internal void Update(Packets.VehicleSync p, Client sender)
{
ServerVehicle veh;
if (!Vehicles.TryGetValue(p.ID, out veh))
if (!Vehicles.TryGetValue(p.ID, out ServerVehicle veh))
{
Vehicles.TryAdd(p.ID, veh=new ServerVehicle(Server));
veh.ID=p.ID;
Vehicles.TryAdd(p.ID, veh = new ServerVehicle(Server));
veh.ID = p.ID;
}
veh._pos = p.Position+p.Velocity*sender.Latency;
veh._quat=p.Quaternion;
if(veh.Owner != sender)
veh._pos = p.Position + p.Velocity * sender.Latency;
veh._quat = p.Quaternion;
if (veh.Owner != sender)
{
if (veh.Owner != null)
{
@ -253,20 +196,20 @@ namespace RageCoop.Server.Scripting
foreach (var pair in Peds)
{
if (pair.Value.Owner==left)
if (pair.Value.Owner == left)
{
Server.QueueJob(()=>Peds.TryRemove(pair.Key,out _));
Server.QueueJob(() => Peds.TryRemove(pair.Key, out _));
}
}
foreach (var pair in Vehicles)
{
if (pair.Value.Owner==left)
if (pair.Value.Owner == left)
{
Server.QueueJob(() => Vehicles.TryRemove(pair.Key, out _));
}
}
// Server.QueueJob(() =>
// Server.Logger?.Trace("Remaining entities: "+(Peds.Count+Vehicles.Count+ServerProps.Count)));
// Server.Logger?.Trace("Remaining entities: "+(Peds.Count+Vehicles.Count+ServerProps.Count)));
}
internal void RemoveVehicle(int id)
{
@ -277,14 +220,8 @@ namespace RageCoop.Server.Scripting
}
}
internal void RemoveProp(int id)
{
ServerProps.TryRemove(id, out _);
}
internal void RemoveServerBlip(int id)
{
Blips.TryRemove(id, out _);
}
internal void RemoveProp(int id) => ServerProps.TryRemove(id, out _);
internal void RemoveServerBlip(int id) => Blips.TryRemove(id, out _);
internal void RemovePed(int id)
{
Peds.TryRemove(id, out var ped);
@ -298,17 +235,16 @@ namespace RageCoop.Server.Scripting
{
if (Peds.ContainsKey(ped.ID))
{
Peds[ped.ID]=ped;
}
else
{
Peds.TryAdd(ped.ID, ped);
Peds[ped.ID] = ped;
return;
}
Peds.TryAdd(ped.ID, ped);
}
internal int RequestNetworkID()
{
int ID = 0;
while ((ID==0)
while ((ID == 0)
|| ServerProps.ContainsKey(ID)
|| Peds.ContainsKey(ID)
|| Vehicles.ContainsKey(ID)

View File

@ -1,14 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using GTA;
using GTA.Native;
using GTA;
using GTA.Math;
using GTA.Native;
using RageCoop.Core;
using RageCoop.Core.Scripting;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace RageCoop.Server.Scripting
{
@ -22,7 +19,7 @@ namespace RageCoop.Server.Scripting
/// Server that this object belongs to
/// </summary>
internal readonly Server Server;
internal ServerObject(Server server) { Server=server; }
internal ServerObject(Server server) { Server = server; }
/// <summary>
/// Pass this as an argument in CustomEvent or NativeCall to convert this object to handle at client side.
@ -70,8 +67,8 @@ namespace RageCoop.Server.Scripting
/// </summary>
public virtual Vector3 Position
{
get { return _pos; }
set { _pos=value; Owner.SendNativeCall(Hash.SET_ENTITY_COORDS_NO_OFFSET, Handle, value.X, value.Y, value.Z,1, 1,1 ); }
get => _pos;
set { _pos = value; Owner.SendNativeCall(Hash.SET_ENTITY_COORDS_NO_OFFSET, Handle, value.X, value.Y, value.Z, 1, 1, 1); }
}
internal Vector3 _pos;
@ -80,8 +77,8 @@ namespace RageCoop.Server.Scripting
/// </summary>
public virtual Vector3 Rotation
{
get { return _rot; }
set { _rot=value; Owner.SendNativeCall(Hash.SET_ENTITY_ROTATION, Handle, value.X, value.Y, value.Z ,2,1); }
get => _rot;
set { _rot = value; Owner.SendNativeCall(Hash.SET_ENTITY_ROTATION, Handle, value.X, value.Y, value.Z, 2, 1); }
}
internal Vector3 _rot;
@ -105,7 +102,7 @@ namespace RageCoop.Server.Scripting
/// <exception cref="InvalidOperationException"></exception>
public virtual void Freeze(bool toggle)
{
if (GetTypeByte()==50)
if (GetTypeByte() == 50)
{
throw new InvalidOperationException("Can't freeze or unfreeze static server object");
}
@ -128,7 +125,7 @@ namespace RageCoop.Server.Scripting
/// </summary>
public override void Delete()
{
Server.API.SendCustomEventQueued(null,CustomEvents.DeleteServerProp,ID);
Server.API.SendCustomEventQueued(null, CustomEvents.DeleteServerProp, ID);
Server.API.Entities.RemoveProp(ID);
}
@ -137,8 +134,8 @@ namespace RageCoop.Server.Scripting
/// </summary>
public override Vector3 Position
{
get { return _pos; }
set { _pos=value; Server.API.SendNativeCall(null, Hash.SET_ENTITY_COORDS_NO_OFFSET, Handle, value.X, value.Y, value.Z, 1, 1, 1); }
get => _pos;
set { _pos = value; Server.API.SendNativeCall(null, Hash.SET_ENTITY_COORDS_NO_OFFSET, Handle, value.X, value.Y, value.Z, 1, 1, 1); }
}
/// <summary>
@ -146,8 +143,8 @@ namespace RageCoop.Server.Scripting
/// </summary>
public override Vector3 Rotation
{
get { return _rot; }
set { _rot=value; Server.API.SendNativeCall(null, Hash.SET_ENTITY_ROTATION, Handle, value.X, value.Y, value.Z, 2, 1); }
get => _rot;
set { _rot = value; Server.API.SendNativeCall(null, Hash.SET_ENTITY_ROTATION, Handle, value.X, value.Y, value.Z, 2, 1); }
}
@ -156,7 +153,7 @@ namespace RageCoop.Server.Scripting
/// </summary>
internal void Update()
{
Server.API.Server.BaseScript.SendServerPropsTo(new() { this });
Server.API.Server.BaseScript.SendServerPropsTo(new() { this });
}
}
@ -198,9 +195,10 @@ namespace RageCoop.Server.Scripting
/// <summary>
/// Get or set whether this ped is invincible
/// </summary>
public bool IsInvincible {
public bool IsInvincible
{
get => _isInvincible;
set => Owner.SendNativeCall(Hash.SET_ENTITY_INVINCIBLE,Handle,value);
set => Owner.SendNativeCall(Hash.SET_ENTITY_INVINCIBLE, Handle, value);
}
}
/// <summary>
@ -215,8 +213,8 @@ namespace RageCoop.Server.Scripting
/// </summary>
public override Vector3 Rotation
{
get { return _quat.ToEulerAngles().ToDegree(); }
set { Owner.SendNativeCall(Hash.SET_ENTITY_ROTATION, Handle ,value.X, value.Y ,value.Z); }
get => _quat.ToEulerAngles().ToDegree();
set { Owner.SendNativeCall(Hash.SET_ENTITY_ROTATION, Handle, value.X, value.Y, value.Z); }
}
internal Quaternion _quat;
@ -225,8 +223,8 @@ namespace RageCoop.Server.Scripting
/// </summary>
public Quaternion Quaternion
{
get { return _quat; }
set { _quat = value ;Owner.SendNativeCall(Hash.SET_ENTITY_QUATERNION, Handle, value.X, value.Y, value.Z, value.W); }
get => _quat;
set { _quat = value; Owner.SendNativeCall(Hash.SET_ENTITY_QUATERNION, Handle, value.X, value.Y, value.Z, value.W); }
}
}
@ -263,28 +261,30 @@ namespace RageCoop.Server.Scripting
/// <summary>
/// Color of this blip
/// </summary>
public BlipColor Color {
get { return _color; }
set { _color=value; Update(); }
public BlipColor Color
{
get => _color;
set { _color = value; Update(); }
}
internal BlipSprite _sprite=BlipSprite.Standard;
internal BlipSprite _sprite = BlipSprite.Standard;
/// <summary>
/// Sprite of this blip
/// </summary>
public BlipSprite Sprite {
get { return _sprite; }
set { _sprite=value; Update();}
public BlipSprite Sprite
{
get => _sprite;
set { _sprite = value; Update(); }
}
internal float _scale =1;
internal float _scale = 1;
/// <summary>
/// Scale of this blip
/// </summary>
public float Scale
{
get { return _scale; }
set { _scale=value;Update(); }
get => _scale;
set { _scale = value; Update(); }
}
internal Vector3 _pos = new();
@ -293,8 +293,8 @@ namespace RageCoop.Server.Scripting
/// </summary>
public Vector3 Position
{
get { return _pos; }
set { _pos=value; Update(); }
get => _pos;
set { _pos = value; Update(); }
}
internal int _rot;
@ -303,18 +303,18 @@ namespace RageCoop.Server.Scripting
/// </summary>
public int Rotation
{
get { return _rot; }
set { _rot=value; Update(); }
get => _rot;
set { _rot = value; Update(); }
}
internal string _name="Beeeeeee";
internal string _name = "Beeeeeee";
/// <summary>
/// Name of this blip
/// </summary>
public string Name
{
get { return _name;}
set { _name=value; Update(); }
get => _name;
set { _name = value; Update(); }
}
/// <summary>
@ -322,23 +322,23 @@ namespace RageCoop.Server.Scripting
/// </summary>
public void Delete()
{
Server.API.SendCustomEventQueued(null, CustomEvents.DeleteServerBlip,ID);
Server.API.SendCustomEventQueued(null, CustomEvents.DeleteServerBlip, ID);
Server.Entities.RemoveServerBlip(ID);
}
private bool _bouncing=false;
private bool _bouncing = false;
internal void Update()
{
// 5ms debounce
if (!_bouncing)
{
_bouncing=true;
_bouncing = true;
Task.Run(() =>
{
Thread.Sleep(5);
DoUpdate();
_bouncing=false;
_bouncing = false;
});
}
}
@ -359,7 +359,7 @@ namespace RageCoop.Server.Scripting
/// <summary>
/// Get the <see cref="ServerPed"/> that this blip attached to.
/// </summary>
public ServerPed Ped { get;internal set; }
public ServerPed Ped { get; internal set; }
internal PedBlip(ServerPed ped)
{
Ped = ped;
@ -372,18 +372,18 @@ namespace RageCoop.Server.Scripting
/// </summary>
public BlipColor Color
{
get { return _color; }
set { _color=value; Update(); }
get => _color;
set { _color = value; Update(); }
}
internal BlipSprite _sprite=BlipSprite.Standard;
internal BlipSprite _sprite = BlipSprite.Standard;
/// <summary>
/// Sprite of this blip
/// </summary>
public BlipSprite Sprite
{
get { return _sprite; }
set { _sprite=value; Update(); }
get => _sprite;
set { _sprite = value; Update(); }
}
internal float _scale = 1;
@ -392,8 +392,8 @@ namespace RageCoop.Server.Scripting
/// </summary>
public float Scale
{
get { return _scale; }
set { _scale=value; Update(); }
get => _scale;
set { _scale = value; Update(); }
}
private bool _bouncing = false;
@ -402,18 +402,18 @@ namespace RageCoop.Server.Scripting
// 5ms debounce
if (!_bouncing)
{
_bouncing=true;
_bouncing = true;
Task.Run(() =>
{
Thread.Sleep(5);
DoUpdate();
_bouncing=false;
_bouncing = false;
});
}
}
private void DoUpdate()
{
Ped.Owner.SendCustomEventQueued(CustomEvents.UpdatePedBlip,Ped.Handle,(byte)Color,(ushort)Sprite,Scale);
Ped.Owner.SendCustomEventQueued(CustomEvents.UpdatePedBlip, Ped.Handle, (byte)Color, (ushort)Sprite, Scale);
}
}

View File

@ -1,214 +1,235 @@
using System;
using System.Collections.Generic;
using System.Linq;
using RageCoop.Core;
using System.Reflection;
using ICSharpCode.SharpZipLib.Zip;
using McMaster.NETCore.Plugins;
using System.IO;
using RageCoop.Core;
using RageCoop.Core.Scripting;
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
namespace RageCoop.Server.Scripting
{
/// <summary>
/// A class representing a server side resource, each resource is isolated from another and will be started alongside the server.
/// </summary>
public class ServerResource : PluginLoader
{
/// <summary>
/// A class representing a server side resource, each resource is isolated from another and will be started alongside the server.
/// </summary>
public class ServerResource : PluginLoader
{
internal ServerResource(PluginConfig config) : base(config) { }
internal static ServerResource LoadFrom(string resDir, string dataFolder, Logger logger = null, bool isTemp = false)
{
var conf = new PluginConfig(Path.GetFullPath(Path.Combine(resDir, Path.GetFileName(resDir)+".dll")))
{
PreferSharedTypes = true,
EnableHotReload=false,
IsUnloadable=false,
LoadInMemory=true,
};
ServerResource r = new(conf);
r.Logger= logger;
r.Name=Path.GetFileName(resDir);
if (!File.Exists(conf.MainAssemblyPath))
{
r.Dispose();
throw new FileNotFoundException($"Main assembly for resource \"{r.Name}\" cannot be found.");
}
r.Scripts = new();
r.DataFolder=Path.Combine(dataFolder, r.Name);
r.Reloaded+=(s, e) => { r.Logger?.Info($"Resource: {r.Name} has been reloaded"); };
Directory.CreateDirectory(r.DataFolder);
foreach (var dir in Directory.GetDirectories(resDir, "*", SearchOption.AllDirectories))
{
r.Files.Add(dir, new ResourceFile()
{
IsDirectory=true,
Name=dir.Substring(resDir.Length+1).Replace('\\','/')
});;
}
var assemblies=new Dictionary<ResourceFile,Assembly>();
foreach (var file in Directory.GetFiles(resDir, "*", SearchOption.AllDirectories))
{
if (Path.GetFileName(file).CanBeIgnored()) { try { File.Delete(file); } catch { } continue; }
var relativeName = file.Substring(resDir.Length+1).Replace('\\', '/');
var rfile = new ResourceFile()
{
GetStream=() => { return new FileStream(file, FileMode.Open, FileAccess.Read); },
IsDirectory=false,
Name=relativeName
};
if (file.EndsWith(".dll") && !relativeName.Contains('/') && IsManagedAssembly(file))
{
assemblies.Add(rfile, r.LoadAssemblyFromPath(Path.GetFullPath(file)));
}
r.Files.Add(relativeName, rfile);
}
foreach(var a in assemblies)
internal ServerResource(PluginConfig config) : base(config) { }
internal static ServerResource LoadFrom(string resDir, string dataFolder, Logger logger = null)
{
var runtimeLibs = Path.Combine(resDir, "RuntimeLibs", CoreUtils.GetInvariantRID());
if (Directory.Exists(runtimeLibs))
{
try
{
r.LoadScriptsFromAssembly(a.Key,a.Value);
}
catch (FileLoadException ex)
{
if (!ex.Message.EndsWith("Assembly with same name is already loaded"))
{
logger?.Warning("Failed to load assembly: "+a.Key.Name);
logger?.Trace(ex.Message);
}
}
}
return r;
}
internal static ServerResource LoadFrom(Stream input,string name, string tmpDir, string dataFolder, Logger logger = null)
{
tmpDir=Path.Combine(tmpDir, name);
new FastZip().ExtractZip(input, tmpDir, FastZip.Overwrite.Always,null,null,null,true,true);
return LoadFrom(tmpDir, dataFolder, logger, true);
}
/// <summary>
/// Name of the resource
/// </summary>
public string Name { get; internal set; }
/// <summary>
/// A resource-specific folder that can be used to store your files.
/// </summary>
public string DataFolder { get; internal set; }
/// <summary>
/// Get all <see cref="ServerScript"/> instance in this resource
/// </summary>
public Dictionary<string,ServerScript> Scripts { get; internal set; } = new();
/// <summary>
/// Get all <see cref="ResourceFile"/> that can be used to acces files in this resource
/// </summary>
public Dictionary<string, ResourceFile> Files { get; internal set; } = new Dictionary<string, ResourceFile>();
/// <summary>
/// Get a <see cref="Logger"/> instance that can be used to show information in console.
/// </summary>
public Logger Logger;
private bool LoadScriptsFromAssembly(ResourceFile rfile, Assembly assembly)
{
int count = 0;
logger?.Debug("Applying runtime libraries from " + CoreUtils.GetInvariantRID());
CoreUtils.CopyFilesRecursively(new(runtimeLibs), new(resDir));
}
try
{
// Find all script types in the assembly
foreach (var type in assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(ServerScript))))
{
ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
if (constructor != null && constructor.IsPublic)
{
try
{
// Invoke script constructor
var script = constructor.Invoke(null) as ServerScript;
script.CurrentResource = this;
script.CurrentFile=rfile;
Scripts.Add(script.GetType().FullName,script);
count++;
}
catch (Exception ex)
{
Logger?.Error($"Error occurred when loading script: {type.FullName}.");
Logger?.Error(ex);
}
}
else
{
Logger?.Error($"Script {type.FullName} has an invalid contructor.");
}
}
}
catch (ReflectionTypeLoadException ex)
{
Logger?.Error($"Failed to load assembly {rfile.Name}: ");
Logger?.Error(ex);
foreach (var e in ex.LoaderExceptions)
{
Logger?.Error(e);
}
return false;
}
if(count != 0)
runtimeLibs = Path.Combine(resDir, "RuntimeLibs", RuntimeInformation.RuntimeIdentifier);
if (Directory.Exists(runtimeLibs))
{
Logger?.Info($"Loaded {count} script(s) in {rfile.Name}");
}
return count != 0;
}
logger?.Debug("Applying runtime libraries from " + CoreUtils.GetInvariantRID());
CoreUtils.CopyFilesRecursively(new(runtimeLibs), new(resDir));
}
internal new void Dispose()
{
base.Dispose();
}
private static bool IsManagedAssembly(string filename)
{
try
{
using (Stream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
if (file.Length < 64)
return false;
var conf = new PluginConfig(Path.GetFullPath(Path.Combine(resDir, Path.GetFileName(resDir) + ".dll")))
{
PreferSharedTypes = true,
EnableHotReload = false,
IsUnloadable = false,
LoadInMemory = true,
};
ServerResource r = new(conf);
r.Logger = logger;
r.Name = Path.GetFileName(resDir);
if (!File.Exists(conf.MainAssemblyPath))
{
r.Dispose();
throw new FileNotFoundException($"Main assembly for resource \"{r.Name}\" cannot be found.");
}
r.Scripts = new();
r.DataFolder = Path.Combine(dataFolder, r.Name);
r.Reloaded += (s, e) => { r.Logger?.Info($"Resource: {r.Name} has been reloaded"); };
using (BinaryReader bin = new BinaryReader(file))
{
// PE header starts at offset 0x3C (60). Its a 4 byte header.
file.Position = 0x3C;
uint offset = bin.ReadUInt32();
if (offset == 0)
offset = 0x80;
Directory.CreateDirectory(r.DataFolder);
foreach (var dir in Directory.GetDirectories(resDir, "*", SearchOption.AllDirectories))
{
r.Files.Add(dir, new ResourceFile()
{
IsDirectory = true,
Name = dir.Substring(resDir.Length + 1).Replace('\\', '/')
}); ;
}
var assemblies = new Dictionary<ResourceFile, Assembly>();
foreach (var file in Directory.GetFiles(resDir, "*", SearchOption.AllDirectories))
{
if (Path.GetFileName(file).CanBeIgnored()) { try { File.Delete(file); } catch { } continue; }
var relativeName = file.Substring(resDir.Length + 1).Replace('\\', '/');
var rfile = new ResourceFile()
{
GetStream = () => { return new FileStream(file, FileMode.Open, FileAccess.Read); },
IsDirectory = false,
Name = relativeName
};
if (file.EndsWith(".dll") && !relativeName.Contains('/') && IsManagedAssembly(file))
{
assemblies.Add(rfile, r.LoadAssemblyFromPath(Path.GetFullPath(file)));
}
r.Files.Add(relativeName, rfile);
}
foreach (var a in assemblies)
{
if (a.Key.Name.ToLower() == r.Name.ToLower() + ".dll")
{
// Ensure there is at least enough room for the following structures:
// 24 byte PE Signature & Header
// 28 byte Standard Fields (24 bytes for PE32+)
// 68 byte NT Fields (88 bytes for PE32+)
// >= 128 byte Data Dictionary Table
if (offset > file.Length - 256)
return false;
try
{
r.LoadScriptsFromAssembly(a.Key, a.Value);
}
catch (FileLoadException ex)
{
if (!ex.Message.EndsWith("Assembly with same name is already loaded"))
{
logger?.Warning("Failed to load assembly: " + a.Key.Name);
logger?.Trace(ex.Message);
}
}
}
}
return r;
}
internal static ServerResource LoadFrom(Stream input, string name, string tmpDir, string dataFolder, Logger logger = null)
{
tmpDir = Path.Combine(tmpDir, name);
if (Directory.Exists(tmpDir)) { Directory.Delete(tmpDir, true); }
Directory.CreateDirectory(tmpDir);
new FastZip().ExtractZip(input, tmpDir, FastZip.Overwrite.Always, null, null, null, true, true);
return LoadFrom(tmpDir, dataFolder, logger);
}
/// <summary>
/// Name of the resource
/// </summary>
public string Name { get; internal set; }
/// <summary>
/// A resource-specific folder that can be used to store your files.
/// </summary>
public string DataFolder { get; internal set; }
/// <summary>
/// Get all <see cref="ServerScript"/> instance in this resource
/// </summary>
public Dictionary<string, ServerScript> Scripts { get; internal set; } = new();
/// <summary>
/// Get all <see cref="ResourceFile"/> that can be used to acces files in this resource
/// </summary>
public Dictionary<string, ResourceFile> Files { get; internal set; } = new Dictionary<string, ResourceFile>();
/// <summary>
/// Get a <see cref="Logger"/> instance that can be used to show information in console.
/// </summary>
public Logger Logger;
private bool LoadScriptsFromAssembly(ResourceFile rfile, Assembly assembly)
{
int count = 0;
// Check the PE signature. Should equal 'PE\0\0'.
file.Position = offset;
if (bin.ReadUInt32() != 0x00004550)
return false;
try
{
// Find all script types in the assembly
foreach (var type in assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(ServerScript))))
{
ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
if (constructor != null && constructor.IsPublic)
{
try
{
// Invoke script constructor
var script = constructor.Invoke(null) as ServerScript;
script.CurrentResource = this;
script.CurrentFile = rfile;
Scripts.Add(script.GetType().FullName, script);
count++;
}
catch (Exception ex)
{
Logger?.Error($"Error occurred when loading script: {type.FullName}.");
Logger?.Error(ex);
}
}
else
{
Logger?.Error($"Script {type.FullName} has an invalid contructor.");
}
}
}
catch (ReflectionTypeLoadException ex)
{
Logger?.Error($"Failed to load assembly {rfile.Name}: ");
Logger?.Error(ex);
foreach (var e in ex.LoaderExceptions)
{
Logger?.Error(e);
}
return false;
}
if (count != 0)
{
Logger?.Info($"Loaded {count} script(s) in {rfile.Name}");
}
return count != 0;
}
// Read PE magic number from Standard Fields to determine format.
file.Position += 20;
var peFormat = bin.ReadUInt16();
if (peFormat != 0x10b /* PE32 */ && peFormat != 0x20b /* PE32Plus */)
return false;
internal new void Dispose()
{
base.Dispose();
}
private static bool IsManagedAssembly(string filename)
{
try
{
using (Stream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
if (file.Length < 64)
return false;
// Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
// When this is non-zero then the file contains CLI data otherwise not.
file.Position = offset + (peFormat == 0x10b ? 232 : 248);
return bin.ReadUInt32() != 0;
}
}
}
catch
{
// This is likely not a valid assembly if any IO exceptions occur during reading
return false;
}
}
}
using (BinaryReader bin = new BinaryReader(file))
{
// PE header starts at offset 0x3C (60). Its a 4 byte header.
file.Position = 0x3C;
uint offset = bin.ReadUInt32();
if (offset == 0)
offset = 0x80;
// Ensure there is at least enough room for the following structures:
// 24 byte PE Signature & Header
// 28 byte Standard Fields (24 bytes for PE32+)
// 68 byte NT Fields (88 bytes for PE32+)
// >= 128 byte Data Dictionary Table
if (offset > file.Length - 256)
return false;
// Check the PE signature. Should equal 'PE\0\0'.
file.Position = offset;
if (bin.ReadUInt32() != 0x00004550)
return false;
// Read PE magic number from Standard Fields to determine format.
file.Position += 20;
var peFormat = bin.ReadUInt16();
if (peFormat != 0x10b /* PE32 */ && peFormat != 0x20b /* PE32Plus */)
return false;
// Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
// When this is non-zero then the file contains CLI data otherwise not.
file.Position = offset + (peFormat == 0x10b ? 232 : 248);
return bin.ReadUInt32() != 0;
}
}
}
catch
{
// This is likely not a valid assembly if any IO exceptions occur during reading
return false;
}
}
}
}

View File

@ -1,5 +1,5 @@
using System;
using RageCoop.Core.Scripting;
using RageCoop.Core.Scripting;
using System;
namespace RageCoop.Server.Scripting
{
@ -35,7 +35,7 @@ namespace RageCoop.Server.Scripting
/// <summary>
/// Eqivalent of <see cref="ServerResource.Logger"/> in <see cref="CurrentResource"/>
/// </summary>
public Core.Logger Logger { get { return CurrentResource.Logger; } }
public Core.Logger Logger => CurrentResource.Logger;
}
/// <summary>
/// Decorate your method with this attribute and use <see cref="API.RegisterCommands{T}"/> or <see cref="API.RegisterCommands(object)"/> to register commands.

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