Improved weapon and turret sync
This commit is contained in:
4
.editorconfig
Normal file
4
.editorconfig
Normal file
@ -0,0 +1,4 @@
|
||||
[*.cs]
|
||||
|
||||
# CS0649: Field 'VehicleInfo.Name' is never assigned to, and will always have its default value null
|
||||
dotnet_diagnostic.CS0649.severity = silent
|
27
Client/DataDumper/Program.cs
Normal file
27
Client/DataDumper/Program.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using RageCoop.Core;
|
||||
using Newtonsoft.Json;
|
||||
using System.Data.HashFunction.Jenkins;
|
||||
using System;
|
||||
|
||||
namespace RageCoop.Client.DataDumper
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
|
||||
static UInt32 Hash(string key)
|
||||
{
|
||||
int i = 0;
|
||||
uint hash = 0;
|
||||
while (i != key.Length)
|
||||
{
|
||||
hash += key[i++];
|
||||
hash += hash << 10;
|
||||
hash ^= hash >> 6;
|
||||
}
|
||||
hash += hash << 3;
|
||||
hash ^= hash >> 11;
|
||||
hash += hash << 15;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
19
Client/DataDumper/RageCoop.Client.DataDumper.csproj
Normal file
19
Client/DataDumper/RageCoop.Client.DataDumper.csproj
Normal file
@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<OutputType>exe</OutputType>
|
||||
<OutDir>..\..\bin\Debug\Client.DataDumper</OutDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="System.Data.HashFunction.Jenkins" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\RageCoop.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -189,7 +189,11 @@ namespace RageCoop.Client.Loader
|
||||
{
|
||||
CurrentDomain.DoKeyEvent(keys, status);
|
||||
}
|
||||
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
// Return null to avoid lifetime restriction on the marshaled object.
|
||||
return null;
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
lock (this)
|
||||
|
@ -1,5 +1,6 @@
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
@ -11,174 +12,80 @@ namespace RageCoop.Client
|
||||
internal class DevTool : Script
|
||||
{
|
||||
public static Vehicle ToMark;
|
||||
public static bool UseSecondary = false;
|
||||
public static int Current = 0;
|
||||
public static int Secondary = 0;
|
||||
public static MuzzleDir Direction = MuzzleDir.Forward;
|
||||
public static Script Instance;
|
||||
public DevTool()
|
||||
{
|
||||
Util.StartUpCheck();
|
||||
Instance = this;
|
||||
Tick += OnTick;
|
||||
KeyDown += OnKeyDown;
|
||||
Pause();
|
||||
}
|
||||
|
||||
private void OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (ToMark == null || (!ToMark.Exists())) { return; }
|
||||
if (DevToolMenu.Menu.SelectedItem == DevToolMenu.boneIndexItem)
|
||||
{
|
||||
|
||||
switch (e.KeyCode)
|
||||
{
|
||||
case Keys.Right:
|
||||
Current++;
|
||||
break;
|
||||
case Keys.Left:
|
||||
Current--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (DevToolMenu.Menu.SelectedItem == DevToolMenu.secondaryBoneIndexItem)
|
||||
{
|
||||
|
||||
switch (e.KeyCode)
|
||||
{
|
||||
case Keys.Right:
|
||||
Secondary++;
|
||||
break;
|
||||
case Keys.Left:
|
||||
Secondary--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Update();
|
||||
}
|
||||
private static void Update()
|
||||
{
|
||||
|
||||
if (Current > ToMark.Bones.Count - 1)
|
||||
{
|
||||
Current = 0;
|
||||
}
|
||||
else if (Current < 0)
|
||||
{
|
||||
Current = ToMark.Bones.Count - 1;
|
||||
}
|
||||
DevToolMenu.boneIndexItem.AltTitle = Current.ToString();
|
||||
if (Secondary > ToMark.Bones.Count - 1)
|
||||
{
|
||||
Secondary = 0;
|
||||
}
|
||||
else if (Secondary < 0)
|
||||
{
|
||||
Secondary = ToMark.Bones.Count - 1;
|
||||
}
|
||||
DevToolMenu.secondaryBoneIndexItem.AltTitle = Secondary.ToString();
|
||||
}
|
||||
private void OnTick(object sender, EventArgs e)
|
||||
{
|
||||
if (ToMark == null || !ToMark.Exists()) { return; }
|
||||
Update();
|
||||
Draw(Current);
|
||||
if (UseSecondary)
|
||||
var wb = Game.Player.Character?.Weapons?.CurrentWeaponObject?.Bones["gun_muzzle"];
|
||||
if (wb?.IsValid==true)
|
||||
{
|
||||
Draw(Secondary);
|
||||
World.DrawLine(wb.Position, wb.Position + wb.RightVector, Color.Blue);
|
||||
}
|
||||
|
||||
}
|
||||
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);
|
||||
Vector3 todraw = bone.ForwardVector;
|
||||
switch ((byte)Direction)
|
||||
if (ToMark == null) return;
|
||||
if (WeaponUtil.VehicleWeapons.TryGetValue((uint)(int)ToMark.Model, out var info))
|
||||
{
|
||||
case 0:
|
||||
todraw = bone.ForwardVector;
|
||||
break;
|
||||
case 1:
|
||||
todraw = bone.RightVector;
|
||||
break;
|
||||
case 2:
|
||||
todraw = bone.UpVector;
|
||||
break;
|
||||
case 3:
|
||||
todraw = bone.ForwardVector * -1;
|
||||
break;
|
||||
case 4:
|
||||
todraw = bone.RightVector * -1;
|
||||
break;
|
||||
case 5:
|
||||
todraw = bone.UpVector * -1;
|
||||
break;
|
||||
}
|
||||
World.DrawLine(bone.Position, bone.Position + 10 * todraw, Color.Red);
|
||||
}
|
||||
public static void CopyToClipboard(MuzzleDir dir)
|
||||
{
|
||||
|
||||
if (ToMark != null)
|
||||
{
|
||||
string s;
|
||||
if (UseSecondary)
|
||||
foreach (var ws in info.Weapons)
|
||||
{
|
||||
if ((byte)dir < 3)
|
||||
foreach (var w in ws.Value.Bones)
|
||||
{
|
||||
s = $@"
|
||||
// {ToMark.DisplayName}
|
||||
case {ToMark.Model.Hash}:
|
||||
return BulletsShot%2==0 ? {Current} : {Secondary};
|
||||
";
|
||||
}
|
||||
else
|
||||
{
|
||||
s = $@"
|
||||
// {ToMark.DisplayName}
|
||||
case {ToMark.Model.Hash}:
|
||||
return BulletsShot%2==0 ? {Current} : {Secondary};
|
||||
";
|
||||
DrawBone(w.BoneName, ws.Value.Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((byte)dir < 3)
|
||||
{
|
||||
s = $@"
|
||||
// {ToMark.DisplayName}
|
||||
case {ToMark.Model.Hash}:
|
||||
return {Current};
|
||||
";
|
||||
}
|
||||
else
|
||||
{
|
||||
s = $@"
|
||||
// {ToMark.DisplayName}
|
||||
case {ToMark.Model.Hash}:
|
||||
return {Current};
|
||||
";
|
||||
}
|
||||
}
|
||||
Thread thread = new Thread(() => Clipboard.SetText(s));
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
thread.Join();
|
||||
GTA.UI.Notification.Show("Copied to clipboard, please paste it on the GitHub issue page!");
|
||||
}
|
||||
}
|
||||
void FindAndDraw()
|
||||
{
|
||||
DrawBone("weapon_1a");
|
||||
DrawBone("weapon_1b");
|
||||
DrawBone("weapon_1c");
|
||||
DrawBone("weapon_1d");
|
||||
DrawBone("weapon_2a");
|
||||
DrawBone("weapon_2b");
|
||||
DrawBone("weapon_2c");
|
||||
DrawBone("weapon_2d");
|
||||
DrawBone("weapon_3a");
|
||||
DrawBone("weapon_3b");
|
||||
DrawBone("weapon_3c");
|
||||
DrawBone("weapon_3d");
|
||||
DrawBone("weapon_4a");
|
||||
DrawBone("weapon_4b");
|
||||
DrawBone("weapon_4c");
|
||||
DrawBone("weapon_4d");
|
||||
DrawBone("weapon_1e");
|
||||
DrawBone("weapon_1f");
|
||||
DrawBone("weapon_1g");
|
||||
DrawBone("weapon_1h");
|
||||
DrawBone("weapon_2e");
|
||||
DrawBone("weapon_2f");
|
||||
DrawBone("weapon_2g");
|
||||
DrawBone("weapon_2h");
|
||||
DrawBone("weapon_3e");
|
||||
DrawBone("weapon_3f");
|
||||
DrawBone("weapon_3g");
|
||||
DrawBone("weapon_3h");
|
||||
DrawBone("weapon_4e");
|
||||
DrawBone("weapon_4f");
|
||||
DrawBone("weapon_4g");
|
||||
DrawBone("weapon_4h");
|
||||
}
|
||||
void DrawBone(string name, string text = null)
|
||||
{
|
||||
text = text ?? name;
|
||||
var b = ToMark.Bones[name];
|
||||
if (b.IsValid)
|
||||
{
|
||||
var start = b.Position;
|
||||
var end = b.Position + b.ForwardVector * 5;
|
||||
World.DrawLine(start, end, Color.AliceBlue);
|
||||
Util.DrawTextFromCoord(end, text, 0.35f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
internal enum MuzzleDir : byte
|
||||
{
|
||||
Forward = 0,
|
||||
Right = 1,
|
||||
Up = 2,
|
||||
Backward = 3,
|
||||
Left = 4,
|
||||
Down = 5,
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,37 @@
|
||||
using GTA;
|
||||
using LemonUI.Menus;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Drawing;
|
||||
using RageCoop.Client.Scripting;
|
||||
using Console = GTA.Console;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using GTA.Native;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
class AnimDic
|
||||
{
|
||||
public string DictionaryName;
|
||||
public string[] Animations;
|
||||
}
|
||||
internal static class DevToolMenu
|
||||
{
|
||||
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "DevTool", "Help with the development")
|
||||
const string AnimationsPath = @"RageCoop\Data\animDictsCompact.json";
|
||||
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "DevTool", "Internal testing tools")
|
||||
{
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
private static readonly NativeCheckboxItem enableItem = new NativeCheckboxItem("Enable");
|
||||
public static readonly NativeItem dumpItem = new NativeItem("Dump vehicle weapons");
|
||||
public static readonly NativeItem dumpFixItem = new NativeItem("Dump weapon fixes");
|
||||
public static readonly NativeItem dumpWHashItem = new NativeItem("Dump WeaponHash.cs");
|
||||
public static readonly NativeItem getAnimItem = new NativeItem("Get current animation");
|
||||
|
||||
public static readonly NativeItem dumpVWHashItem = new NativeItem("Dump VehicleWeaponHash.cs");
|
||||
|
||||
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");
|
||||
public static NativeListItem<MuzzleDir> dirItem = new NativeListItem<MuzzleDir>("Direction");
|
||||
static DevToolMenu()
|
||||
{
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
@ -26,55 +39,70 @@ namespace RageCoop.Client
|
||||
|
||||
enableItem.Activated += enableItem_Activated;
|
||||
enableItem.Checked = false;
|
||||
enableSecondaryItem.CheckboxChanged += EnableSecondaryItem_Changed;
|
||||
|
||||
secondaryBoneIndexItem.Enabled = false;
|
||||
clipboardItem.Activated += ClipboardItem_Activated;
|
||||
dirItem.ItemChanged += DirItem_ItemChanged;
|
||||
foreach (var d in Enum.GetValues(typeof(MuzzleDir)))
|
||||
dumpItem.Activated += DumpItem_Activated;
|
||||
dumpVWHashItem.Activated += (s,e)=> WeaponUtil.DumpVehicleWeaponHashes();
|
||||
dumpWHashItem.Activated += (s, e) => WeaponUtil.DumpWeaponHashes();
|
||||
dumpFixItem.Activated += (s, e) => WeaponUtil.DumpWeaponFix();
|
||||
getAnimItem.Activated += (s, e) =>
|
||||
{
|
||||
dirItem.Items.Add((MuzzleDir)d);
|
||||
}
|
||||
dirItem.SelectedIndex = 0;
|
||||
if (File.Exists(AnimationsPath))
|
||||
{
|
||||
var anims = JsonConvert.DeserializeObject<AnimDic[]>(File.ReadAllText(AnimationsPath));
|
||||
foreach(var anim in anims)
|
||||
{
|
||||
foreach(var a in anim.Animations)
|
||||
{
|
||||
if (Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Main.P,anim.DictionaryName,a,3))
|
||||
{
|
||||
Console.Info(anim.DictionaryName + " : " + a);
|
||||
GTA.UI.Notification.Show(anim.DictionaryName+" : "+a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GTA.UI.Notification.Show($"~r~{AnimationsPath} not found");
|
||||
}
|
||||
};
|
||||
|
||||
Menu.Add(enableItem);
|
||||
Menu.Add(boneIndexItem);
|
||||
Menu.Add(enableSecondaryItem);
|
||||
Menu.Add(secondaryBoneIndexItem);
|
||||
Menu.Add(dirItem);
|
||||
Menu.Add(clipboardItem);
|
||||
Menu.Add(dumpItem);
|
||||
Menu.Add(dumpVWHashItem);
|
||||
Menu.Add(dumpWHashItem);
|
||||
Menu.Add(dumpFixItem);
|
||||
Menu.Add(getAnimItem);
|
||||
}
|
||||
|
||||
private static void EnableSecondaryItem_Changed(object sender, EventArgs e)
|
||||
private static void DumpItem_Activated(object sender, EventArgs e)
|
||||
{
|
||||
if (enableSecondaryItem.Checked)
|
||||
dumpItem.Enabled = false;
|
||||
Directory.CreateDirectory(@"RageCoop\Data\tmp");
|
||||
var input = @"RageCoop\Data\tmp\vehicles.json";
|
||||
var dumpLocation = @"RageCoop\Data\VehicleWeapons.json";
|
||||
try
|
||||
{
|
||||
DevTool.UseSecondary = true;
|
||||
secondaryBoneIndexItem.Enabled = true;
|
||||
|
||||
VehicleWeaponInfo.Dump(input, dumpLocation);
|
||||
Console.Info($"Weapon info dumped to " + dumpLocation);
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
DevTool.UseSecondary = false;
|
||||
secondaryBoneIndexItem.Enabled = false;
|
||||
Console.Error($"~r~" + ex.ToString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
dumpItem.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void DirItem_ItemChanged(object sender, ItemChangedEventArgs<MuzzleDir> e)
|
||||
{
|
||||
DevTool.Direction = dirItem.SelectedItem;
|
||||
}
|
||||
|
||||
private static void ClipboardItem_Activated(object sender, EventArgs e)
|
||||
{
|
||||
DevTool.CopyToClipboard(dirItem.SelectedItem);
|
||||
}
|
||||
|
||||
private static void enableItem_Activated(object sender, EventArgs e)
|
||||
{
|
||||
if (enableItem.Checked)
|
||||
{
|
||||
DevTool.Instance.Resume();
|
||||
DevTool.ToMark = Game.Player.Character.CurrentVehicle;
|
||||
DevTool.Instance.Resume();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -42,11 +42,10 @@ namespace RageCoop.Client
|
||||
}
|
||||
};
|
||||
private static readonly AutoResetEvent _publicKeyReceived = new AutoResetEvent(false);
|
||||
private static bool _recycle;
|
||||
public static void ProcessMessage(NetIncomingMessage message)
|
||||
{
|
||||
if (message == null) { return; }
|
||||
_recycle = true;
|
||||
var _recycle = true;
|
||||
switch (message.MessageType)
|
||||
{
|
||||
case NetIncomingMessageType.StatusChanged:
|
||||
@ -293,7 +292,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
recycle = false;
|
||||
// Dispatch to script thread
|
||||
API.QueueAction(() => { SyncEvents.HandleEvent(packetType, msg); Peer.Recycle(msg); return true; });
|
||||
API.QueueAction(() => { SyncEvents.HandleEvent(packetType, msg); return true; });
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ using System.Resources;
|
||||
|
||||
|
||||
// Version informationr(
|
||||
[assembly: AssemblyVersion("1.5.6.1")]
|
||||
[assembly: AssemblyFileVersion("1.5.6.1")]
|
||||
[assembly: AssemblyVersion("1.5.6.98")]
|
||||
[assembly: AssemblyFileVersion("1.5.6.98")]
|
||||
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
|
||||
|
||||
|
@ -128,6 +128,9 @@
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\.editorconfig">
|
||||
<Link>.editorconfig</Link>
|
||||
</None>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
|
@ -175,7 +175,7 @@ namespace RageCoop.Client
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 targetPos = MainPed.Bones[Bone.IKHead].Position;
|
||||
Vector3 targetPos = MainPed.Bones[Bone.IKHead].Position + Vector3.WorldUp * 0.5f;
|
||||
Point toDraw = default;
|
||||
if (Util.WorldToScreen(targetPos, ref toDraw))
|
||||
{
|
||||
@ -688,7 +688,6 @@ namespace RageCoop.Client
|
||||
}
|
||||
if (MainPed.IsOnTurretSeat())
|
||||
{
|
||||
// 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)
|
||||
|
@ -43,7 +43,7 @@ namespace RageCoop.Client
|
||||
#endregion
|
||||
public static void Cleanup(bool keepPlayer = true, bool keepMine = true)
|
||||
{
|
||||
foreach (var ped in PedsByID.Values)
|
||||
foreach (var ped in PedsByID.Values.ToArray())
|
||||
{
|
||||
if ((keepPlayer && (ped.ID == Main.LocalPlayerID)) || (keepMine && (ped.OwnerID == Main.LocalPlayerID))) { continue; }
|
||||
RemovePed(ped.ID);
|
||||
@ -51,7 +51,7 @@ namespace RageCoop.Client
|
||||
PedsByID.Clear();
|
||||
PedsByHandle.Clear();
|
||||
|
||||
foreach (int id in new List<int>(VehiclesByID.Keys))
|
||||
foreach (int id in VehiclesByID.Keys.ToArray())
|
||||
{
|
||||
if (keepMine && (VehiclesByID[id].OwnerID == Main.LocalPlayerID)) { continue; }
|
||||
RemoveVehicle(id);
|
||||
@ -59,7 +59,7 @@ namespace RageCoop.Client
|
||||
VehiclesByID.Clear();
|
||||
VehiclesByHandle.Clear();
|
||||
|
||||
foreach (var p in ProjectilesByID.Values)
|
||||
foreach (var p in ProjectilesByID.Values.ToArray())
|
||||
{
|
||||
if (p.Shooter.ID != Main.LocalPlayerID && p.MainProjectile != null && p.MainProjectile.Exists())
|
||||
{
|
||||
|
@ -3,6 +3,7 @@ using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -30,9 +31,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
// Main.Logger.Trace($"bullet shot:{(WeaponHash)hash}");
|
||||
|
||||
|
||||
var start = owner.MainPed.GetMuzzlePosition();
|
||||
if (owner.MainPed.IsOnTurretSeat()) { start = owner.MainPed.Bones[Bone.SkelHead].Position; }
|
||||
if (start.DistanceTo(impactPosition) > 10)
|
||||
{
|
||||
// Reduce latency
|
||||
@ -43,17 +42,8 @@ namespace RageCoop.Client
|
||||
|
||||
public static void TriggerVehBulletShot(uint hash, Vehicle veh, SyncedPed owner)
|
||||
{
|
||||
|
||||
int i;
|
||||
// ANNIHL
|
||||
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)
|
||||
if ((i = veh.GetMuzzleIndex(owner.MainPed.VehicleWeapon)) != -1)
|
||||
{
|
||||
Networking.SendVehicleBullet(hash, owner, veh.Bones[i]);
|
||||
}
|
||||
@ -72,8 +62,6 @@ namespace RageCoop.Client
|
||||
#region HANDLE
|
||||
|
||||
public static ParticleEffectAsset CorePFXAsset = new ParticleEffectAsset("core");
|
||||
private static WeaponAsset _weaponAsset = default;
|
||||
private static uint _lastWeaponHash;
|
||||
|
||||
private static void HandlePedKilled(Packets.PedKilled p)
|
||||
{
|
||||
@ -94,60 +82,21 @@ namespace RageCoop.Client
|
||||
}
|
||||
private static void HandleBulletShot(Vector3 start, Vector3 end, uint weaponHash, int ownerID)
|
||||
{
|
||||
switch (weaponHash)
|
||||
{
|
||||
// Minigun, not working for some reason
|
||||
case (uint)WeaponHash.Minigun:
|
||||
weaponHash = 1176362416;
|
||||
break;
|
||||
|
||||
// Valkyire, not working for some reason
|
||||
case 2756787765:
|
||||
weaponHash = 1176362416;
|
||||
break;
|
||||
|
||||
// Tampa3, not working for some reason
|
||||
case 3670375085:
|
||||
weaponHash = 1176362416;
|
||||
break;
|
||||
|
||||
// Ruiner2, not working for some reason
|
||||
case 50118905:
|
||||
weaponHash = 1176362416;
|
||||
break;
|
||||
|
||||
// SAVAGE
|
||||
case 1638077257:
|
||||
weaponHash = (uint)VehicleWeaponHash.PlayerLazer;
|
||||
break;
|
||||
|
||||
case (uint)VehicleWeaponHash.PlayerBuzzard:
|
||||
weaponHash = 1176362416;
|
||||
break;
|
||||
}
|
||||
|
||||
var p = EntityPool.GetPedByID(ownerID)?.MainPed;
|
||||
if (p == null) { p = Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); }
|
||||
|
||||
var damage = (int)p.GetWeaponDamage(weaponHash);
|
||||
weaponHash = WeaponUtil.GetWeaponFix(weaponHash);
|
||||
|
||||
if (!CorePFXAsset.IsLoaded) { CorePFXAsset.Request(); }
|
||||
if (_lastWeaponHash != weaponHash)
|
||||
{
|
||||
_weaponAsset.MarkAsNoLongerNeeded();
|
||||
_weaponAsset = new WeaponAsset(weaponHash);
|
||||
_lastWeaponHash = weaponHash;
|
||||
}
|
||||
if (!_weaponAsset.IsLoaded) { _weaponAsset.Request(); }
|
||||
World.ShootBullet(start, end, p, _weaponAsset, (int)p.GetWeaponDamage(weaponHash));
|
||||
var asset = new WeaponAsset(weaponHash);
|
||||
if (!asset.IsLoaded) { asset.Request(); }
|
||||
World.ShootBullet(start, end, p, asset, damage);
|
||||
Prop w;
|
||||
if (((w = p.Weapons.CurrentWeaponObject) != null) && (p.VehicleWeapon == VehicleWeaponHash.Invalid))
|
||||
var turret = false;
|
||||
if ((((w = p.Weapons.CurrentWeaponObject) != null) && (p.VehicleWeapon == VehicleWeaponHash.Invalid)) || (turret = p.IsOnTurretSeat()))
|
||||
{
|
||||
if (p.Weapons.Current.Components.GetSuppressorComponent().Active)
|
||||
{
|
||||
World.CreateParticleEffectNonLooped(CorePFXAsset, "muz_pistol_silencer", p.GetMuzzlePosition(), w.Rotation, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
World.CreateParticleEffectNonLooped(CorePFXAsset, WeaponUtil.GetFlashFX((WeaponHash)weaponHash), p.GetMuzzlePosition(), w.Rotation, 1);
|
||||
}
|
||||
World.CreateParticleEffectNonLooped(CorePFXAsset, p.Weapons.Current.Components.GetSuppressorComponent().Active ? "muz_pistol_silencer" : WeaponUtil.GetFlashFX((WeaponHash)weaponHash, turret), p.GetMuzzlePosition(), turret ? p.CurrentVehicle.GetMuzzleBone(p.VehicleWeapon).GetRotation() : w.Rotation, 1);
|
||||
}
|
||||
}
|
||||
public static void HandleVehicleBulletShot(Packets.VehicleBulletShot p)
|
||||
@ -157,8 +106,8 @@ namespace RageCoop.Client
|
||||
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);
|
||||
WeaponUtil.GetFlashFX((WeaponHash)p.WeaponHash, true),
|
||||
b.Position, b.GetRotation(), 1);
|
||||
}
|
||||
public static void HandleEvent(PacketType type, NetIncomingMessage msg)
|
||||
{
|
||||
@ -166,8 +115,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
case PacketType.BulletShot:
|
||||
{
|
||||
Packets.BulletShot p = new Packets.BulletShot();
|
||||
p.Deserialize(msg);
|
||||
var p = msg.GetPacket<Packets.BulletShot>();
|
||||
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
|
||||
break;
|
||||
}
|
||||
|
@ -335,7 +335,11 @@ namespace RageCoop.Client
|
||||
{
|
||||
return v.Bones[35].Position + v.Bones[35].ForwardVector * 100;
|
||||
}
|
||||
if (p.IsOnTurretSeat()) { return p.GetLookingCoord(); }
|
||||
if (p.IsOnTurretSeat())
|
||||
{
|
||||
var b = p.CurrentVehicle.GetMuzzleBone(p.VehicleWeapon);
|
||||
return b.Position + b.ForwardVector * 50;
|
||||
}
|
||||
if (weapon != null)
|
||||
{
|
||||
// Not very accurate, but doesn't matter
|
||||
@ -459,6 +463,7 @@ namespace RageCoop.Client
|
||||
|
||||
public static bool IsTurretSeat(this Vehicle veh, int seat)
|
||||
{
|
||||
if (Function.Call<bool>(Hash.IS_TURRET_SEAT, veh, seat)) { return true; }
|
||||
if (!Function.Call<bool>(Hash.DOES_VEHICLE_HAVE_WEAPONS, veh.Handle))
|
||||
{
|
||||
return false;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using LemonUI.Elements;
|
||||
using Newtonsoft.Json;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
@ -14,6 +15,10 @@ namespace RageCoop.Client
|
||||
{
|
||||
internal static class Util
|
||||
{
|
||||
public static Vector3 GetRotation(this EntityBone b)
|
||||
{
|
||||
return b.ForwardVector.ToEulerRotation(b.UpVector);
|
||||
}
|
||||
public static void StartUpCheck()
|
||||
{
|
||||
if (AppDomain.CurrentDomain.GetData("RageCoop.Client.LoaderContext") == null)
|
||||
@ -42,6 +47,21 @@ namespace RageCoop.Client
|
||||
return new SizeF(width, 1080f);
|
||||
}
|
||||
}
|
||||
public static void DrawTextFromCoord(Vector3 coord, string text, float scale = 0.5f, Point offset = default)
|
||||
{
|
||||
Point toDraw = default;
|
||||
if (WorldToScreen(coord, ref toDraw))
|
||||
{
|
||||
toDraw.X += offset.X;
|
||||
toDraw.Y += offset.Y;
|
||||
new ScaledText(toDraw, text, scale, GTA.UI.Font.ChaletLondon)
|
||||
{
|
||||
Outline = true,
|
||||
Alignment = GTA.UI.Alignment.Center,
|
||||
Color = Color.White,
|
||||
}.Draw();
|
||||
}
|
||||
}
|
||||
public static bool WorldToScreen(Vector3 pos, ref Point screenPos)
|
||||
{
|
||||
float x, y;
|
||||
|
@ -1,22 +1,239 @@
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using Newtonsoft.Json;
|
||||
using RageCoop.Core;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System;
|
||||
using Console = GTA.Console;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class MuzzleInfo
|
||||
#region DUMP
|
||||
|
||||
class VehicleInfo
|
||||
{
|
||||
public MuzzleInfo(Vector3 pos, Vector3 forward)
|
||||
{
|
||||
Position = pos;
|
||||
ForawardVector = forward;
|
||||
}
|
||||
public Vector3 Position;
|
||||
public Vector3 ForawardVector;
|
||||
public string Name;
|
||||
public string[] Weapons;
|
||||
public uint Hash;
|
||||
public VehicleBone[] Bones;
|
||||
}
|
||||
class VehicleBone
|
||||
{
|
||||
public uint BoneID;
|
||||
public uint BoneIndex;
|
||||
public string BoneName;
|
||||
}
|
||||
class WeaponBones
|
||||
{
|
||||
public string Name;
|
||||
public VehicleBone[] Bones;
|
||||
}
|
||||
class VehicleWeaponInfo
|
||||
{
|
||||
public static void Dump(string input, string output)
|
||||
{
|
||||
Console.Info("Generating " + output);
|
||||
if (!File.Exists(input))
|
||||
{
|
||||
Console.Info("Downloading");
|
||||
HttpHelper.DownloadFile("https://raw.githubusercontent.com/DurtyFree/gta-v-data-dumps/master/vehicles.json", input);
|
||||
}
|
||||
Console.Info("Deserialising");
|
||||
var infos = JsonConvert.DeserializeObject<VehicleInfo[]>(File.ReadAllText(input));
|
||||
Console.Info("Serialising");
|
||||
File.WriteAllText(output,
|
||||
JsonConvert.SerializeObject(
|
||||
infos.Select(x => FromVehicle(x)).Where(x => x != null),
|
||||
Formatting.Indented));
|
||||
}
|
||||
public static VehicleWeaponInfo FromVehicle(VehicleInfo info)
|
||||
{
|
||||
if (info.Weapons.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var result = new VehicleWeaponInfo() { Hash = info.Hash, Name = info.Name };
|
||||
for (int i = 0; i < info.Weapons.Length; i++)
|
||||
{
|
||||
result.Weapons.Add((uint)Game.GenerateHash(info.Weapons[i])
|
||||
, new WeaponBones
|
||||
{
|
||||
Name = info.Weapons[i],
|
||||
Bones = info.Bones.Where(x => x.BoneName.StartsWith($"weapon_{i + 1}") && !x.BoneName.EndsWith("rot")).ToArray()
|
||||
});
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public uint Hash;
|
||||
public string Name;
|
||||
public Dictionary<uint, WeaponBones> Weapons = new Dictionary<uint, WeaponBones>();
|
||||
}
|
||||
class WeaponInfo
|
||||
{
|
||||
public string Name;
|
||||
public uint Hash;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 312)]
|
||||
public struct DlcWeaponData
|
||||
{
|
||||
}
|
||||
class WeaponFix
|
||||
{
|
||||
public Dictionary<uint,string> Bullet=new Dictionary<uint, string>();
|
||||
public Dictionary<uint, string> Lazer = new Dictionary<uint, string>();
|
||||
}
|
||||
#endregion
|
||||
|
||||
internal static class WeaponUtil
|
||||
{
|
||||
public static Dictionary<uint, VehicleWeaponInfo> VehicleWeapons = new Dictionary<uint, VehicleWeaponInfo>();
|
||||
public static WeaponFix WeaponFix;
|
||||
public const string VehicleWeaponLocation= @"RageCoop\Data\VehicleWeapons.json";
|
||||
public const string WeaponFixLocation = @"RageCoop\Data\WeaponFixes.json";
|
||||
static WeaponUtil()
|
||||
{
|
||||
if (!File.Exists(VehicleWeaponLocation))
|
||||
{
|
||||
Directory.CreateDirectory(@"RageCoop\Data\tmp");
|
||||
var input = @"RageCoop\Data\tmp\vehicles.json";
|
||||
VehicleWeaponInfo.Dump(input, VehicleWeaponLocation);
|
||||
}
|
||||
|
||||
// Parse and load to memory
|
||||
foreach (var w in JsonConvert.DeserializeObject<VehicleWeaponInfo[]>(File.ReadAllText(VehicleWeaponLocation)))
|
||||
{
|
||||
VehicleWeapons.Add(w.Hash, w);
|
||||
}
|
||||
WeaponFix = JsonConvert.DeserializeObject<WeaponFix>(File.ReadAllText(WeaponFixLocation));
|
||||
}
|
||||
public static void DumpWeaponFix(string path = WeaponFixLocation)
|
||||
{
|
||||
var P = Game.Player.Character;
|
||||
var pos = P.Position + Vector3.WorldUp * 3;
|
||||
var types = new HashSet<int>() { 3 };
|
||||
P.IsInvincible = true;
|
||||
var fix = new WeaponFix();
|
||||
foreach (VehicleWeaponHash v in Enum.GetValues(typeof(VehicleWeaponHash)))
|
||||
{
|
||||
Console.Info("Testing: " + v);
|
||||
if (types.Contains(v.GetWeaponDamageType()))
|
||||
{
|
||||
var asset = new WeaponAsset((int)v);
|
||||
asset.Request(1000);
|
||||
World.ShootBullet(pos, pos + Vector3.WorldUp, P, asset, 0, 1000);
|
||||
if (!Function.Call<bool>(Hash.IS_BULLET_IN_AREA, pos.X, pos.Y, pos.Z, 10f, true) &&
|
||||
!Function.Call<bool>(Hash.IS_PROJECTILE_IN_AREA, pos.X - 10, pos.Y - 10, pos.Z - 10, pos.X + 10, pos.Y + 10, pos.Z + 10, true))
|
||||
{
|
||||
fix.Bullet.Add((uint)v,$"{nameof(VehicleWeaponHash)}.{v}");
|
||||
}
|
||||
foreach (var p in World.GetAllProjectiles())
|
||||
{
|
||||
p.Delete();
|
||||
}
|
||||
Script.Wait(50);
|
||||
}
|
||||
}
|
||||
foreach (WeaponHash w in Enum.GetValues(typeof(WeaponHash)))
|
||||
{
|
||||
if (types.Contains(w.GetWeaponDamageType()))
|
||||
{
|
||||
Console.Info("Testing: " + w);
|
||||
var asset = new WeaponAsset((int)w);
|
||||
asset.Request(1000);
|
||||
World.ShootBullet(pos, pos + Vector3.WorldUp, P, asset, 0, 1000);
|
||||
if (!Function.Call<bool>(Hash.IS_BULLET_IN_AREA, pos.X, pos.Y, pos.Z, 10f, true) &&
|
||||
!Function.Call<bool>(Hash.IS_PROJECTILE_IN_AREA, pos.X - 10, pos.Y - 10, pos.Z - 10, pos.X + 10, pos.Y + 10, pos.Z + 10, true))
|
||||
{
|
||||
fix.Bullet.Add((uint)w, $"{nameof(WeaponHash)}.{w}");
|
||||
}
|
||||
foreach (var p in World.GetAllProjectiles())
|
||||
{
|
||||
p.Delete();
|
||||
}
|
||||
Script.Wait(50);
|
||||
}
|
||||
}
|
||||
AddLazer(VehicleWeaponHash.PlayerSavage);
|
||||
AddLazer(VehicleWeaponHash.StrikeforceCannon);
|
||||
void AddLazer(dynamic hash)
|
||||
{
|
||||
fix.Lazer.Add((uint)hash, $"{hash.GetType().Name}.{hash.ToString()}");
|
||||
}
|
||||
File.WriteAllText(path, JsonConvert.SerializeObject(fix, Formatting.Indented));
|
||||
|
||||
P.IsInvincible = false;
|
||||
}
|
||||
public static void DumpWeaponHashes(string path = VehicleWeaponLocation)
|
||||
{
|
||||
Dictionary<uint, string> hashes = new Dictionary<uint, string>();
|
||||
foreach (var wep in JsonConvert.DeserializeObject<WeaponInfo[]>(HttpHelper.DownloadString("https://raw.githubusercontent.com/DurtyFree/gta-v-data-dumps/master/weapons.json")))
|
||||
{
|
||||
if (!wep.Name.StartsWith("WEAPON")) { continue; }
|
||||
hashes.Add(wep.Hash, wep.Name);
|
||||
}
|
||||
var output = "public enum WeaponHash : uint\r\n{";
|
||||
List<string> lines = new List<string>();
|
||||
foreach (var hash in hashes)
|
||||
{
|
||||
lines.Add($"{CoreUtils.FormatToSharpStyle(hash.Value, 7)} = {hash.Key.ToHex()}");
|
||||
}
|
||||
lines.Sort();
|
||||
foreach (var l in lines)
|
||||
{
|
||||
output += $"\r\n\t{l},";
|
||||
}
|
||||
output += "\r\n}";
|
||||
File.WriteAllText(path, output);
|
||||
|
||||
}
|
||||
|
||||
public static void DumpVehicleWeaponHashes(string path = @"RageCoop\Data\VehicleWeaponHash.cs")
|
||||
{
|
||||
Dictionary<uint, string> hashes = new Dictionary<uint, string>();
|
||||
foreach (var veh in VehicleWeapons.Values)
|
||||
{
|
||||
foreach (var hash in veh.Weapons)
|
||||
{
|
||||
if (!hashes.ContainsKey(hash.Key))
|
||||
{
|
||||
hashes.Add(hash.Key, hash.Value.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
var output = "public enum VehicleWeaponHash : uint\r\n{\r\n\tInvalid = 0xFFFFFFFF,";
|
||||
List<string> lines = new List<string>();
|
||||
foreach (var hash in hashes)
|
||||
{
|
||||
lines.Add($"{CoreUtils.FormatToSharpStyle(hash.Value)} = {hash.Key.ToHex()}");
|
||||
}
|
||||
lines.Sort();
|
||||
foreach (var l in lines)
|
||||
{
|
||||
output += $"\r\n\t{l},";
|
||||
}
|
||||
output += "\r\n}";
|
||||
File.WriteAllText(path, output);
|
||||
|
||||
}
|
||||
public static uint GetWeaponFix(uint hash)
|
||||
{
|
||||
if(WeaponFix.Bullet.TryGetValue(hash,out var _))
|
||||
{
|
||||
return (uint)VehicleWeaponHash.SubcarMg;
|
||||
}
|
||||
if (WeaponFix.Lazer.TryGetValue(hash, out var _))
|
||||
{
|
||||
return (uint)VehicleWeaponHash.PlayerLazer;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
public static Dictionary<uint, bool> GetWeaponComponents(this Weapon weapon)
|
||||
{
|
||||
Dictionary<uint, bool> result = null;
|
||||
@ -36,334 +253,37 @@ namespace RageCoop.Client
|
||||
|
||||
public static Vector3 GetMuzzlePosition(this Ped p)
|
||||
{
|
||||
var w = p.Weapons.CurrentWeaponObject;
|
||||
if (w != null)
|
||||
if (p.IsOnTurretSeat())
|
||||
{
|
||||
var hash = p.Weapons.Current.Hash;
|
||||
if (MuzzleBoneIndexes.ContainsKey(hash)) { return w.Bones[MuzzleBoneIndexes[hash]].Position; }
|
||||
return w.Position;
|
||||
return p.CurrentVehicle.GetMuzzleBone(p.VehicleWeapon).Position;
|
||||
}
|
||||
var wb = p.Weapons?.CurrentWeaponObject?.Bones["gun_muzzle"];
|
||||
if (wb?.IsValid == true)
|
||||
{
|
||||
return wb.Position;
|
||||
}
|
||||
return p.Bones[Bone.SkelRightHand].Position;
|
||||
}
|
||||
|
||||
private static long BulletsShot = 0;
|
||||
|
||||
public static float GetWeaponDamage(this Ped P, uint hash)
|
||||
{
|
||||
var comp = P.Weapons.Current.Components.GetSuppressorComponent();
|
||||
return Function.Call<float>(Hash.GET_WEAPON_DAMAGE, hash, comp.Active ? comp.ComponentHash : WeaponComponentHash.Invalid);
|
||||
|
||||
/*
|
||||
if (P.IsInVehicle() && (hash!=(uint)P.Weapons.Current.Hash))
|
||||
{
|
||||
// This is a vehicle weapon
|
||||
P.VehicleWeapon=(VehicleWeaponHash)hash;
|
||||
return 100;
|
||||
}
|
||||
switch (P.Weapons.Current.Group)
|
||||
{
|
||||
case WeaponGroup.Pistol: return 30;
|
||||
case WeaponGroup.AssaultRifle: return 30;
|
||||
case WeaponGroup.SMG: return 20;
|
||||
case WeaponGroup.MG: return 40;
|
||||
case WeaponGroup.Shotgun: return 30;
|
||||
case WeaponGroup.Sniper: return 200;
|
||||
case WeaponGroup.Heavy: return 30;
|
||||
}
|
||||
return 0;
|
||||
*/
|
||||
}
|
||||
|
||||
public static int GetMuzzleIndex(this Vehicle v)
|
||||
public static int GetMuzzleIndex(this Vehicle v, VehicleWeaponHash hash)
|
||||
{
|
||||
BulletsShot++;
|
||||
switch (v.Model.Hash)
|
||||
if (VehicleWeapons.TryGetValue((uint)v.Model.Hash, out var veh) && veh.Weapons.TryGetValue((uint)hash, out var wp))
|
||||
{
|
||||
// cerberus3
|
||||
case 1909700336:
|
||||
return 53;
|
||||
|
||||
// cerberus2
|
||||
case 679453769:
|
||||
return 54;
|
||||
|
||||
// cerberus
|
||||
case -801550069:
|
||||
return 90;
|
||||
/*
|
||||
// cerberus (flame)
|
||||
case -801550069:
|
||||
i=BulletsShot%2==0 ? 89 : 88;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
// cerberus (passenger flame)
|
||||
case -801550069:
|
||||
i=BulletsShot%2==0 ? 76 : 75;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
*/
|
||||
|
||||
// ISSI6
|
||||
case 1239571361:
|
||||
return BulletsShot % 2 == 0 ? 12 : 14;
|
||||
|
||||
|
||||
// ISSI5
|
||||
case 1537277726:
|
||||
return BulletsShot % 2 == 0 ? 30 : 32;
|
||||
|
||||
|
||||
// ISSI4
|
||||
case 628003514:
|
||||
return BulletsShot % 2 == 0 ? 14 : 12;
|
||||
|
||||
|
||||
// DOMINATOR6
|
||||
case -1293924613:
|
||||
return BulletsShot % 2 == 0 ? 51 : 55;
|
||||
|
||||
|
||||
// IMPALER4
|
||||
case -1744505657:
|
||||
return BulletsShot % 2 == 0 ? 64 : 63;
|
||||
|
||||
|
||||
|
||||
// IMPERATOR3
|
||||
case -755532233:
|
||||
return BulletsShot % 2 == 0 ? 86 : 88;
|
||||
|
||||
|
||||
|
||||
// SLAMVAN6
|
||||
case 1742022738:
|
||||
return BulletsShot % 2 == 0 ? 78 : 76;
|
||||
|
||||
|
||||
// CHAMPION
|
||||
case -915234475:
|
||||
return BulletsShot % 2 == 0 ? 60 : 61;
|
||||
|
||||
|
||||
// MONSTER4
|
||||
case 840387324:
|
||||
return BulletsShot % 2 == 0 ? 63 : 65;
|
||||
|
||||
|
||||
// BRUTUS2
|
||||
case -1890996696:
|
||||
return 67;
|
||||
|
||||
// BRUISER2
|
||||
case -1694081890:
|
||||
return BulletsShot % 2 == 0 ? 45 : 51;
|
||||
|
||||
|
||||
// TECHNICAL3
|
||||
case 1356124575:
|
||||
return 67;
|
||||
|
||||
// TECHNICAL2
|
||||
case 1180875963:
|
||||
return 54;
|
||||
|
||||
// TECHNICAL
|
||||
case -2096818938:
|
||||
return 63;
|
||||
|
||||
// PATRIOT3
|
||||
case -670086588:
|
||||
return BulletsShot % 2 == 0 ? 87 : 89;
|
||||
|
||||
// NIGHTSHARK
|
||||
case 433954513:
|
||||
return BulletsShot % 2 == 0 ? 1 : 2;
|
||||
|
||||
/*
|
||||
// NIGHTSHARK (second)
|
||||
case 433954513:
|
||||
return BulletsShot%2==0 ? 3 : 4;
|
||||
*/
|
||||
|
||||
// MENACER
|
||||
case 2044532910:
|
||||
return BulletsShot % 2 == 0 ? 91 : 90;
|
||||
/*
|
||||
// MENACER
|
||||
case 2044532910:
|
||||
return new MuzzleInfo(v.Bones[75].Position, v.Bones[75].ForwardVector);
|
||||
// MENACER
|
||||
case 2044532910:
|
||||
return new MuzzleInfo(v.Bones[78].Position, v.Bones[78].ForwardVector);
|
||||
|
||||
*/
|
||||
|
||||
// CARACARA
|
||||
case 1254014755:
|
||||
return 83;
|
||||
|
||||
/*
|
||||
// CARACARA
|
||||
case 1254014755:
|
||||
return BulletsShot%2==0 ? 93 : 94;
|
||||
*/
|
||||
|
||||
// INSURGENT
|
||||
case -1860900134:
|
||||
return 49;
|
||||
|
||||
// INSURGENT3
|
||||
case -1924433270:
|
||||
return 81;
|
||||
|
||||
/*
|
||||
// INSURGENT3
|
||||
case -1924433270:
|
||||
return BulletsShot%2==0 ? 86 : 91;
|
||||
*/
|
||||
|
||||
// BLAZER5
|
||||
case -1590337689:
|
||||
return BulletsShot % 2 == 0 ? 17 : 18;
|
||||
|
||||
// BRUISER
|
||||
case 668439077:
|
||||
return BulletsShot % 2 == 0 ? 66 : 68;
|
||||
|
||||
|
||||
// BRUTUS
|
||||
case 2139203625:
|
||||
return 84;
|
||||
|
||||
|
||||
// MONSTER3
|
||||
case 1721676810:
|
||||
return BulletsShot % 2 == 0 ? 53 : 55;
|
||||
|
||||
|
||||
// BRUISER3
|
||||
case -2042350822:
|
||||
return BulletsShot % 2 == 0 ? 52 : 50;
|
||||
|
||||
// BRUTUS3
|
||||
case 2038858402:
|
||||
return 84;
|
||||
|
||||
// MONSTER5
|
||||
case -715746948:
|
||||
return BulletsShot % 2 == 0 ? 63 : 65;
|
||||
|
||||
// JB7002
|
||||
case 394110044:
|
||||
return BulletsShot % 2 == 0 ? 54 : 53;
|
||||
|
||||
// DOMINATOR5
|
||||
case -1375060657:
|
||||
return BulletsShot % 2 == 0 ? 35 : 36;
|
||||
|
||||
// IMPALER3
|
||||
case -1924800695:
|
||||
return BulletsShot % 2 == 0 ? 75 : 76;
|
||||
|
||||
|
||||
// IMPERATOR2
|
||||
case 1637620610:
|
||||
return BulletsShot % 2 == 0 ? 97 : 99;
|
||||
|
||||
|
||||
// SLAMVAN5
|
||||
case 373261600:
|
||||
return BulletsShot % 2 == 0 ? 51 : 53;
|
||||
|
||||
|
||||
// RUINER2
|
||||
case 941494461:
|
||||
return BulletsShot % 2 == 0 ? 65 : 66;
|
||||
|
||||
|
||||
// TAMPA3
|
||||
case -1210451983:
|
||||
return 87;
|
||||
|
||||
// SCRAMJET
|
||||
case -638562243:
|
||||
return BulletsShot % 2 == 0 ? 44 : 45;
|
||||
|
||||
|
||||
// VIGILANTE
|
||||
case -1242608589:
|
||||
return BulletsShot % 2 == 0 ? 42 : 43;
|
||||
|
||||
|
||||
// ZR380
|
||||
case 540101442:
|
||||
return BulletsShot % 2 == 0 ? 57 : 63;
|
||||
|
||||
|
||||
// ZR3802
|
||||
case -1106120762:
|
||||
return BulletsShot % 2 == 0 ? 57 : 63;
|
||||
|
||||
|
||||
// ZR3803
|
||||
case -1478704292:
|
||||
return BulletsShot % 2 == 0 ? 53 : 59;
|
||||
|
||||
|
||||
// STROMBERG
|
||||
case 886810209:
|
||||
return BulletsShot % 2 == 0 ? 85 : 84;
|
||||
|
||||
|
||||
// SLAMVAN4
|
||||
case -2061049099:
|
||||
return BulletsShot % 2 == 0 ? 76 : 78;
|
||||
|
||||
|
||||
// IMPERATOR
|
||||
case 444994115:
|
||||
return BulletsShot % 2 == 0 ? 88 : 86;
|
||||
|
||||
|
||||
// IMPALER2
|
||||
case 1009171724:
|
||||
return BulletsShot % 2 == 0 ? 63 : 64;
|
||||
|
||||
|
||||
// DOMINATOR4
|
||||
case -688189648:
|
||||
return BulletsShot % 2 == 0 ? 59 : 60;
|
||||
|
||||
|
||||
// SAVAGE
|
||||
case -82626025:
|
||||
return 30;
|
||||
|
||||
// BUZZARD
|
||||
case 788747387:
|
||||
return BulletsShot % 2 == 0 ? 28 : 23;
|
||||
|
||||
|
||||
// ANNIHL
|
||||
case 837858166:
|
||||
return (int)BulletsShot % 4 + 35;
|
||||
|
||||
|
||||
// HYDRA
|
||||
case 970385471:
|
||||
return BulletsShot % 2 == 0 ? 29 : 28;
|
||||
|
||||
|
||||
// STARLING
|
||||
case -1700874274:
|
||||
return BulletsShot % 2 == 0 ? 24 : 12;
|
||||
|
||||
|
||||
// RHINO
|
||||
case 782665360:
|
||||
return 30;
|
||||
|
||||
default:
|
||||
return AddOnDataProvider.GetMuzzleIndex(v.Model.Hash);
|
||||
return (int)wp.Bones[CoreUtils.RandInt(0, wp.Bones.Length)].BoneIndex;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
public static EntityBone GetMuzzleBone(this Vehicle v, VehicleWeaponHash hash)
|
||||
{
|
||||
var i = v.GetMuzzleIndex(hash);
|
||||
if (i == -1) { return null; }
|
||||
return v.Bones[i];
|
||||
}
|
||||
public static bool IsUsingProjectileWeapon(this Ped p)
|
||||
{
|
||||
@ -377,83 +297,16 @@ namespace RageCoop.Client
|
||||
var w = p.Weapons.Current;
|
||||
return w.Group == WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
|
||||
}
|
||||
|
||||
public static int GetWeaponDamageType<T>(this T hash) where T : Enum
|
||||
{
|
||||
return Function.Call<int>(Hash.GET_WEAPON_DAMAGE_TYPE, hash);
|
||||
}
|
||||
public static readonly HashSet<uint> ExplosiveBullets = new HashSet<uint>
|
||||
{
|
||||
(uint)VehicleWeaponHash.PlayerLazer,
|
||||
(uint)WeaponHash.Railgun,
|
||||
1638077257
|
||||
};
|
||||
|
||||
public static readonly Dictionary<WeaponHash, int> MuzzleBoneIndexes = new Dictionary<WeaponHash, int>
|
||||
{
|
||||
{WeaponHash.HeavySniper,6},
|
||||
{WeaponHash.MarksmanRifle,9},
|
||||
{WeaponHash.SniperRifle,9},
|
||||
{WeaponHash.AdvancedRifle,5},
|
||||
{WeaponHash.SpecialCarbine,9},
|
||||
{WeaponHash.BullpupRifle,7},
|
||||
{WeaponHash.AssaultRifle,9},
|
||||
{WeaponHash.CarbineRifle,6},
|
||||
{WeaponHash.MachinePistol,5},
|
||||
{WeaponHash.SMG,5},
|
||||
{WeaponHash.AssaultSMG,6},
|
||||
{WeaponHash.CombatPDW,5},
|
||||
{WeaponHash.MG,6},
|
||||
{WeaponHash.CombatMG,7},
|
||||
{WeaponHash.Gusenberg,7},
|
||||
{WeaponHash.MicroSMG,10},
|
||||
{WeaponHash.APPistol,8},
|
||||
{WeaponHash.StunGun,4},
|
||||
{WeaponHash.Pistol,8},
|
||||
{WeaponHash.CombatPistol,8},
|
||||
{WeaponHash.Pistol50,7},
|
||||
{WeaponHash.SNSPistol,8},
|
||||
{WeaponHash.HeavyPistol,8},
|
||||
{WeaponHash.VintagePistol,8},
|
||||
{WeaponHash.Railgun,9},
|
||||
{WeaponHash.Minigun,5},
|
||||
{WeaponHash.Musket,3},
|
||||
{WeaponHash.HeavyShotgun,10},
|
||||
{WeaponHash.PumpShotgun,11},
|
||||
{WeaponHash.SawnOffShotgun,8},
|
||||
{WeaponHash.BullpupShotgun,8},
|
||||
{WeaponHash.AssaultShotgun,9},
|
||||
{WeaponHash.HeavySniperMk2,11},
|
||||
{WeaponHash.MarksmanRifleMk2,9},
|
||||
{WeaponHash.CarbineRifleMk2,13},
|
||||
{WeaponHash.SpecialCarbineMk2,16},
|
||||
{WeaponHash.BullpupRifleMk2,8},
|
||||
{WeaponHash.CompactRifle,7},
|
||||
{WeaponHash.MilitaryRifle,11},
|
||||
{WeaponHash.AssaultrifleMk2,17},
|
||||
{WeaponHash.MiniSMG,5},
|
||||
{WeaponHash.SMGMk2,6},
|
||||
{WeaponHash.CombatMGMk2,16},
|
||||
{WeaponHash.UnholyHellbringer,4},
|
||||
{WeaponHash.PistolMk2,12},
|
||||
{WeaponHash.SNSPistolMk2,15},
|
||||
{WeaponHash.CeramicPistol,10},
|
||||
{WeaponHash.MarksmanPistol,4},
|
||||
{WeaponHash.Revolver,7},
|
||||
{WeaponHash.RevolverMk2,7},
|
||||
{WeaponHash.DoubleActionRevolver,7},
|
||||
{WeaponHash.NavyRevolver,7},
|
||||
{WeaponHash.PericoPistol,4},
|
||||
{WeaponHash.FlareGun,4},
|
||||
{WeaponHash.UpNAtomizer,4},
|
||||
{WeaponHash.HomingLauncher,5},
|
||||
{WeaponHash.CompactGrenadeLauncher,8},
|
||||
{WeaponHash.Widowmaker,6},
|
||||
{WeaponHash.GrenadeLauncher,3},
|
||||
{WeaponHash.RPG,9},
|
||||
{WeaponHash.DoubleBarrelShotgun,8},
|
||||
{WeaponHash.SweeperShotgun,7},
|
||||
{WeaponHash.CombatShotgun,7},
|
||||
{WeaponHash.PumpShotgunMk2,7},
|
||||
|
||||
};
|
||||
|
||||
public static readonly HashSet<WeaponHash> ProjectileWeapons = new HashSet<WeaponHash> {
|
||||
WeaponHash.HomingLauncher,
|
||||
WeaponHash.RPG,
|
||||
@ -471,8 +324,18 @@ namespace RageCoop.Client
|
||||
(VehicleWeaponHash)3565779982, // STROMBERG missiles
|
||||
(VehicleWeaponHash)3169388763, // SCRAMJET missiles
|
||||
};
|
||||
public static string GetFlashFX(this WeaponHash w)
|
||||
public static string GetFlashFX(this WeaponHash w,bool veh)
|
||||
{
|
||||
if (veh)
|
||||
{
|
||||
|
||||
switch ((VehicleWeaponHash)w)
|
||||
{
|
||||
case VehicleWeaponHash.Tank:
|
||||
return "muz_tank";
|
||||
default: return "muz_buzzard";
|
||||
}
|
||||
}
|
||||
switch (w.GetWeaponGroup())
|
||||
{
|
||||
case WeaponGroup.SMG:
|
||||
@ -510,16 +373,9 @@ namespace RageCoop.Client
|
||||
|
||||
case WeaponGroup.FireExtinguisher:
|
||||
return "weap_extinguisher";
|
||||
default:
|
||||
return "muz_assault_rifle";
|
||||
}
|
||||
switch ((VehicleWeaponHash)w)
|
||||
{
|
||||
case VehicleWeaponHash.Tank:
|
||||
return "muz_tank";
|
||||
|
||||
case VehicleWeaponHash.PlayerBuzzard:
|
||||
return "muz_buzzard";
|
||||
}
|
||||
return "muz_assault_rifle";
|
||||
}
|
||||
public static WeaponGroup GetWeaponGroup(this WeaponHash hash)
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
using GTA.Native;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -19,11 +19,33 @@ using System.Text;
|
||||
[assembly: InternalsVisibleTo("RageCoop.Server")]
|
||||
[assembly: InternalsVisibleTo("RageCoop.Client")]
|
||||
[assembly: InternalsVisibleTo("RageCoop.Client.Installer")]
|
||||
[assembly: InternalsVisibleTo("RageCoop.Client.DataDumper")]
|
||||
[assembly: InternalsVisibleTo("RageCoop.ResourceBuilder")]
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
internal static class CoreUtils
|
||||
{
|
||||
private static Random random = new Random();
|
||||
public static string FormatToSharpStyle(string input,int offset=14)
|
||||
{
|
||||
var ss = input.Substring(offset).Split("_".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
||||
// Replace first character with upper case
|
||||
for (int i = 0; i < ss.Length; i++)
|
||||
{
|
||||
var sec = ss[i].ToLower();
|
||||
var head = sec[0];
|
||||
ss[i] = head.ToString().ToUpper() + sec.Remove(0, 1);
|
||||
}
|
||||
return string.Join("", ss);
|
||||
}
|
||||
public static string ToHex(this int value)
|
||||
{
|
||||
return String.Format("0x{0:X}", value);
|
||||
}
|
||||
public static string ToHex(this uint value)
|
||||
{
|
||||
return String.Format("0x{0:X}", value);
|
||||
}
|
||||
private static readonly HashSet<string> ToIgnore = new HashSet<string>()
|
||||
{
|
||||
"RageCoop.Client",
|
||||
@ -35,16 +57,37 @@ namespace RageCoop.Core
|
||||
"ScriptHookVDotNet3",
|
||||
"ScriptHookVDotNet"
|
||||
};
|
||||
public static int RandInt(int start,int end)
|
||||
{
|
||||
return random.Next(start, end);
|
||||
}
|
||||
public static string GetTempDirectory(string dir = null)
|
||||
{
|
||||
dir = dir ?? Path.GetTempPath();
|
||||
string path;
|
||||
do
|
||||
{
|
||||
path = Path.Combine(dir, RandomString(10));
|
||||
} while (Directory.Exists(path) || File.Exists(path));
|
||||
|
||||
return path;
|
||||
}
|
||||
public static string RandomString(int length)
|
||||
{
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
return new string(Enumerable.Repeat(chars, length)
|
||||
.Select(s => s[random.Next(s.Length)]).ToArray());
|
||||
}
|
||||
public static void GetDependencies(Assembly assembly, ref HashSet<string> existing)
|
||||
{
|
||||
if (assembly.FullName.StartsWith("System")) { return; }
|
||||
foreach(var name in assembly.GetReferencedAssemblies())
|
||||
foreach (var name in assembly.GetReferencedAssemblies())
|
||||
{
|
||||
if (name.FullName.StartsWith("System")) { continue; }
|
||||
try
|
||||
{
|
||||
var asm = Assembly.Load(name);
|
||||
GetDependencies(asm,ref existing);
|
||||
GetDependencies(asm, ref existing);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ 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 = null)
|
||||
{
|
||||
if (File.Exists(destination)) { File.Delete(destination); }
|
||||
AutoResetEvent ae = new AutoResetEvent(false);
|
||||
|
@ -15,6 +15,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RageCoop.Client.Loader", "C
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{531656CF-7269-488D-B042-741BC96C3941}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{12E29AB7-74C4-4250-8975-C02D7FFC2D7B}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -15,7 +15,7 @@ using System.Resources;
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Version information
|
||||
[assembly: AssemblyVersion("1.5.6.1")]
|
||||
[assembly: AssemblyFileVersion("1.5.6.1")]
|
||||
[assembly: AssemblyVersion("1.5.6.12")]
|
||||
[assembly: AssemblyFileVersion("1.5.6.12")]
|
||||
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user