59 Commits

Author SHA1 Message Date
564d1467f6 Merge pull request #57 from RAGECOOP/dev-nightly
Dev nightly
2023-11-20 13:44:47 -03:00
8bd6ea15a3 Remove global limits
world limits will be applied to all players instead
Fix explosions when remote and local vehicles exist at same position
Fix "floating corpses" issue when remote NPCs are killed
2023-11-20 11:32:18 -03:00
3c7f16f7a4 Add ped limit menu setting
Fix vehicle limit menu setting
Fix player blip disappearing after switching character
2023-11-12 10:50:37 -03:00
393a401860 Always sync vehicles with synced peds 2023-11-07 20:27:14 -03:00
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 3422 additions and 3613 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());
}
}
@ -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()
{
Memory.ApplyPatches();
if (Settings.Voice && !Voice.WasInitialized())
{
Voice.Init();
}
QueueAction(() =>
{
MainChat.Clear();
Voice.ClearAll();
EntityPool.Cleanup();
PlayerList.Cleanup();
LocalPlayerID=default;
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();
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,38 @@ 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());
private static readonly NativeItem _pedSoftLimit = new NativeItem("Ped limit (soft)", "The game won't spawn more NPCs if the limit is exceeded. \n-1 for unlimited (not recommended).", Main.Settings.WorldPedSoftLimit.ToString());
static SettingsMenu()
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
Menu.BannerText.Color = Color.FromArgb(255, 165, 0);
_disableTrafficItem.CheckboxChanged += DisableTrafficCheckboxChanged;
_disablePauseAlt.CheckboxChanged+= DisablePauseAltCheckboxChanged;
_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;
_pedSoftLimit.Activated += PedSoftLimitActivated;
_showBlip.Activated += (s, e) =>
{
Main.Settings.ShowPlayerBlip = _showBlip.Checked;
Util.SaveSettings();
};
_showNametag.Activated += (s, e) =>
{
Main.Settings.ShowPlayerNameTag = _showNametag.Checked;
Util.SaveSettings();
};
Menu.Add(_disableTrafficItem);
Menu.Add(_disablePauseAlt);
@ -43,6 +57,9 @@ namespace RageCoop.Client.Menus
Menu.Add(_menuKey);
Menu.Add(_passengerKey);
Menu.Add(_vehicleSoftLimit);
Menu.Add(_pedSoftLimit);
Menu.Add(_showBlip);
Menu.Add(_showNametag);
}
private static void DisableVoiceCheckboxChanged(object sender, EventArgs e)
@ -53,7 +70,9 @@ namespace RageCoop.Client.Menus
{
Voice.Init();
}
} else {
}
else
{
Voice.ClearAll();
}
@ -63,17 +82,29 @@ 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();
_vehicleSoftLimit.AltTitle = Main.Settings.WorldVehicleSoftLimit.ToString();
Util.SaveSettings();
}
catch { }
}
private static void PedSoftLimitActivated(object sender, EventArgs e)
{
try
{
Main.Settings.WorldPedSoftLimit = int.Parse(
Game.GetUserInput(WindowTitle.EnterMessage20,
Main.Settings.WorldPedSoftLimit.ToString(), 20));
_pedSoftLimit.AltTitle = Main.Settings.WorldPedSoftLimit.ToString();
Util.SaveSettings();
}
catch { }
@ -82,11 +113,11 @@ namespace RageCoop.Client.Menus
{
try
{
Main.Settings.MenuKey =(Keys)Enum.Parse(
Main.Settings.MenuKey = (Keys)Enum.Parse(
typeof(Keys),
Game.GetUserInput(WindowTitle.EnterMessage20,
Main.Settings.MenuKey.ToString(), 20));
_menuKey.AltTitle=Main.Settings.MenuKey.ToString();
_menuKey.AltTitle = Main.Settings.MenuKey.ToString();
Util.SaveSettings();
}
catch { }
@ -96,11 +127,11 @@ namespace RageCoop.Client.Menus
{
try
{
Main.Settings.PassengerKey =(Keys)Enum.Parse(
Main.Settings.PassengerKey = (Keys)Enum.Parse(
typeof(Keys),
Game.GetUserInput(WindowTitle.EnterMessage20,
Main.Settings.PassengerKey.ToString(), 20));
_passengerKey.AltTitle=Main.Settings.PassengerKey.ToString();
_passengerKey.AltTitle = Main.Settings.PassengerKey.ToString();
Util.SaveSettings();
}
catch { }

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,35 +80,44 @@ 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)
{
Menus.CoopMenu._serverConnectItem.Enabled=true;
if (!GetServerPublicKey(ip[0], int.Parse(ip[1])))
{
Menus.CoopMenu._serverConnectItem.Enabled = true;
throw new TimeoutException("Failed to retrive server's public key");
}
}
else{
Security.SetServerPublicKey(publicKey.Modulus,publicKey.Exponent);
else
{
Security.SetServerPublicKey(publicKey.Modulus, publicKey.Exponent);
}
// Send handshake packet
@ -114,9 +125,9 @@ namespace RageCoop.Client
var handshake = new Packets.Handshake()
{
PedID = Main.LocalPlayerID,
Username =username,
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,8 @@ using Lidgren.Network;
using RageCoop.Client.Menus;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using GTA.Native;
namespace RageCoop.Client
{
@ -15,7 +14,7 @@ namespace RageCoop.Client
/// <summary>
/// Reduce GC pressure by reusing frequently used packets
/// </summary>
static class ReceivedPackets
private static class ReceivedPackets
{
public static Packets.PedSync PedPacket = new Packets.PedSync();
public static Packets.VehicleSync VehicelPacket = new Packets.VehicleSync();
@ -25,7 +24,7 @@ namespace RageCoop.Client
/// <summary>
/// Used to reslove entity handle in a <see cref="Packets.CustomEvent"/>
/// </summary>
private static readonly Func<byte, BitReader, object> _resolveHandle = (t, reader) =>
private static readonly Func<byte, NetIncomingMessage, object> _resolveHandle = (t, reader) =>
{
switch (t)
{
@ -38,14 +37,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 +54,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 +94,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 +116,7 @@ namespace RageCoop.Client
int id = message.ReadInt32();
if (PendingResponses.TryGetValue(id, out var callback))
{
callback((PacketType)message.ReadByte(), message.ReadBytes(message.ReadInt32()));
callback((PacketType)message.ReadByte(), message);
PendingResponses.Remove(id);
}
break;
@ -151,57 +125,60 @@ namespace RageCoop.Client
{
int id = message.ReadInt32();
var realType = (PacketType)message.ReadByte();
int len = message.ReadInt32();
if (RequestHandlers.TryGetValue(realType, out var handler))
{
var response = Peer.CreateMessage();
response.Write((byte)PacketType.Response);
response.Write(id);
handler(message.ReadBytes(len)).Pack(response);
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 +195,42 @@ namespace RageCoop.Client
default:
break;
}
if (_recycle)
{
Peer.Recycle(message);
}
private static void HandlePacket(PacketType packetType, byte[] data, NetConnection senderConnection)
}
private static void HandlePacket(PacketType packetType, NetIncomingMessage msg, NetConnection senderConnection, ref bool recycle)
{
switch (packetType)
{
case PacketType.HolePunchInit:
HolePunch.Add(data.GetPacket<Packets.HolePunchInit>());
HolePunch.Add(msg.GetPacket<Packets.HolePunchInit>());
break;
case PacketType.PlayerConnect:
PlayerConnect(data.GetPacket<Packets.PlayerConnect>());
PlayerConnect(msg.GetPacket<Packets.PlayerConnect>());
break;
case PacketType.PlayerDisconnect:
PlayerDisconnect(data.GetPacket<Packets.PlayerDisconnect>());
PlayerDisconnect(msg.GetPacket<Packets.PlayerDisconnect>());
break;
case PacketType.PlayerInfoUpdate:
PlayerList.UpdatePlayer(data.GetPacket<Packets.PlayerInfoUpdate>());
PlayerList.UpdatePlayer(msg.GetPacket<Packets.PlayerInfoUpdate>());
break;
case PacketType.VehicleSync:
ReceivedPackets.VehicelPacket.Deserialize(data);
ReceivedPackets.VehicelPacket.Deserialize(msg);
VehicleSync(ReceivedPackets.VehicelPacket);
break;
case PacketType.PedSync:
ReceivedPackets.PedPacket.Deserialize(data);
ReceivedPackets.PedPacket.Deserialize(msg);
PedSync(ReceivedPackets.PedPacket);
break;
case PacketType.ProjectileSync:
ReceivedPackets.ProjectilePacket.Deserialize(data);
ReceivedPackets.ProjectilePacket.Deserialize(msg);
ProjectileSync(ReceivedPackets.ProjectilePacket);
break;
@ -260,7 +238,7 @@ namespace RageCoop.Client
{
Packets.ChatMessage packet = new Packets.ChatMessage((b) => Security.Decrypt(b));
packet.Deserialize(data);
packet.Deserialize(msg);
Main.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message); return true; });
}
@ -271,7 +249,7 @@ namespace RageCoop.Client
if (Main.Settings.Voice)
{
Packets.Voice packet = new Packets.Voice();
packet.Deserialize(data);
packet.Deserialize(msg);
SyncedPed player = EntityPool.GetPedByID(packet.ID);
@ -286,18 +264,20 @@ namespace RageCoop.Client
case PacketType.CustomEvent:
{
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
packet.Deserialize(data);
packet.Deserialize(msg);
Scripting.API.Events.InvokeCustomEventReceived(packet);
}
break;
case PacketType.CustomEventQueued:
{
recycle = false;
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
Main.QueueAction(() =>
{
packet.Deserialize(data);
packet.Deserialize(msg);
Scripting.API.Events.InvokeCustomEventReceived(packet);
Peer.Recycle(msg);
});
}
break;
@ -305,7 +285,7 @@ namespace RageCoop.Client
case PacketType.FileTransferChunk:
{
Packets.FileTransferChunk packet = new Packets.FileTransferChunk();
packet.Deserialize(data);
packet.Deserialize(msg);
DownloadManager.Write(packet.ID, packet.FileChunk);
}
break;
@ -313,8 +293,9 @@ namespace RageCoop.Client
default:
if (packetType.IsSyncEvent())
{
recycle = false;
// Dispatch to script thread
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, data); return true; });
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, msg); return true; });
}
break;
}
@ -323,32 +304,36 @@ namespace RageCoop.Client
private static void PedSync(Packets.PedSync packet)
{
SyncedPed c = EntityPool.GetPedByID(packet.ID);
if (c==null)
if (c == null)
{
if (EntityPool.PedsByID.Count(x => x.Value.OwnerID == packet.OwnerID) < Main.Settings.WorldPedSoftLimit / PlayerList.Players.Count ||
EntityPool.VehiclesByID.Any(x => x.Value.Position.DistanceTo(packet.Position) < 2) || packet.ID == packet.OwnerID)
{
// Main.Logger.Debug($"Creating character for incoming sync:{packet.ID}");
EntityPool.ThreadSafe.Add(c=new SyncedPed(packet.ID));
EntityPool.ThreadSafe.Add(c = new SyncedPed(packet.ID));
}
PedDataFlags flags = packet.Flags;
c.ID=packet.ID;
c.OwnerID=packet.OwnerID;
else return;
}
c.ID = packet.ID;
c.OwnerID = packet.OwnerID;
c.Health = packet.Health;
c.Rotation = packet.Rotation;
c.Velocity = packet.Velocity;
c.Speed = packet.Speed;
c.Flags=packet.Flags;
c.Heading=packet.Heading;
c.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;
if (c.IsAiming)
@ -358,13 +343,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 +357,64 @@ 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.VehiclesByID.Count(x => x.Value.OwnerID == packet.OwnerID) < Main.Settings.WorldVehicleSoftLimit / PlayerList.Players.Count ||
EntityPool.PedsByID.Any(x => x.Value.VehicleID == packet.ID || x.Value.Position.DistanceTo(packet.Position) < 2))
{
// Main.Logger.Debug($"Creating vehicle for incoming sync:{packet.ID}");
EntityPool.ThreadSafe.Add(v = new SyncedVehicle(packet.ID));
}
else return;
}
if (v.IsLocal) { return; }
v.ID= packet.ID;
v.OwnerID= packet.OwnerID;
v.Flags=packet.Flags;
v.Position=packet.Position;
v.Quaternion=packet.Quaternion;
v.SteeringAngle=packet.SteeringAngle;
v.ThrottlePower=packet.ThrottlePower;
v.BrakePower=packet.BrakePower;
v.Velocity=packet.Velocity;
v.RotationVelocity=packet.RotationVelocity;
v.DeluxoWingRatio=packet.DeluxoWingRatio;
v.LastSynced=Main.Ticked;
v.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));
EntityPool.ThreadSafe.Add(p = new SyncedProjectile(packet.ID));
}
p.Flags=packet.Flags;
p.Position=packet.Position;
p.Rotation=packet.Rotation;
p.Velocity=packet.Velocity;
p.WeaponHash=(WeaponHash)packet.WeaponHash;
p.Shooter= packet.Flags.HasProjDataFlag(ProjectileDataFlags.IsShotByVehicle) ?
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.7")]
[assembly: AssemblyFileVersion("1.5.4.7")]
[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]);
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,7 @@ namespace RageCoop.Client
/// The game won't spawn more NPC traffic if the limit is exceeded. -1 for unlimited (not recommended).
/// </summary>
public int WorldPedSoftLimit { get; set; } = 30;
/// <summary>
/// The directory where log and resources downloaded from server will be placed.
/// </summary>
@ -76,5 +77,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,19 @@ namespace RageCoop.Client
}
}
if (Speed>=4)
if (!IsPlayer && Health <= 0 && !MainPed.IsDead)
{
MainPed.Kill();
return;
}
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 +172,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 +186,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();
}
}
@ -274,7 +211,7 @@ namespace RageCoop.Client
MainPed = null;
}
if (PedBlip != null && PedBlip.Exists())
if (PedBlip != null)
{
PedBlip.Delete();
PedBlip = null;
@ -293,19 +230,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 +258,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 +274,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 +426,7 @@ namespace RageCoop.Client
}
_lastIsJumping = false;
if (IsRagdoll || Health==0)
if (IsRagdoll || (IsPlayer && Health == 0))
{
if (!MainPed.IsRagdoll)
{
@ -502,15 +436,13 @@ namespace RageCoop.Client
if (!_lastRagdoll)
{
_lastRagdoll = true;
_lastRagdollTime=Main.Ticked;
_lastRagdollTime = Main.Ticked;
}
return;
}
else
{
if (MainPed.IsRagdoll)
{
if (Speed==0)
if (Speed == 0)
{
MainPed.CancelRagdoll();
}
@ -518,10 +450,8 @@ namespace RageCoop.Client
{
MainPed.Task.ClearAllImmediately();
}
return;
}
_lastRagdoll = false;
return;
}
if (IsReloading)
@ -551,11 +481,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 +495,7 @@ namespace RageCoop.Client
else if (_lastInCover)
{
MainPed.Task.ClearAllImmediately();
_lastInCover=false;
_lastInCover = false;
}
else if (IsAiming)
{
@ -581,12 +511,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 +536,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 +544,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 +604,8 @@ namespace RageCoop.Client
MainPed.Task.StandStill(2000);
LastMoving = false;
}
if (MainPed.IsTaskActive(TaskType.CTaskDiveToGround)) MainPed.Task.ClearAll();
break;
}
SmoothTransition();
@ -688,23 +618,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 +647,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 +658,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 +666,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 +674,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 +695,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 +703,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,7 @@ using GTA.Native;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
namespace RageCoop.Client
{
@ -24,22 +23,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 +52,8 @@ namespace RageCoop.Client
}
internal SyncedVehicle(int id)
{
ID=id;
LastSynced=Main.Ticked;
ID = id;
LastSynced = Main.Ticked;
}
#endregion
/// <summary>
@ -97,8 +98,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 +120,7 @@ namespace RageCoop.Client
{
MainVehicle.Repair();
}
},1000);
}, 1000);
}
}
if (MainVehicle.IsOnFire)
@ -149,8 +150,6 @@ namespace RageCoop.Client
MainVehicle.AreHighBeamsOn = HighBeamsOn;
}
if (IsAircraft)
{
if (LandingGear != (byte)MainVehicle.LandingGearState)
@ -179,15 +178,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 +198,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 +220,9 @@ namespace RageCoop.Client
}
MainVehicle.LockStatus=LockStatus;
MainVehicle.LockStatus = LockStatus;
if (LastFullSynced>=LastUpdated)
if (LastFullSynced >= LastUpdated)
{
if (Flags.HasVehFlag(VehicleDataFlags.Repaired))
{
@ -233,7 +234,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 +247,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,41 +276,48 @@ 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;
}
}
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()
{
var existing = World.GetNearbyVehicles(Position, 2).ToList().FirstOrDefault();
if (existing != null && existing != MainVehicle)
{
if (EntityPool.VehiclesByHandle.ContainsKey(existing.Handle))
{
EntityPool.RemoveVehicle(ID);
return false;
}
existing.Delete();
}
MainVehicle?.Delete();
MainVehicle = Util.CreateVehicle(Model, Position);
if (!Model.IsInCdImage)
@ -316,7 +325,7 @@ namespace RageCoop.Client
// GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
return false;
}
else if (MainVehicle==null)
if (MainVehicle == null)
{
Model.Request();
return false;
@ -328,54 +337,16 @@ 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 --
/*
* Thanks to @oldnapalm.
*/
private string PedalingAnimDict()
{
switch ((VehicleHash)Model)
{
case VehicleHash.Bmx:
return "veh@bicycle@bmx@front@base";
case VehicleHash.Cruiser:
return "veh@bicycle@cruiserfront@base";
case VehicleHash.Scorcher:
return "veh@bicycle@mountainfront@base";
default:
return "veh@bicycle@roadfront@base";
}
}
private string PedalingAnimName(bool fast)
{
return fast ? "fast_pedal_char" : "cruise_pedal_char";
}
private void StartPedalingAnim(bool fast)
{
MainVehicle.Driver?.Task.PlayAnimation(PedalingAnimDict(), PedalingAnimName(fast), 8.0f, -8.0f, -1, AnimationFlags.Loop | AnimationFlags.AllowRotation, 1.0f);
}
private void StopPedalingAnim(bool fast)
{
MainVehicle.Driver.Task.ClearAnimation(PedalingAnimDict(), PedalingAnimName(fast));
}
#endregion
}
}

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))
foreach (int id in VehiclesByID.Keys.ToArray())
{
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,29 @@ namespace RageCoop.Client
}
}
i=-1;
i = -1;
lock (PedsLock)
{
EntityPool.AddPlayer();
AddPlayer();
var mainCharacters = new List<PedHash> { PedHash.Michael, PedHash.Franklin, PedHash.Franklin02, PedHash.Trevor };
foreach (Ped p in allPeds)
{
SyncedPed c = EntityPool.GetPedByHandle(p.Handle);
if (c==null && (p!=Game.Player.Character))
if (!PedsByHandle.ContainsKey(p.Handle) && p != Game.Player.Character && !mainCharacters.Contains((PedHash)p.Model.Hash))
{
if (allPeds.Length>Main.Settings.WorldPedSoftLimit && p.PopulationType != EntityPopulationType.RandomAmbient)
if (PedsByID.Count(x => x.Value.IsLocal) > Main.Settings.WorldPedSoftLimit)
{
if (p.PopulationType == EntityPopulationType.RandomAmbient && !p.IsInVehicle())
{
p.Delete();
continue;
}
if (p.PopulationType == EntityPopulationType.RandomScenario) continue;
}
// Main.Logger.Trace($"Creating SyncEntity for ped, handle:{p.Handle}");
c=new SyncedPed(p);
EntityPool.Add(c);
Add(new SyncedPed(p));
}
}
#if BENCHMARK
@ -393,18 +384,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 +408,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 +432,25 @@ 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 (VehiclesByID.Count(x => x.Value.IsLocal) > Main.Settings.WorldVehicleSoftLimit)
{
var type = veh.PopulationType;
if (type==EntityPopulationType.RandomAmbient || type==EntityPopulationType.RandomParked)
if (veh.PopulationType == EntityPopulationType.RandomAmbient || veh.PopulationType == EntityPopulationType.RandomParked)
{
foreach (var p in veh.Occupants)
{
p.Delete();
var c = EntityPool.GetPedByHandle(p.Handle);
if (c!=null)
var c = GetPedByHandle(p.Handle);
if (c != null)
{
EntityPool.RemovePed(c.ID, "ThrottleTraffic");
RemovePed(c.ID, "ThrottleTraffic");
}
}
veh.Delete();
@ -477,28 +466,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 +508,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 +525,7 @@ namespace RageCoop.Client
{
foreach (SyncedPed p in PedsByID.Values.ToArray())
{
if (p.OwnerID==playerPedId)
if (p.OwnerID == playerPedId)
{
RemovePed(p.ID);
}
@ -540,7 +533,7 @@ namespace RageCoop.Client
foreach (SyncedVehicle v in VehiclesByID.Values.ToArray())
{
if (v.OwnerID==playerPedId)
if (v.OwnerID == playerPedId)
{
RemoveVehicle(v.ID);
}
@ -550,7 +543,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 +574,21 @@ namespace RageCoop.Client
{
public static void Add(SyncedVehicle v)
{
lock (EntityPool.VehiclesLock)
lock (VehiclesLock)
{
EntityPool.Add(v);
}
}
public static void Add(SyncedPed p)
{
lock (EntityPool.PedsLock)
lock (PedsLock)
{
EntityPool.Add(p);
}
}
public static void Add(SyncedProjectile sp)
{
lock (EntityPool.ProjectilesLock)
lock (ProjectilesLock)
{
EntityPool.Add(sp);
}

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,14 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA;
using GTA.Math;
using GTA.Native;
using GTA.Math;
using System;
using System.Runtime.InteropServices;
using LemonUI.Elements;
using System.Drawing;
namespace RageCoop.Client
{
@ -57,27 +50,27 @@ namespace RageCoop.Client
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)
{
return new NativeVector3() { X=vec.X, Y=vec.Y, Z=vec.Z };
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);
private static extern void NativeInit(ulong hash);
[DllImport("ScriptHookV.dll", ExactSpelling = true, EntryPoint = "?nativePush64@@YAX_K@Z")]
static extern void NativePush64(ulong val);
private static extern void NativePush64(ulong val);
[DllImport("ScriptHookV.dll", ExactSpelling = true, EntryPoint = "?nativeCall@@YAPEA_KXZ")]
static extern unsafe ulong* NativeCall();
private static extern unsafe ulong* NativeCall();
// These are from ScriptHookV's nativeCaller.h
static unsafe void NativePush<T>(T val) where T : unmanaged
private static unsafe void NativePush<T>(T val) where T : unmanaged
{
ulong val64 = 0;
*(T*)(&val64) = val;
@ -93,7 +86,7 @@ namespace RageCoop.Client
where R : unmanaged
{
NativeInit((ulong)hash);
var arguments=ConvertPrimitiveArguments(args);
var arguments = ConvertPrimitiveArguments(args);
foreach (var arg in arguments)
NativePush(arg);
@ -106,7 +99,7 @@ namespace RageCoop.Client
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
static unsafe ulong[] ConvertPrimitiveArguments(object[] args)
private static unsafe ulong[] ConvertPrimitiveArguments(object[] args)
{
var result = new ulong[args.Length];
for (int i = 0; i < args.Length; ++i)
@ -118,7 +111,7 @@ namespace RageCoop.Client
}
if (args[i] is byte valueByte)
{
result[i] = (ulong)valueByte;
result[i] = valueByte;
continue;
}
if (args[i] is int valueInt32)

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 type == 3 ? false : VehicleProjectileWeapons.Contains(vp) || (type == 5 && !ExplosiveBullets.Contains((uint)vp));
}
return VehicleProjectileWeapons.Contains(vp) || (type==5 && !ExplosiveBullets.Contains((uint)vp));
}
else
{
var w = p.Weapons.Current;
return w.Group==WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
}
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,29 +113,24 @@ 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())
{
if (ped == Game.Player.Character) { continue; }
SyncedPed c = EntityPool.GetPedByHandle(ped.Handle);
if ((c == null) || (c.IsLocal && (ped.Handle != Game.Player.Character.Handle) && ped.PopulationType != EntityPopulationType.Mission))
{
if (ped.Handle == Game.Player.Character.Handle) { continue; }
// Main.Logger.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
ped.CurrentVehicle?.Delete();
ped.Kill();
ped.Delete();
}
}
foreach (Vehicle veh in World.GetAllVehicles())
{
SyncedVehicle v = veh.GetSyncEntity();
if (v.MainVehicle == Game.Player.LastVehicle)
if (v.MainVehicle == Game.Player.LastVehicle || v.MainVehicle == Game.Player.Character.CurrentVehicle)
{
// Don't delete player's vehicle
continue;
@ -157,32 +143,6 @@ namespace RageCoop.Client
}
}
}
else
{
foreach (Ped ped in World.GetAllPeds())
{
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();
}
}
var last = Game.Player.Character.LastVehicle;
var current = Game.Player.Character.CurrentVehicle;
foreach (Vehicle veh in World.GetAllVehicles())
{
if (veh.PopulationType != EntityPopulationType.Mission && veh != last && veh!=current)
{
// Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
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,26 +31,26 @@ 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(() =>
LoggerThread = new Thread(() =>
{
if (!UseConsole)
{
while (LogPath==default)
while (LogPath == default)
{
Thread.Sleep(100);
}
if (File.Exists(LogPath)&&overwrite) { File.Delete(LogPath); }
if (File.Exists(LogPath) && overwrite) { File.Delete(LogPath); }
}
while (!Stopping)
{
@ -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,19 +9,19 @@ 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(() =>
ListenerThread = new Thread(() =>
{
while (!_stopping)
{
msg=WaitMessage(200);
if (msg!=null)
msg = WaitMessage(200);
if (msg != null)
{
OnMessageReceived?.Invoke(this,msg);
OnMessageReceived?.Invoke(this, msg);
}
}
});
@ -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
{
@ -11,8 +10,8 @@ namespace RageCoop.Core
internal class ChatMessage : Packet
{
public override PacketType Type => PacketType.ChatMessage;
private Func<string, byte[]> crypt;
private Func<byte[], byte[]> decrypt;
private readonly Func<string, byte[]> crypt;
private readonly Func<byte[], byte[]> decrypt;
public ChatMessage(Func<string, byte[]> crypter)
{
crypt = crypter;
@ -25,33 +24,31 @@ namespace RageCoop.Core
public string Message { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// Write Username
byteArray.AddString(Username);
m.Write(Username);
// Write Message
byteArray.AddArray(crypt(Message));
return byteArray.ToArray();
m.WriteByteArray(crypt(Message));
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read username
Username = reader.ReadString();
Username = m.ReadString();
Message = decrypt(reader.ReadByteArray()).GetString();
Message = decrypt(m.ReadByteArray()).GetString();
#endregion
}
}

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
@ -10,85 +8,78 @@ namespace RageCoop.Core
internal class CustomEvent : Packet
{
public override PacketType Type => (_queued ? PacketType.CustomEventQueued : PacketType.CustomEvent);
public CustomEvent(Func<byte,BitReader,object> onResolve = null,bool queued=false)
public CustomEvent(Func<byte, NetIncomingMessage, object> onResolve = null, bool queued = false)
{
_resolve= onResolve;
_queued= queued;
_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");
CoreUtils.GetBytesFromObject(arg, m);
}
result.Add(tup.Item1);
result.AddRange(tup.Item2);
}
return result.ToArray();
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
BitReader reader = new BitReader(array);
Hash = reader.ReadInt32();
var len=reader.ReadInt32();
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,25 +54,21 @@ namespace RageCoop.Core
public override PacketType Type => PacketType.FileTransferResponse;
public int ID { get; set; }
public FileResponse Response { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// The ID from the download
byteArray.AddInt(ID);
m.Write(ID);
byteArray.Add((byte)Response);
m.Write((byte)Response);
return byteArray.ToArray();
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
BitReader reader = new BitReader(array);
ID = reader.ReadInt32();
Response = (FileResponse)reader.ReadByte();
ID = m.ReadInt32();
Response = (FileResponse)m.ReadByte();
}
}
@ -90,27 +79,21 @@ namespace RageCoop.Core
public byte[] FileChunk { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// The ID from the download
byteArray.AddInt(ID);
// The chunk of the file
byteArray.AddInt(FileChunk.Length);
byteArray.AddRange(FileChunk);
return byteArray.ToArray();
m.Write(ID);
m.WriteByteArray(FileChunk);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
BitReader reader = new BitReader(array);
ID = reader.ReadInt32();
FileChunk = reader.ReadByteArray();
ID = m.ReadInt32();
FileChunk = m.ReadByteArray();
}
}
@ -119,22 +102,20 @@ namespace RageCoop.Core
public override PacketType Type => PacketType.FileTransferComplete;
public int ID { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// The ID for the download
byteArray.AddInt(ID);
return byteArray.ToArray();
m.Write(ID);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
BitReader reader = new BitReader(array);
ID = reader.ReadInt32();
ID = m.ReadInt32();
}
}
internal class AllResourcesSent : Packet

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
{
@ -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
@ -38,62 +36,55 @@ namespace RageCoop.Core
public byte[] PasswordEncrypted { get; set; }
public IPEndPoint InternalEndPoint { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// Write Player Ped ID
byteArray.AddRange(BitConverter.GetBytes(PedID));
m.Write(PedID);
// Write Username
byte[] usernameBytes = Encoding.UTF8.GetBytes(Username);
byteArray.AddRange(BitConverter.GetBytes(usernameBytes.Length));
byteArray.AddRange(usernameBytes);
m.Write(Username);
// Write ModVersion
byte[] modVersionBytes = Encoding.UTF8.GetBytes(ModVersion);
byteArray.AddRange(BitConverter.GetBytes(modVersionBytes.Length));
byteArray.AddRange(modVersionBytes);
m.Write(ModVersion);
byteArray.AddString(InternalEndPoint.ToString());
m.Write(InternalEndPoint.ToString());
// Write AesKeyCrypted
byteArray.AddArray(AesKeyCrypted);
m.WriteByteArray(AesKeyCrypted);
// Write AesIVCrypted
byteArray.AddArray(AesIVCrypted);
m.WriteByteArray(AesIVCrypted);
// Write PassHash
byteArray.AddArray(PasswordEncrypted);
m.WriteByteArray(PasswordEncrypted);
return byteArray.ToArray();
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read player netHandle
PedID = reader.ReadInt32();
PedID = m.ReadInt32();
// Read Username
Username = reader.ReadString();
Username = m.ReadString();
// Read ModVersion
ModVersion = reader.ReadString();
ModVersion = m.ReadString();
InternalEndPoint=CoreUtils.StringToEndPoint(reader.ReadString());
InternalEndPoint = CoreUtils.StringToEndPoint(m.ReadString());
AesKeyCrypted=reader.ReadByteArray();
AesKeyCrypted = m.ReadByteArray();
AesIVCrypted=reader.ReadByteArray();
AesIVCrypted = m.ReadByteArray();
PasswordEncrypted=reader.ReadByteArray();
PasswordEncrypted = m.ReadByteArray();
#endregion
}
}
@ -101,27 +92,25 @@ namespace RageCoop.Core
{
public PlayerData[] Players { get; set; }
public override PacketType Type => PacketType.HandshakeSuccess;
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
var data = new List<byte>();
data.AddInt(Players.Length);
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(),
};
}
}
@ -133,36 +122,24 @@ namespace RageCoop.Core
public string Username { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
// Write NetHandle
byteArray.AddRange(BitConverter.GetBytes(PedID));
m.Write(PedID);
// Get Username bytes
byte[] usernameBytes = Encoding.UTF8.GetBytes(Username);
// Write UsernameLength
byteArray.AddRange(BitConverter.GetBytes(usernameBytes.Length));
// Write Username
byteArray.AddRange(usernameBytes);
return byteArray.ToArray();
m.Write(Username);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read player netHandle
PedID = reader.ReadInt32();
PedID = m.ReadInt32();
// Read Username
Username = reader.ReadString();
Username = m.ReadString();
#endregion
}
}
@ -172,22 +149,18 @@ namespace RageCoop.Core
public override PacketType Type => PacketType.PlayerDisconnect;
public int PedID { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
m.Write(PedID);
byteArray.AddRange(BitConverter.GetBytes(PedID));
return byteArray.ToArray();
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
PedID = reader.ReadInt32();
PedID = m.ReadInt32();
#endregion
}
}
@ -203,42 +176,38 @@ 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();
}
}
@ -249,24 +218,24 @@ namespace RageCoop.Core
public byte[] Modulus;
public byte[] Exponent;
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
byteArray.AddArray(Modulus);
byteArray.AddArray(Exponent);
return byteArray.ToArray();
m.WriteByteArray(Modulus);
m.WriteByteArray(Exponent);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
var reader=new BitReader(array);
Modulus=reader.ReadByteArray();
Exponent=reader.ReadByteArray();
Modulus = m.ReadByteArray();
Exponent = m.ReadByteArray();
#endregion
}

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
@ -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
@ -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
@ -15,24 +12,24 @@ namespace RageCoop.Core
public bool Hover { get; set; }
public override byte[] Serialize()
protected override void Serialize(NetOutgoingMessage m)
{
List<byte> byteArray = new List<byte>();
byteArray.AddInt(VehicleID);
byteArray.AddBool(Hover);
return byteArray.ToArray();
m.Write(VehicleID);
m.Write(Hover);
}
public override void Deserialize(byte[] array)
public override void Deserialize(NetIncomingMessage m)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
VehicleID=reader.ReadInt32();
Hover=reader.ReadBoolean();
VehicleID = m.ReadInt32();
Hover = m.ReadBoolean();
#endregion
}

View File

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

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

View File

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

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

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
{
@ -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,26 +40,21 @@ namespace RageCoop.Core.Scripting
public static int Hash(string s)
{
var hash = BitConverter.ToInt32(Hasher.ComputeHash(Encoding.UTF8.GetBytes(s)), 0);
string name;
lock (Hashed)
{
if (Hashed.TryGetValue(hash, out name))
if (Hashed.TryGetValue(hash, out string name))
{
if (name!=s)
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;
}
}
}
}
}

View File

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace RageCoop.Core.Scripting

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,20 +19,20 @@ 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(() =>
_semaphoreSlim = new SemaphoreSlim(0, maxJobs);
_workerThread = new Thread(() =>
{
while (!_stopping)
{
IsBusy=false;
IsBusy = false;
_semaphoreSlim.Wait();
if(Jobs.TryDequeue(out var job))
if (Jobs.TryDequeue(out var job))
{
IsBusy=true;
IsBusy = true;
try
{
job.Invoke();
@ -48,7 +48,7 @@ namespace RageCoop.Core
throw new InvalidOperationException("Hmm... that's unexpected.");
}
}
IsBusy=false;
IsBusy = false;
});
_workerThread.Start();
}
@ -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;
return response;
}
else
{
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 });
@ -320,8 +318,8 @@ namespace RageCoop.Server.Scripting
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) =>
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,39 +1,33 @@
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();
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;
Logger = server.Logger;
}
private Dictionary<string,Func<Stream>> ClientResources=new();
private Dictionary<string,Func<Stream>> ResourceStreams=new();
private List<MemoryStream> MemStreams = new();
private readonly Dictionary<string, Stream> ClientResources = new();
private readonly Dictionary<string, Stream> ResourceStreams = new();
public void LoadAll()
{
// Packages
{
var path = Path.Combine("Resources", "Packages");
Directory.CreateDirectory(path);
foreach (var pkg in Directory.GetFiles(path,"*.respkg",SearchOption.AllDirectories))
foreach (var pkg in Directory.GetFiles(path, "*.respkg", SearchOption.AllDirectories))
{
Logger?.Debug($"Adding resourece from package \"{Path.GetFileNameWithoutExtension(pkg)}\"");
Logger?.Debug($"Adding resources from package \"{Path.GetFileNameWithoutExtension(pkg)}\"");
var pkgZip = new ZipFile(pkg);
foreach (ZipEntry e in pkgZip)
{
@ -41,15 +35,13 @@ namespace RageCoop.Server.Scripting
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));
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);
ResourceStreams.Add(Path.GetFileNameWithoutExtension(e.Name), stream);
Logger?.Debug("Resource added: " + Path.GetFileNameWithoutExtension(e.Name));
}
}
@ -61,7 +53,7 @@ namespace RageCoop.Server.Scripting
// Client
{
var path = Path.Combine("Resources", "Client");
var tmpDir = Path.Combine("Resources", "Temp","Client");
var tmpDir = Path.Combine("Resources", "Temp", "Client");
Directory.CreateDirectory(path);
if (Directory.Exists(tmpDir))
{
@ -69,13 +61,13 @@ namespace RageCoop.Server.Scripting
}
Directory.CreateDirectory(tmpDir);
var resourceFolders = Directory.GetDirectories(path, "*", SearchOption.TopDirectoryOnly);
if (resourceFolders.Length!=0)
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";
Logger?.Info("Packing client-side resource: " + resourceFolder);
var zipPath = Path.Combine(tmpDir, Path.GetFileName(resourceFolder)) + ".res";
try
{
using ZipFile zip = ZipFile.Create(zipPath);
@ -91,7 +83,7 @@ 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)
{
@ -101,11 +93,11 @@ namespace RageCoop.Server.Scripting
}
}
var packed = Directory.GetFiles(path, "*.res", SearchOption.TopDirectoryOnly);
if (packed.Length>0)
if (packed.Length > 0)
{
foreach(var file in packed)
foreach (var file in packed)
{
ClientResources.Add(Path.GetFileNameWithoutExtension(file),()=>File.OpenRead(file));
ClientResources.Add(Path.GetFileNameWithoutExtension(file), File.OpenRead(file));
}
}
}
@ -125,12 +117,12 @@ namespace RageCoop.Server.Scripting
Logger?.Warning($"Resource \"{name}\" has already been loaded, ignoring...");
continue;
}
if (name.ToLower()=="data") { 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)
catch (Exception ex)
{
Logger?.Error($"Failed to load resource: {Path.GetFileName(resource)}");
Logger?.Error(ex);
@ -138,13 +130,13 @@ namespace RageCoop.Server.Scripting
}
foreach (var res in Directory.GetFiles(path, "*.res", SearchOption.TopDirectoryOnly))
{
if (!ResourceStreams.TryAdd(Path.GetFileNameWithoutExtension(res),()=>File.OpenRead(res)))
if (!ResourceStreams.TryAdd(Path.GetFileNameWithoutExtension(res), File.OpenRead(res)))
{
Logger?.Warning($"Resource \"{res}\" cannot be loaded, ignoring...");
continue;
}
}
foreach(var res in ResourceStreams)
foreach (var res in ResourceStreams)
{
try
{
@ -154,11 +146,11 @@ namespace RageCoop.Server.Scripting
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);
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)
catch (Exception ex)
{
Logger?.Error($"Failed to load resource: {res.Key}");
Logger?.Error(ex);
@ -172,17 +164,17 @@ namespace RageCoop.Server.Scripting
{
foreach (ServerScript s in r.Scripts.Values)
{
s.API=Server.API;
s.API = Server.API;
try
{
Logger?.Debug("Starting script:"+s.CurrentFile.Name);
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;
IsLoaded = true;
}
}
@ -198,7 +190,7 @@ namespace RageCoop.Server.Scripting
{
s.OnStop();
}
catch(Exception ex)
catch (Exception ex)
{
Logger?.Error(ex);
}
@ -207,7 +199,7 @@ namespace RageCoop.Server.Scripting
{
d.Dispose();
}
catch(Exception ex)
catch (Exception ex)
{
Logger.Error($"Resource \"{d.Name}\" cannot be unloaded.");
Logger.Error(ex);
@ -215,44 +207,64 @@ namespace RageCoop.Server.Scripting
}
LoadedResources.Clear();
}
foreach(var s in MemStreams)
foreach (var s in ResourceStreams.Values)
{
try
{
s.Close();
s.Dispose();
}
catch(Exception ex)
catch (Exception ex)
{
Logger?.Error("[Resources.CloseMemStream]",ex);
Logger?.Error("[Resources.CloseStream]", ex);
}
}
foreach (var s in ClientResources.Values)
{
try
{
s.Close();
s.Dispose();
}
catch (Exception ex)
{
Logger?.Error("[Resources.CloseStream]", ex);
}
}
}
public void SendTo(Client client)
{
Task.Run(() =>
{
try
{
if (ClientResources.Count!=0)
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);
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)
if (Server.GetResponse<Packets.FileTransferResponse>(client, new Packets.AllResourcesSent())?.Response == FileResponse.Loaded)
{
client.IsReady=true;
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,14 +196,14 @@ 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 _));
}
@ -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;
Peds[ped.ID] = ped;
return;
}
else
{
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); }
}
@ -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,12 +1,13 @@
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
{
@ -17,46 +18,60 @@ namespace RageCoop.Server.Scripting
{
internal ServerResource(PluginConfig config) : base(config) { }
internal static ServerResource LoadFrom(string resDir, string dataFolder, Logger logger = null, bool isTemp = false)
internal static ServerResource LoadFrom(string resDir, string dataFolder, Logger logger = null)
{
var conf = new PluginConfig(Path.GetFullPath(Path.Combine(resDir, Path.GetFileName(resDir)+".dll")))
var runtimeLibs = Path.Combine(resDir, "RuntimeLibs", CoreUtils.GetInvariantRID());
if (Directory.Exists(runtimeLibs))
{
logger?.Debug("Applying runtime libraries from " + CoreUtils.GetInvariantRID());
CoreUtils.CopyFilesRecursively(new(runtimeLibs), new(resDir));
}
runtimeLibs = Path.Combine(resDir, "RuntimeLibs", RuntimeInformation.RuntimeIdentifier);
if (Directory.Exists(runtimeLibs))
{
logger?.Debug("Applying runtime libraries from " + CoreUtils.GetInvariantRID());
CoreUtils.CopyFilesRecursively(new(runtimeLibs), new(resDir));
}
var conf = new PluginConfig(Path.GetFullPath(Path.Combine(resDir, Path.GetFileName(resDir) + ".dll")))
{
PreferSharedTypes = true,
EnableHotReload=false,
IsUnloadable=false,
LoadInMemory=true,
EnableHotReload = false,
IsUnloadable = false,
LoadInMemory = true,
};
ServerResource r = new(conf);
r.Logger= logger;
r.Name=Path.GetFileName(resDir);
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"); };
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('\\','/')
});;
IsDirectory = true,
Name = dir.Substring(resDir.Length + 1).Replace('\\', '/')
}); ;
}
var assemblies=new Dictionary<ResourceFile,Assembly>();
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 relativeName = file.Substring(resDir.Length + 1).Replace('\\', '/');
var rfile = new ResourceFile()
{
GetStream=() => { return new FileStream(file, FileMode.Open, FileAccess.Read); },
IsDirectory=false,
Name=relativeName
GetStream = () => { return new FileStream(file, FileMode.Open, FileAccess.Read); },
IsDirectory = false,
Name = relativeName
};
if (file.EndsWith(".dll") && !relativeName.Contains('/') && IsManagedAssembly(file))
{
@ -64,28 +79,34 @@ namespace RageCoop.Server.Scripting
}
r.Files.Add(relativeName, rfile);
}
foreach(var a in assemblies)
foreach (var a in assemblies)
{
if (a.Key.Name.ToLower() == r.Name.ToLower() + ".dll")
{
try
{
r.LoadScriptsFromAssembly(a.Key,a.Value);
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?.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)
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);
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
@ -98,7 +119,7 @@ namespace RageCoop.Server.Scripting
/// <summary>
/// Get all <see cref="ServerScript"/> instance in this resource
/// </summary>
public Dictionary<string,ServerScript> Scripts { get; internal set; } = new();
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>
@ -124,8 +145,8 @@ namespace RageCoop.Server.Scripting
// Invoke script constructor
var script = constructor.Invoke(null) as ServerScript;
script.CurrentResource = this;
script.CurrentFile=rfile;
Scripts.Add(script.GetType().FullName,script);
script.CurrentFile = rfile;
Scripts.Add(script.GetType().FullName, script);
count++;
}
catch (Exception ex)
@ -150,7 +171,7 @@ namespace RageCoop.Server.Scripting
}
return false;
}
if(count != 0)
if (count != 0)
{
Logger?.Info($"Loaded {count} script(s) in {rfile.Name}");
}

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