Clean up
This commit is contained in:
@ -3,7 +3,7 @@
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Class providing support for addon mods
|
||||
/// Class providing support for addon mods
|
||||
/// </summary>
|
||||
internal class AddOnDataProvider
|
||||
{
|
||||
@ -56,4 +56,4 @@ namespace RageCoop.Client
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +1,19 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using RageCoop.Core;
|
||||
using SHVDN;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal unsafe class MemPatch
|
||||
{
|
||||
private readonly IntPtr _address;
|
||||
private readonly byte[] _data;
|
||||
private readonly byte[] _orginal;
|
||||
private readonly IntPtr _address;
|
||||
|
||||
public MemPatch(byte* address, byte[] data)
|
||||
{
|
||||
_data = data;
|
||||
@ -21,10 +21,12 @@ namespace RageCoop.Client
|
||||
_address = (IntPtr)address;
|
||||
Marshal.Copy((IntPtr)address, _orginal, 0, data.Length);
|
||||
}
|
||||
|
||||
public void Install()
|
||||
{
|
||||
Marshal.Copy(_data, 0, _address, _data.Length);
|
||||
}
|
||||
|
||||
public void Uninstall()
|
||||
{
|
||||
Marshal.Copy(_orginal, 0, _address, _orginal.Length);
|
||||
@ -36,68 +38,95 @@ namespace RageCoop.Client
|
||||
public static MemPatch VignettingPatch;
|
||||
public static MemPatch VignettingCallPatch;
|
||||
public static MemPatch TimeScalePatch;
|
||||
|
||||
static 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"); }
|
||||
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 });
|
||||
|
||||
}
|
||||
|
||||
public static void ApplyPatches()
|
||||
{
|
||||
VignettingPatch.Install();
|
||||
VignettingCallPatch.Install();
|
||||
TimeScalePatch.Install();
|
||||
}
|
||||
|
||||
public static void RestorePatches()
|
||||
{
|
||||
VignettingPatch.Uninstall();
|
||||
VignettingCallPatch.Uninstall();
|
||||
TimeScalePatch.Uninstall();
|
||||
}
|
||||
#region PATCHES
|
||||
#endregion
|
||||
#region OFFSET-CONST
|
||||
public const int PositionOffset = 144;
|
||||
public const int VelocityOffset = 800;
|
||||
public const int MatrixOffset = 96;
|
||||
#endregion
|
||||
#region OPCODE
|
||||
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 ReadPosition(this Entity e)
|
||||
{
|
||||
return ReadVector3(e.MemoryAddress + PositionOffset);
|
||||
}
|
||||
|
||||
public static Quaternion ReadQuaternion(this Entity e)
|
||||
{
|
||||
return Quaternion.RotationMatrix(e.Matrix);
|
||||
}
|
||||
|
||||
public static Vector3 ReadRotation(this Entity e)
|
||||
{
|
||||
return e.ReadQuaternion().ToEulerDegrees();
|
||||
}
|
||||
|
||||
public static Vector3 ReadVelocity(this Ped e)
|
||||
{
|
||||
return ReadVector3(e.MemoryAddress + VelocityOffset);
|
||||
}
|
||||
|
||||
public static Vector3 ReadVector3(IntPtr address)
|
||||
{
|
||||
float* ptr = (float*)address.ToPointer();
|
||||
return new Vector3()
|
||||
var ptr = (float*)address.ToPointer();
|
||||
return new Vector3
|
||||
{
|
||||
X = *ptr,
|
||||
Y = ptr[1],
|
||||
Z = ptr[2]
|
||||
};
|
||||
}
|
||||
|
||||
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++)
|
||||
for (var i = 0; i <= range; i++)
|
||||
{
|
||||
var val = NativeMemory.ReadFloat(start + i);
|
||||
if (Math.Abs(val - toSearch) < tolerance)
|
||||
{
|
||||
foundOffsets.Add(i);
|
||||
}
|
||||
if (Math.Abs(val - toSearch) < tolerance) foundOffsets.Add(i);
|
||||
}
|
||||
|
||||
return foundOffsets;
|
||||
}
|
||||
|
||||
#region PATCHES
|
||||
|
||||
#endregion
|
||||
|
||||
#region OFFSET-CONST
|
||||
|
||||
public const int PositionOffset = 144;
|
||||
public const int VelocityOffset = 800;
|
||||
public const int MatrixOffset = 96;
|
||||
|
||||
#endregion
|
||||
|
||||
#region OPCODE
|
||||
|
||||
private const byte XOR_32_64 = 0x31;
|
||||
private const byte RET = 0xC3;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
@ -1,62 +1,52 @@
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using System;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit, Size = 80)]
|
||||
public struct HeadBlendData
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public int ShapeFirst;
|
||||
[FieldOffset(0)] public int ShapeFirst;
|
||||
|
||||
[FieldOffset(8)]
|
||||
public int ShapeSecond;
|
||||
[FieldOffset(8)] public int ShapeSecond;
|
||||
|
||||
[FieldOffset(16)]
|
||||
public int ShapeThird;
|
||||
[FieldOffset(16)] public int ShapeThird;
|
||||
|
||||
[FieldOffset(24)]
|
||||
public int SkinFirst;
|
||||
[FieldOffset(24)] public int SkinFirst;
|
||||
|
||||
[FieldOffset(32)]
|
||||
public int SkinSecond;
|
||||
[FieldOffset(32)] public int SkinSecond;
|
||||
|
||||
[FieldOffset(40)]
|
||||
public int SkinThird;
|
||||
[FieldOffset(40)] public int SkinThird;
|
||||
|
||||
[FieldOffset(48)]
|
||||
public float ShapeMix;
|
||||
[FieldOffset(48)] public float ShapeMix;
|
||||
|
||||
[FieldOffset(56)]
|
||||
public float SkinMix;
|
||||
[FieldOffset(56)] public float SkinMix;
|
||||
|
||||
[FieldOffset(64)]
|
||||
public float ThirdMix;
|
||||
[FieldOffset(64)] public float ThirdMix;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 24)]
|
||||
public struct NativeVector3
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public float X;
|
||||
[FieldOffset(0)] public float X;
|
||||
|
||||
[FieldOffset(8)]
|
||||
public float Y;
|
||||
[FieldOffset(8)] public float Y;
|
||||
|
||||
[FieldOffset(16)]
|
||||
public float Z;
|
||||
[FieldOffset(16)] public float Z;
|
||||
|
||||
public static implicit operator Vector3(NativeVector3 vec)
|
||||
{
|
||||
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
|
||||
@ -80,8 +70,9 @@ namespace RageCoop.Client
|
||||
public static unsafe R Invoke<R>(ulong hash) where R : unmanaged
|
||||
{
|
||||
NativeInit(hash);
|
||||
return *(R*)(NativeCall());
|
||||
return *(R*)NativeCall();
|
||||
}
|
||||
|
||||
public static unsafe R Invoke<R>(Hash hash, params object[] args)
|
||||
where R : unmanaged
|
||||
{
|
||||
@ -90,45 +81,50 @@ namespace RageCoop.Client
|
||||
foreach (var arg in arguments)
|
||||
NativePush(arg);
|
||||
|
||||
return *(R*)(NativeCall());
|
||||
return *(R*)NativeCall();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Helper function that converts an array of primitive values to a native stack.
|
||||
/// Helper function that converts an array of primitive values to a native stack.
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
private static unsafe ulong[] ConvertPrimitiveArguments(object[] args)
|
||||
{
|
||||
var result = new ulong[args.Length];
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
for (var i = 0; i < args.Length; ++i)
|
||||
{
|
||||
if (args[i] is bool valueBool)
|
||||
{
|
||||
result[i] = valueBool ? 1ul : 0ul;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (args[i] is byte valueByte)
|
||||
{
|
||||
result[i] = valueByte;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (args[i] is int valueInt32)
|
||||
{
|
||||
result[i] = (ulong)valueInt32;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (args[i] is ulong valueUInt64)
|
||||
{
|
||||
result[i] = valueUInt64;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (args[i] is float valueFloat)
|
||||
{
|
||||
result[i] = *(ulong*)&valueFloat;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (args[i] is IntPtr valueIntPtr)
|
||||
{
|
||||
result[i] = (ulong)valueIntPtr.ToInt64();
|
||||
@ -141,5 +137,4 @@ namespace RageCoop.Client
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -460,6 +460,6 @@
|
||||
_0x1D19C622 = 454,
|
||||
_0xB68D3EAB = 455,
|
||||
CPED_CONFIG_FLAG_CanBeIncapacitated = 456,
|
||||
_0x4BD5EBAD = 457,
|
||||
_0x4BD5EBAD = 457
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,14 @@
|
||||
using GTA;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static partial class PedExtensions
|
||||
internal static class PedExtensions
|
||||
{
|
||||
|
||||
public static bool IsBetween<T>(this T item, T start, T end)
|
||||
{
|
||||
return Comparer<T>.Default.Compare(item, start) >= 0 && Comparer<T>.Default.Compare(item, end) <= 0;
|
||||
@ -17,17 +16,11 @@ namespace RageCoop.Client
|
||||
|
||||
public static bool Compare<T, Y>(this Dictionary<T, Y> item, Dictionary<T, Y> item2)
|
||||
{
|
||||
if (item == null || item2 == null || item.Count != item2.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (item == null || item2 == null || item.Count != item2.Count) return false;
|
||||
|
||||
foreach (KeyValuePair<T, Y> pair in item)
|
||||
foreach (var pair in item)
|
||||
{
|
||||
if (item2.TryGetValue(pair.Key, out Y value) && Equals(value, pair.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (item2.TryGetValue(pair.Key, out var value) && Equals(value, pair.Value)) continue;
|
||||
|
||||
// TryGetValue() or Equals failed
|
||||
return false;
|
||||
@ -38,37 +31,141 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
|
||||
public static Vector3 RaycastEverything(Vector2 screenCoord)
|
||||
{
|
||||
var camPos = GameplayCamera.Position;
|
||||
var camRot = GameplayCamera.Rotation;
|
||||
const float raycastToDist = 100.0f;
|
||||
const float raycastFromDist = 1f;
|
||||
|
||||
var target3D = ScreenRelToWorld(camPos, camRot, screenCoord);
|
||||
var source3D = camPos;
|
||||
|
||||
Entity ignoreEntity = Game.Player.Character;
|
||||
if (Game.Player.Character.IsInVehicle()) ignoreEntity = Game.Player.Character.CurrentVehicle;
|
||||
|
||||
var dir = target3D - source3D;
|
||||
dir.Normalize();
|
||||
var raycastResults = World.Raycast(source3D + dir * raycastFromDist,
|
||||
source3D + dir * raycastToDist,
|
||||
IntersectFlags.Everything,
|
||||
ignoreEntity);
|
||||
|
||||
if (raycastResults.DidHit) return raycastResults.HitPosition;
|
||||
|
||||
return camPos + dir * raycastToDist;
|
||||
}
|
||||
|
||||
public static Vector3 ScreenRelToWorld(Vector3 camPos, Vector3 camRot, Vector2 coord)
|
||||
{
|
||||
var camForward = camRot.ToDirection();
|
||||
var rotUp = camRot + new Vector3(10, 0, 0);
|
||||
var rotDown = camRot + new Vector3(-10, 0, 0);
|
||||
var rotLeft = camRot + new Vector3(0, 0, -10);
|
||||
var rotRight = camRot + new Vector3(0, 0, 10);
|
||||
|
||||
var camRight = rotRight.ToDirection() - rotLeft.ToDirection();
|
||||
var camUp = rotUp.ToDirection() - rotDown.ToDirection();
|
||||
|
||||
double rollRad = -camRot.Y.ToRadians();
|
||||
|
||||
var camRightRoll = camRight * (float)Math.Cos(rollRad) - camUp * (float)Math.Sin(rollRad);
|
||||
var camUpRoll = camRight * (float)Math.Sin(rollRad) + camUp * (float)Math.Cos(rollRad);
|
||||
|
||||
var point3D = camPos + camForward * 10.0f + camRightRoll + camUpRoll;
|
||||
if (!WorldToScreenRel(point3D, out var point2D)) return camPos + camForward * 10.0f;
|
||||
|
||||
var point3DZero = camPos + camForward * 10.0f;
|
||||
if (!WorldToScreenRel(point3DZero, out var point2DZero)) return camPos + camForward * 10.0f;
|
||||
|
||||
const double eps = 0.001;
|
||||
if (Math.Abs(point2D.X - point2DZero.X) < eps || Math.Abs(point2D.Y - point2DZero.Y) < eps)
|
||||
return camPos + camForward * 10.0f;
|
||||
|
||||
var scaleX = (coord.X - point2DZero.X) / (point2D.X - point2DZero.X);
|
||||
var scaleY = (coord.Y - point2DZero.Y) / (point2D.Y - point2DZero.Y);
|
||||
|
||||
return camPos + camForward * 10.0f + camRightRoll * scaleX + camUpRoll * scaleY;
|
||||
}
|
||||
|
||||
public static bool WorldToScreenRel(Vector3 worldCoords, out Vector2 screenCoords)
|
||||
{
|
||||
var num1 = new OutputArgument();
|
||||
var num2 = new OutputArgument();
|
||||
|
||||
if (!Function.Call<bool>(Hash.GET_SCREEN_COORD_FROM_WORLD_COORD, worldCoords.X, worldCoords.Y,
|
||||
worldCoords.Z, num1, num2))
|
||||
{
|
||||
screenCoords = new Vector2();
|
||||
return false;
|
||||
}
|
||||
|
||||
screenCoords = new Vector2((num1.GetResult<float>() - 0.5f) * 2, (num2.GetResult<float>() - 0.5f) * 2);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void StayInCover(this Ped p)
|
||||
{
|
||||
Function.Call(Hash.TASK_STAY_IN_COVER, p);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
switch (seat)
|
||||
{
|
||||
case -1:
|
||||
return (VehicleHash)veh.Model.Hash == VehicleHash.Rhino
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Khanjari
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.FireTruck
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Riot2
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus2
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus3;
|
||||
case 0:
|
||||
return (VehicleHash)veh.Model.Hash == VehicleHash.Apc
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Dune3;
|
||||
case 1:
|
||||
return (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie2
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical2
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical3
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.HalfTrack
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Barrage;
|
||||
case 2:
|
||||
return (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie2
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Barrage;
|
||||
case 3:
|
||||
return (VehicleHash)veh.Model.Hash == VehicleHash.Limo2
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Dinghy5;
|
||||
case 7:
|
||||
return (VehicleHash)veh.Model.Hash == VehicleHash.Insurgent;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsOnTurretSeat(this Ped P)
|
||||
{
|
||||
if (P.CurrentVehicle == null) return false;
|
||||
return IsTurretSeat(P.CurrentVehicle, (int)P.SeatIndex);
|
||||
}
|
||||
|
||||
|
||||
#region PED
|
||||
|
||||
public static byte GetPedSpeed(this Ped ped)
|
||||
{
|
||||
|
||||
if (ped.IsSittingInVehicle())
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
if (ped.IsTaskActive(TaskType.CTaskEnterVehicle))
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
if (ped.IsTaskActive(TaskType.CTaskExitVehicle))
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
if (ped.IsWalking)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (ped.IsRunning)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
if (ped.IsSprinting)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
if (ped.IsSittingInVehicle()) return 4;
|
||||
if (ped.IsTaskActive(TaskType.CTaskEnterVehicle)) return 5;
|
||||
if (ped.IsTaskActive(TaskType.CTaskExitVehicle)) return 6;
|
||||
if (ped.IsWalking) return 1;
|
||||
if (ped.IsRunning) return 2;
|
||||
if (ped.IsSprinting) return 3;
|
||||
|
||||
|
||||
return 0;
|
||||
@ -84,87 +181,46 @@ namespace RageCoop.Client
|
||||
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;
|
||||
}
|
||||
|
||||
public static PedDataFlags GetPedFlags(this Ped ped)
|
||||
{
|
||||
PedDataFlags flags = PedDataFlags.None;
|
||||
var flags = PedDataFlags.None;
|
||||
|
||||
if (ped.IsAiming || ped.IsOnTurretSeat())
|
||||
{
|
||||
flags |= PedDataFlags.IsAiming;
|
||||
}
|
||||
if (ped.IsAiming || ped.IsOnTurretSeat()) flags |= PedDataFlags.IsAiming;
|
||||
|
||||
|
||||
if (ped.IsReloading)
|
||||
{
|
||||
flags |= PedDataFlags.IsReloading;
|
||||
}
|
||||
if (ped.IsReloading) flags |= PedDataFlags.IsReloading;
|
||||
|
||||
if (ped.IsJumping)
|
||||
{
|
||||
flags |= PedDataFlags.IsJumping;
|
||||
}
|
||||
if (ped.IsJumping) flags |= PedDataFlags.IsJumping;
|
||||
|
||||
// Fake death
|
||||
if (ped.IsRagdoll || (ped.Health == 1 && ped.IsPlayer))
|
||||
{
|
||||
flags |= PedDataFlags.IsRagdoll;
|
||||
}
|
||||
if (ped.IsRagdoll || (ped.Health == 1 && ped.IsPlayer)) flags |= PedDataFlags.IsRagdoll;
|
||||
|
||||
if (ped.IsOnFire)
|
||||
{
|
||||
flags |= PedDataFlags.IsOnFire;
|
||||
}
|
||||
if (ped.IsOnFire) flags |= PedDataFlags.IsOnFire;
|
||||
|
||||
if (ped.IsInParachuteFreeFall)
|
||||
{
|
||||
flags |= PedDataFlags.IsInParachuteFreeFall;
|
||||
}
|
||||
if (ped.IsInParachuteFreeFall) flags |= PedDataFlags.IsInParachuteFreeFall;
|
||||
|
||||
if (ped.ParachuteState == ParachuteState.Gliding)
|
||||
{
|
||||
flags |= PedDataFlags.IsParachuteOpen;
|
||||
}
|
||||
if (ped.ParachuteState == ParachuteState.Gliding) flags |= PedDataFlags.IsParachuteOpen;
|
||||
|
||||
bool climbingLadder = ped.IsTaskActive(TaskType.CTaskGoToAndClimbLadder);
|
||||
if (climbingLadder)
|
||||
{
|
||||
flags |= PedDataFlags.IsOnLadder;
|
||||
}
|
||||
var climbingLadder = ped.IsTaskActive(TaskType.CTaskGoToAndClimbLadder);
|
||||
if (climbingLadder) flags |= PedDataFlags.IsOnLadder;
|
||||
|
||||
if (ped.IsVaulting && !climbingLadder)
|
||||
{
|
||||
flags |= PedDataFlags.IsVaulting;
|
||||
}
|
||||
if (ped.IsVaulting && !climbingLadder) flags |= PedDataFlags.IsVaulting;
|
||||
|
||||
if (ped.IsInCover || ped.IsGoingIntoCover)
|
||||
{
|
||||
flags |= PedDataFlags.IsInCover;
|
||||
if (ped.IsInCoverFacingLeft)
|
||||
{
|
||||
flags |= PedDataFlags.IsInCover;
|
||||
}
|
||||
if (!Function.Call<bool>(Hash.IS_PED_IN_HIGH_COVER, ped))
|
||||
{
|
||||
flags |= PedDataFlags.IsInLowCover;
|
||||
}
|
||||
if (ped.IsTaskActive(TaskType.CTaskAimGunBlindFire))
|
||||
{
|
||||
flags |= PedDataFlags.IsBlindFiring;
|
||||
}
|
||||
if (ped.IsInCoverFacingLeft) flags |= PedDataFlags.IsInCover;
|
||||
if (!Function.Call<bool>(Hash.IS_PED_IN_HIGH_COVER, ped)) flags |= PedDataFlags.IsInLowCover;
|
||||
if (ped.IsTaskActive(TaskType.CTaskAimGunBlindFire)) flags |= PedDataFlags.IsBlindFiring;
|
||||
}
|
||||
|
||||
if (ped.IsInvincible)
|
||||
{
|
||||
flags |= PedDataFlags.IsInvincible;
|
||||
}
|
||||
if (ped.IsInvincible) flags |= PedDataFlags.IsInvincible;
|
||||
|
||||
if (Function.Call<bool>(Hash.GET_PED_STEALTH_MOVEMENT, ped))
|
||||
{
|
||||
flags |= PedDataFlags.IsInStealthMode;
|
||||
}
|
||||
if (Function.Call<bool>(Hash.GET_PED_STEALTH_MOVEMENT, ped)) flags |= PedDataFlags.IsInStealthMode;
|
||||
|
||||
|
||||
return flags;
|
||||
@ -253,31 +309,34 @@ namespace RageCoop.Client
|
||||
case WeaponHash.MG:
|
||||
return new string[2] { "weapons@machinegun@mg_str", "reload_aim" };
|
||||
default:
|
||||
Main.Logger.Warning($"~r~Reloading failed! Weapon ~g~[{ped.Weapons.Current.Hash}]~r~ could not be found!");
|
||||
Main.Logger.Warning(
|
||||
$"~r~Reloading failed! Weapon ~g~[{ped.Weapons.Current.Hash}]~r~ could not be found!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static VehicleSeat GetNearestSeat(this Ped ped, Vehicle veh, float distanceToignoreDoors = 50f)
|
||||
{
|
||||
float num = 99f;
|
||||
int result = -2;
|
||||
Dictionary<string, int> dictionary = new Dictionary<string, int>();
|
||||
var num = 99f;
|
||||
var result = -2;
|
||||
var dictionary = new Dictionary<string, int>();
|
||||
dictionary.Add("door_dside_f", -1);
|
||||
dictionary.Add("door_pside_f", 0);
|
||||
dictionary.Add("door_dside_r", 1);
|
||||
dictionary.Add("door_pside_r", 2);
|
||||
foreach (string text in dictionary.Keys)
|
||||
foreach (var text in dictionary.Keys)
|
||||
{
|
||||
bool flag = veh.Bones[text].Position != Vector3.Zero;
|
||||
var flag = veh.Bones[text].Position != Vector3.Zero;
|
||||
if (flag)
|
||||
{
|
||||
float num2 = ped.Position.DistanceTo(Function.Call<Vector3>(Hash.GET_WORLD_POSITION_OF_ENTITY_BONE, new InputArgument[]
|
||||
{
|
||||
veh,
|
||||
veh.Bones[text].Index
|
||||
}));
|
||||
bool flag2 = (num2 < distanceToignoreDoors) && (num2 < num) && IsSeatUsableByPed(ped, veh, dictionary[text]);
|
||||
var num2 = ped.Position.DistanceTo(Function.Call<Vector3>(Hash.GET_WORLD_POSITION_OF_ENTITY_BONE,
|
||||
new InputArgument[]
|
||||
{
|
||||
veh,
|
||||
veh.Bones[text].Index
|
||||
}));
|
||||
var flag2 = num2 < distanceToignoreDoors && num2 < num &&
|
||||
IsSeatUsableByPed(ped, veh, dictionary[text]);
|
||||
if (flag2)
|
||||
{
|
||||
num = num2;
|
||||
@ -285,46 +344,46 @@ namespace RageCoop.Client
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (VehicleSeat)result;
|
||||
}
|
||||
|
||||
public static bool IsSeatUsableByPed(Ped ped, Vehicle veh, int _seat)
|
||||
{
|
||||
VehicleSeat seat = (VehicleSeat)_seat;
|
||||
bool result = false;
|
||||
bool flag = veh.IsSeatFree(seat);
|
||||
var seat = (VehicleSeat)_seat;
|
||||
var result = false;
|
||||
var flag = veh.IsSeatFree(seat);
|
||||
if (flag)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
bool isDead = veh.GetPedOnSeat(seat).IsDead;
|
||||
var isDead = veh.GetPedOnSeat(seat).IsDead;
|
||||
if (isDead)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int num = Function.Call<int>(Hash.GET_RELATIONSHIP_BETWEEN_PEDS, new InputArgument[]
|
||||
var num = Function.Call<int>(Hash.GET_RELATIONSHIP_BETWEEN_PEDS, new InputArgument[]
|
||||
{
|
||||
ped,
|
||||
veh.GetPedOnSeat(seat)
|
||||
});
|
||||
bool flag2 = num > 2;
|
||||
if (flag2)
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
var flag2 = num > 2;
|
||||
if (flag2) result = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool IsTaskActive(this Ped p, TaskType task)
|
||||
{
|
||||
return Function.Call<bool>(Hash.GET_IS_TASK_ACTIVE, p.Handle, task);
|
||||
}
|
||||
|
||||
public static Vector3 GetAimCoord(this Ped p)
|
||||
{
|
||||
Prop weapon;
|
||||
@ -332,183 +391,35 @@ namespace RageCoop.Client
|
||||
EntityBone b;
|
||||
if (p.IsOnTurretSeat())
|
||||
{
|
||||
if((b = p.CurrentVehicle.GetMuzzleBone(p.VehicleWeapon)) != null)
|
||||
{
|
||||
if ((b = p.CurrentVehicle.GetMuzzleBone(p.VehicleWeapon)) != null)
|
||||
return b.Position + b.ForwardVector * 50;
|
||||
}
|
||||
return GetLookingCoord(p);
|
||||
}
|
||||
if ((weapon= p.Weapons.CurrentWeaponObject) != null)
|
||||
|
||||
if ((weapon = p.Weapons.CurrentWeaponObject) != null)
|
||||
{
|
||||
// Not very accurate, but doesn't matter
|
||||
Vector3 dir = weapon.RightVector;
|
||||
var dir = weapon.RightVector;
|
||||
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)
|
||||
{
|
||||
return RaycastEverything(default);
|
||||
}
|
||||
EntityBone b = p.Bones[Bone.FacialForehead];
|
||||
Vector3 v = b.UpVector.Normalized;
|
||||
var v = b.UpVector.Normalized;
|
||||
return b.Position + 200 * v;
|
||||
}
|
||||
|
||||
public static VehicleSeat GetSeatTryingToEnter(this Ped p)
|
||||
{
|
||||
return (VehicleSeat)Function.Call<int>(Hash.GET_SEAT_PED_IS_TRYING_TO_ENTER, p);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static Vector3 RaycastEverything(Vector2 screenCoord)
|
||||
{
|
||||
Vector3 camPos = GameplayCamera.Position;
|
||||
Vector3 camRot = GameplayCamera.Rotation;
|
||||
const float raycastToDist = 100.0f;
|
||||
const float raycastFromDist = 1f;
|
||||
|
||||
Vector3 target3D = ScreenRelToWorld(camPos, camRot, screenCoord);
|
||||
Vector3 source3D = camPos;
|
||||
|
||||
Entity ignoreEntity = Game.Player.Character;
|
||||
if (Game.Player.Character.IsInVehicle())
|
||||
{
|
||||
ignoreEntity = Game.Player.Character.CurrentVehicle;
|
||||
}
|
||||
|
||||
Vector3 dir = target3D - source3D;
|
||||
dir.Normalize();
|
||||
RaycastResult raycastResults = World.Raycast(source3D + dir * raycastFromDist,
|
||||
source3D + dir * raycastToDist,
|
||||
IntersectFlags.Everything,
|
||||
ignoreEntity);
|
||||
|
||||
if (raycastResults.DidHit)
|
||||
{
|
||||
return raycastResults.HitPosition;
|
||||
}
|
||||
|
||||
return camPos + dir * raycastToDist;
|
||||
}
|
||||
public static Vector3 ScreenRelToWorld(Vector3 camPos, Vector3 camRot, Vector2 coord)
|
||||
{
|
||||
Vector3 camForward = camRot.ToDirection();
|
||||
Vector3 rotUp = camRot + new Vector3(10, 0, 0);
|
||||
Vector3 rotDown = camRot + new Vector3(-10, 0, 0);
|
||||
Vector3 rotLeft = camRot + new Vector3(0, 0, -10);
|
||||
Vector3 rotRight = camRot + new Vector3(0, 0, 10);
|
||||
|
||||
Vector3 camRight = rotRight.ToDirection() - rotLeft.ToDirection();
|
||||
Vector3 camUp = rotUp.ToDirection() - rotDown.ToDirection();
|
||||
|
||||
double rollRad = -camRot.Y.ToRadians();
|
||||
|
||||
Vector3 camRightRoll = camRight * (float)Math.Cos(rollRad) - camUp * (float)Math.Sin(rollRad);
|
||||
Vector3 camUpRoll = camRight * (float)Math.Sin(rollRad) + camUp * (float)Math.Cos(rollRad);
|
||||
|
||||
Vector3 point3D = camPos + camForward * 10.0f + camRightRoll + camUpRoll;
|
||||
if (!WorldToScreenRel(point3D, out Vector2 point2D))
|
||||
{
|
||||
return camPos + camForward * 10.0f;
|
||||
}
|
||||
|
||||
Vector3 point3DZero = camPos + camForward * 10.0f;
|
||||
if (!WorldToScreenRel(point3DZero, out Vector2 point2DZero))
|
||||
{
|
||||
return camPos + camForward * 10.0f;
|
||||
}
|
||||
|
||||
const double eps = 0.001;
|
||||
if (Math.Abs(point2D.X - point2DZero.X) < eps || Math.Abs(point2D.Y - point2DZero.Y) < eps)
|
||||
{
|
||||
return camPos + camForward * 10.0f;
|
||||
}
|
||||
|
||||
float scaleX = (coord.X - point2DZero.X) / (point2D.X - point2DZero.X);
|
||||
float scaleY = (coord.Y - point2DZero.Y) / (point2D.Y - point2DZero.Y);
|
||||
|
||||
return camPos + camForward * 10.0f + camRightRoll * scaleX + camUpRoll * scaleY;
|
||||
}
|
||||
public static bool WorldToScreenRel(Vector3 worldCoords, out Vector2 screenCoords)
|
||||
{
|
||||
OutputArgument num1 = new OutputArgument();
|
||||
OutputArgument num2 = new OutputArgument();
|
||||
|
||||
if (!Function.Call<bool>(Hash.GET_SCREEN_COORD_FROM_WORLD_COORD, worldCoords.X, worldCoords.Y, worldCoords.Z, num1, num2))
|
||||
{
|
||||
screenCoords = new Vector2();
|
||||
return false;
|
||||
}
|
||||
|
||||
screenCoords = new Vector2((num1.GetResult<float>() - 0.5f) * 2, (num2.GetResult<float>() - 0.5f) * 2);
|
||||
return true;
|
||||
}
|
||||
public static void StayInCover(this Ped p)
|
||||
{
|
||||
Function.Call(Hash.TASK_STAY_IN_COVER, p);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
switch (seat)
|
||||
{
|
||||
case -1:
|
||||
return (VehicleHash)veh.Model.Hash == VehicleHash.Rhino
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Khanjari
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.FireTruck
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Riot2
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus2
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus3;
|
||||
case 0:
|
||||
return (VehicleHash)veh.Model.Hash == VehicleHash.Apc
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Dune3;
|
||||
case 1:
|
||||
return (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie2
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical2
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical3
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.HalfTrack
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Barrage;
|
||||
case 2:
|
||||
return (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie2
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Barrage;
|
||||
case 3:
|
||||
return (VehicleHash)veh.Model.Hash == VehicleHash.Limo2
|
||||
|| (VehicleHash)veh.Model.Hash == VehicleHash.Dinghy5;
|
||||
case 7:
|
||||
return (VehicleHash)veh.Model.Hash == VehicleHash.Insurgent;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public static bool IsOnTurretSeat(this Ped P)
|
||||
{
|
||||
if (P.CurrentVehicle == null) { return false; }
|
||||
return IsTurretSeat(P.CurrentVehicle, (int)P.SeatIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// WARNING: values can change after a game update
|
||||
// if R* adds in the middle!
|
||||
// This is up-to-date for b2372
|
||||
|
||||
internal enum TaskType
|
||||
{
|
||||
CTaskHandsUp = 0,
|
||||
@ -435,4 +436,4 @@ internal enum TaskType
|
||||
CTaskVehiclePullAlongside = 528,
|
||||
CTaskVehicleTransformToSubmarine = 529,
|
||||
CTaskAnimatedFallback = 530
|
||||
};
|
||||
}
|
@ -1,52 +1,63 @@
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using LemonUI.Elements;
|
||||
using Newtonsoft.Json;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using GTA.UI;
|
||||
using LemonUI.Elements;
|
||||
using Newtonsoft.Json;
|
||||
using RageCoop.Core;
|
||||
using Font = GTA.UI.Font;
|
||||
|
||||
[assembly: InternalsVisibleTo("RageCoop.Client.Installer")]
|
||||
|
||||
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)
|
||||
{
|
||||
var error = $"Client not loaded with loader, please re-install using the installer to fix this issue";
|
||||
try
|
||||
{
|
||||
GTA.UI.Notification.Show("~r~" + error);
|
||||
}
|
||||
catch { }
|
||||
throw new Exception(error);
|
||||
}
|
||||
}
|
||||
public static string SettingsPath = "RageCoop\\Settings.json";
|
||||
|
||||
public static SizeF ResolutionMaintainRatio
|
||||
{
|
||||
get
|
||||
{
|
||||
// Get the game width and height
|
||||
int screenw = GTA.UI.Screen.Resolution.Width;
|
||||
int screenh = GTA.UI.Screen.Resolution.Height;
|
||||
var screenw = Screen.Resolution.Width;
|
||||
var screenh = Screen.Resolution.Height;
|
||||
// Calculate the ratio
|
||||
float ratio = (float)screenw / screenh;
|
||||
var ratio = (float)screenw / screenh;
|
||||
// And the width with that ratio
|
||||
float width = 1080f * ratio;
|
||||
var width = 1080f * ratio;
|
||||
// Finally, return a SizeF
|
||||
return new SizeF(width, 1080f);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var error = "Client not loaded with loader, please re-install using the installer to fix this issue";
|
||||
try
|
||||
{
|
||||
Notification.Show("~r~" + error);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
throw new Exception(error);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawTextFromCoord(Vector3 coord, string text, float scale = 0.5f, Point offset = default)
|
||||
{
|
||||
Point toDraw = default;
|
||||
@ -54,14 +65,15 @@ namespace RageCoop.Client
|
||||
{
|
||||
toDraw.X += offset.X;
|
||||
toDraw.Y += offset.Y;
|
||||
new ScaledText(toDraw, text, scale, GTA.UI.Font.ChaletLondon)
|
||||
new ScaledText(toDraw, text, scale, Font.ChaletLondon)
|
||||
{
|
||||
Outline = true,
|
||||
Alignment = GTA.UI.Alignment.Center,
|
||||
Color = Color.White,
|
||||
Alignment = Alignment.Center,
|
||||
Color = Color.White
|
||||
}.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool WorldToScreen(Vector3 pos, ref Point screenPos)
|
||||
{
|
||||
float x, y;
|
||||
@ -74,74 +86,10 @@ namespace RageCoop.Client
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#region -- POINTER --
|
||||
private static int _steeringAngleOffset { get; set; }
|
||||
|
||||
public static unsafe void NativeMemory()
|
||||
{
|
||||
IntPtr address;
|
||||
|
||||
address = Game.FindPattern("\x74\x0A\xF3\x0F\x11\xB3\x1C\x09\x00\x00\xEB\x25", "xxxxxx????xx");
|
||||
if (address != IntPtr.Zero)
|
||||
{
|
||||
_steeringAngleOffset = *(int*)(address + 6) + 8;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static unsafe void CustomSteeringAngle(this Vehicle veh, float value)
|
||||
{
|
||||
IntPtr address = new IntPtr((long)veh.MemoryAddress);
|
||||
if (address == IntPtr.Zero || _steeringAngleOffset == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*(float*)(address + _steeringAngleOffset).ToPointer() = value;
|
||||
}
|
||||
#endregion
|
||||
#region MATH
|
||||
public static Vector3 LinearVectorLerp(Vector3 start, Vector3 end, ulong currentTime, int duration)
|
||||
{
|
||||
return new Vector3()
|
||||
{
|
||||
X = LinearFloatLerp(start.X, end.X, currentTime, duration),
|
||||
Y = LinearFloatLerp(start.Y, end.Y, currentTime, duration),
|
||||
Z = LinearFloatLerp(start.Z, end.Z, currentTime, duration),
|
||||
};
|
||||
}
|
||||
|
||||
public static float LinearFloatLerp(float start, float end, ulong currentTime, int duration)
|
||||
{
|
||||
return (end - start) * currentTime / duration + start;
|
||||
}
|
||||
|
||||
public static float Lerp(float from, float to, float fAlpha)
|
||||
{
|
||||
return (from * (1.0f - fAlpha)) + (to * fAlpha); //from + (to - from) * fAlpha
|
||||
}
|
||||
|
||||
public static Vector3 RotationToDirection(Vector3 rotation)
|
||||
{
|
||||
double z = MathExtensions.DegToRad(rotation.Z);
|
||||
double x = MathExtensions.DegToRad(rotation.X);
|
||||
double num = Math.Abs(Math.Cos(x));
|
||||
|
||||
return new Vector3
|
||||
{
|
||||
X = (float)(-Math.Sin(z) * num),
|
||||
Y = (float)(Math.Cos(z) * num),
|
||||
Z = (float)Math.Sin(x)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
public static string SettingsPath = "RageCoop\\Settings.json";
|
||||
public static Settings ReadSettings(string path = null)
|
||||
{
|
||||
path = path ?? SettingsPath;
|
||||
@ -160,6 +108,7 @@ namespace RageCoop.Client
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
public static bool SaveSettings(string path = null, Settings settings = null)
|
||||
{
|
||||
try
|
||||
@ -181,25 +130,26 @@ namespace RageCoop.Client
|
||||
|
||||
public static Vehicle CreateVehicle(Model model, Vector3 position, float heading = 0f)
|
||||
{
|
||||
if (!model.IsLoaded) { return null; }
|
||||
return (Vehicle)Entity.FromHandle(Function.Call<int>(Hash.CREATE_VEHICLE, model.Hash, position.X, position.Y, position.Z, heading, false, false));
|
||||
if (!model.IsLoaded) return null;
|
||||
return (Vehicle)Entity.FromHandle(Function.Call<int>(Hash.CREATE_VEHICLE, model.Hash, position.X,
|
||||
position.Y, position.Z, heading, false, false));
|
||||
}
|
||||
|
||||
public static Ped CreatePed(Model model, Vector3 position, float heading = 0f)
|
||||
{
|
||||
if (!model.IsLoaded) { return null; }
|
||||
return (Ped)Entity.FromHandle(Function.Call<int>(Hash.CREATE_PED, 26, model.Hash, position.X, position.Y, position.Z, heading, false, false));
|
||||
if (!model.IsLoaded) return null;
|
||||
return (Ped)Entity.FromHandle(Function.Call<int>(Hash.CREATE_PED, 26, model.Hash, position.X, position.Y,
|
||||
position.Z, heading, false, false));
|
||||
}
|
||||
|
||||
public static void SetOnFire(this Entity e, bool toggle)
|
||||
{
|
||||
if (toggle)
|
||||
{
|
||||
Function.Call(Hash.START_ENTITY_FIRE, e.Handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
Function.Call(Hash.STOP_ENTITY_FIRE, e.Handle);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetFrozen(this Entity e, bool toggle)
|
||||
{
|
||||
Function.Call(Hash.FREEZE_ENTITY_POSITION, e, toggle);
|
||||
@ -207,28 +157,32 @@ namespace RageCoop.Client
|
||||
|
||||
public static SyncedPed GetSyncEntity(this Ped p)
|
||||
{
|
||||
if (p == null) { return null; }
|
||||
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;
|
||||
}
|
||||
|
||||
public static SyncedVehicle GetSyncEntity(this Vehicle veh)
|
||||
{
|
||||
if (veh == null) { return null; }
|
||||
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;
|
||||
}
|
||||
|
||||
public static void ApplyForce(this Entity e, int boneIndex, Vector3 direction, Vector3 rotation = default(Vector3), ForceType forceType = ForceType.MaxForceRot2)
|
||||
public static void ApplyForce(this Entity e, int boneIndex, Vector3 direction, Vector3 rotation = default,
|
||||
ForceType forceType = ForceType.MaxForceRot2)
|
||||
{
|
||||
Function.Call(Hash.APPLY_FORCE_TO_ENTITY, e.Handle, forceType, direction.X, direction.Y, direction.Z, rotation.X, rotation.Y, rotation.Z, boneIndex, false, true, true, false, true);
|
||||
Function.Call(Hash.APPLY_FORCE_TO_ENTITY, e.Handle, forceType, direction.X, direction.Y, direction.Z,
|
||||
rotation.X, rotation.Y, rotation.Z, boneIndex, false, true, true, false, true);
|
||||
}
|
||||
|
||||
public static byte GetPlayerRadioIndex()
|
||||
{
|
||||
return (byte)Function.Call<int>(Hash.GET_PLAYER_RADIO_STATION_INDEX);
|
||||
}
|
||||
|
||||
public static void SetPlayerRadioIndex(int index)
|
||||
{
|
||||
Function.Call(Hash.SET_RADIO_TO_STATION_INDEX, index);
|
||||
@ -237,5 +191,66 @@ namespace RageCoop.Client
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern ulong GetTickCount64();
|
||||
|
||||
|
||||
#region -- POINTER --
|
||||
|
||||
private static int _steeringAngleOffset { get; set; }
|
||||
|
||||
public static unsafe void NativeMemory()
|
||||
{
|
||||
IntPtr address;
|
||||
|
||||
address = Game.FindPattern("\x74\x0A\xF3\x0F\x11\xB3\x1C\x09\x00\x00\xEB\x25", "xxxxxx????xx");
|
||||
if (address != IntPtr.Zero) _steeringAngleOffset = *(int*)(address + 6) + 8;
|
||||
}
|
||||
|
||||
public static unsafe void CustomSteeringAngle(this Vehicle veh, float value)
|
||||
{
|
||||
var address = new IntPtr((long)veh.MemoryAddress);
|
||||
if (address == IntPtr.Zero || _steeringAngleOffset == 0) return;
|
||||
|
||||
*(float*)(address + _steeringAngleOffset).ToPointer() = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MATH
|
||||
|
||||
public static Vector3 LinearVectorLerp(Vector3 start, Vector3 end, ulong currentTime, int duration)
|
||||
{
|
||||
return new Vector3
|
||||
{
|
||||
X = LinearFloatLerp(start.X, end.X, currentTime, duration),
|
||||
Y = LinearFloatLerp(start.Y, end.Y, currentTime, duration),
|
||||
Z = LinearFloatLerp(start.Z, end.Z, currentTime, duration)
|
||||
};
|
||||
}
|
||||
|
||||
public static float LinearFloatLerp(float start, float end, ulong currentTime, int duration)
|
||||
{
|
||||
return (end - start) * currentTime / duration + start;
|
||||
}
|
||||
|
||||
public static float Lerp(float from, float to, float fAlpha)
|
||||
{
|
||||
return from * (1.0f - fAlpha) + to * fAlpha; //from + (to - from) * fAlpha
|
||||
}
|
||||
|
||||
public static Vector3 RotationToDirection(Vector3 rotation)
|
||||
{
|
||||
var z = MathExtensions.DegToRad(rotation.Z);
|
||||
var x = MathExtensions.DegToRad(rotation.X);
|
||||
var num = Math.Abs(Math.Cos(x));
|
||||
|
||||
return new Vector3
|
||||
{
|
||||
X = (float)(-Math.Sin(z) * num),
|
||||
Y = (float)(Math.Cos(z) * num),
|
||||
Z = (float)Math.Sin(x)
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
using GTA;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -15,101 +15,62 @@ namespace RageCoop.Client
|
||||
var veh = v.MainVehicle;
|
||||
VehicleDataFlags flags = 0;
|
||||
|
||||
if (veh.IsEngineRunning)
|
||||
{
|
||||
flags |= VehicleDataFlags.IsEngineRunning;
|
||||
}
|
||||
if (veh.IsEngineRunning) flags |= VehicleDataFlags.IsEngineRunning;
|
||||
|
||||
if (veh.AreLightsOn)
|
||||
{
|
||||
flags |= VehicleDataFlags.AreLightsOn;
|
||||
}
|
||||
if (veh.AreLightsOn) flags |= VehicleDataFlags.AreLightsOn;
|
||||
|
||||
if (veh.BrakePower >= 0.01f)
|
||||
{
|
||||
flags |= VehicleDataFlags.AreBrakeLightsOn;
|
||||
}
|
||||
if (veh.BrakePower >= 0.01f) flags |= VehicleDataFlags.AreBrakeLightsOn;
|
||||
|
||||
if (veh.AreHighBeamsOn)
|
||||
{
|
||||
flags |= VehicleDataFlags.AreHighBeamsOn;
|
||||
}
|
||||
if (veh.AreHighBeamsOn) flags |= VehicleDataFlags.AreHighBeamsOn;
|
||||
|
||||
if (veh.IsSirenActive)
|
||||
{
|
||||
flags |= VehicleDataFlags.IsSirenActive;
|
||||
}
|
||||
if (veh.IsSirenActive) flags |= VehicleDataFlags.IsSirenActive;
|
||||
|
||||
if (veh.IsDead)
|
||||
{
|
||||
flags |= VehicleDataFlags.IsDead;
|
||||
}
|
||||
if (veh.IsDead) flags |= VehicleDataFlags.IsDead;
|
||||
|
||||
if (Function.Call<bool>(Hash.IS_HORN_ACTIVE, veh.Handle))
|
||||
{
|
||||
flags |= VehicleDataFlags.IsHornActive;
|
||||
}
|
||||
if (Function.Call<bool>(Hash.IS_HORN_ACTIVE, veh.Handle)) flags |= VehicleDataFlags.IsHornActive;
|
||||
|
||||
if (v.IsSubmarineCar && Function.Call<bool>(Hash._GET_IS_SUBMARINE_VEHICLE_TRANSFORMED, veh.Handle))
|
||||
{
|
||||
flags |= VehicleDataFlags.IsTransformed;
|
||||
}
|
||||
|
||||
if (v.IsAircraft)
|
||||
{
|
||||
flags |= VehicleDataFlags.IsAircraft;
|
||||
}
|
||||
if (v.IsAircraft) flags |= VehicleDataFlags.IsAircraft;
|
||||
|
||||
if (v.IsDeluxo && veh.IsDeluxoHovering())
|
||||
{
|
||||
flags |= VehicleDataFlags.IsDeluxoHovering;
|
||||
}
|
||||
if (v.IsDeluxo && veh.IsDeluxoHovering()) flags |= VehicleDataFlags.IsDeluxoHovering;
|
||||
|
||||
if (v.HasRoof)
|
||||
{
|
||||
flags |= VehicleDataFlags.HasRoof;
|
||||
}
|
||||
if (v.HasRoof) flags |= VehicleDataFlags.HasRoof;
|
||||
|
||||
if (v.HasRocketBoost && veh.IsRocketBoostActive())
|
||||
{
|
||||
flags |= VehicleDataFlags.IsRocketBoostActive;
|
||||
}
|
||||
if (v.HasRocketBoost && veh.IsRocketBoostActive()) flags |= VehicleDataFlags.IsRocketBoostActive;
|
||||
|
||||
if (v.HasParachute && veh.IsParachuteActive())
|
||||
{
|
||||
flags |= VehicleDataFlags.IsParachuteActive;
|
||||
}
|
||||
if (v.HasParachute && veh.IsParachuteActive()) flags |= VehicleDataFlags.IsParachuteActive;
|
||||
|
||||
if (veh.IsOnFire)
|
||||
{
|
||||
flags |= VehicleDataFlags.IsOnFire;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
public static bool IsParachuteActive(this Vehicle veh)
|
||||
{
|
||||
return Function.Call<bool>((Hash)0x3DE51E9C80B116CF, veh);
|
||||
}
|
||||
|
||||
public static void SetRocketBoostActive(this Vehicle veh, bool toggle)
|
||||
{
|
||||
Function.Call(Hash._SET_VEHICLE_ROCKET_BOOST_ACTIVE, veh, toggle);
|
||||
}
|
||||
|
||||
public static void SetParachuteActive(this Vehicle veh, bool toggle)
|
||||
{
|
||||
Function.Call((Hash)0x0BFFB028B3DD0A97, veh, toggle);
|
||||
}
|
||||
|
||||
public static Dictionary<int, int> GetVehicleMods(this VehicleModCollection mods)
|
||||
{
|
||||
Dictionary<int, int> result = new Dictionary<int, int>();
|
||||
foreach (VehicleMod mod in mods.ToArray())
|
||||
{
|
||||
result.Add((int)mod.Type, mod.Index);
|
||||
}
|
||||
var result = new Dictionary<int, int>();
|
||||
foreach (var mod in mods.ToArray()) result.Add((int)mod.Type, mod.Index);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -117,40 +78,25 @@ namespace RageCoop.Client
|
||||
{
|
||||
// Broken windows
|
||||
byte brokenWindows = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
for (var i = 0; i < 8; i++)
|
||||
if (!veh.Windows[(VehicleWindowIndex)i].IsIntact)
|
||||
{
|
||||
brokenWindows |= (byte)(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
// Broken doors
|
||||
byte brokenDoors = 0;
|
||||
byte openedDoors = 0;
|
||||
foreach (VehicleDoor door in veh.Doors)
|
||||
{
|
||||
foreach (var door in veh.Doors)
|
||||
if (door.IsBroken)
|
||||
{
|
||||
brokenDoors |= (byte)(1 << (byte)door.Index);
|
||||
}
|
||||
else if (door.IsOpen)
|
||||
{
|
||||
openedDoors |= (byte)(1 << (byte)door.Index);
|
||||
}
|
||||
}
|
||||
else if (door.IsOpen) openedDoors |= (byte)(1 << (byte)door.Index);
|
||||
|
||||
// Bursted tires
|
||||
short burstedTires = 0;
|
||||
foreach (VehicleWheel wheel in veh.Wheels.GetAllWheels())
|
||||
{
|
||||
foreach (var wheel in veh.Wheels.GetAllWheels())
|
||||
if (wheel.IsBursted)
|
||||
{
|
||||
burstedTires |= (short)(1 << (int)wheel.BoneId);
|
||||
}
|
||||
}
|
||||
|
||||
return new VehicleDamageModel()
|
||||
return new VehicleDamageModel
|
||||
{
|
||||
BrokenDoors = brokenDoors,
|
||||
OpenedDoors = openedDoors,
|
||||
@ -163,47 +109,37 @@ namespace RageCoop.Client
|
||||
|
||||
public static void SetDamageModel(this Vehicle veh, VehicleDamageModel model, bool leavedoors = true)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
var door = veh.Doors[(VehicleDoorIndex)i];
|
||||
if ((model.BrokenDoors & (byte)(1 << i)) != 0)
|
||||
{
|
||||
if (!door.IsBroken)
|
||||
{
|
||||
door.Break(leavedoors);
|
||||
}
|
||||
if (!door.IsBroken) door.Break(leavedoors);
|
||||
continue;
|
||||
}
|
||||
else if (door.IsBroken)
|
||||
|
||||
if (door.IsBroken)
|
||||
{
|
||||
// The vehicle can only fix a door if the vehicle was completely fixed
|
||||
veh.Repair();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((model.OpenedDoors & (byte)(1 << i)) != 0)
|
||||
{
|
||||
if ((!door.IsOpen) && (!door.IsBroken))
|
||||
{
|
||||
door.Open();
|
||||
}
|
||||
if (!door.IsOpen && !door.IsBroken) door.Open();
|
||||
}
|
||||
else if (door.IsOpen)
|
||||
{
|
||||
if (!door.IsBroken) { door.Close(); }
|
||||
if (!door.IsBroken) door.Close();
|
||||
}
|
||||
|
||||
if ((model.BrokenWindows & (byte)(1 << i)) != 0)
|
||||
{
|
||||
veh.Windows[(VehicleWindowIndex)i].Smash();
|
||||
}
|
||||
else if (!veh.Windows[(VehicleWindowIndex)i].IsIntact)
|
||||
{
|
||||
veh.Windows[(VehicleWindowIndex)i].Repair();
|
||||
}
|
||||
else if (!veh.Windows[(VehicleWindowIndex)i].IsIntact) veh.Windows[(VehicleWindowIndex)i].Repair();
|
||||
}
|
||||
|
||||
foreach (VehicleWheel wheel in veh.Wheels)
|
||||
{
|
||||
foreach (var wheel in veh.Wheels)
|
||||
if ((model.BurstedTires & (short)(1 << (int)wheel.BoneId)) != 0)
|
||||
{
|
||||
if (!wheel.IsBursted)
|
||||
@ -216,7 +152,6 @@ namespace RageCoop.Client
|
||||
{
|
||||
wheel.Fix();
|
||||
}
|
||||
}
|
||||
|
||||
veh.IsLeftHeadLightBroken = model.LeftHeadLightBroken > 0;
|
||||
veh.IsRightHeadLightBroken = model.RightHeadLightBroken > 0;
|
||||
@ -224,19 +159,12 @@ namespace RageCoop.Client
|
||||
|
||||
public static Dictionary<int, int> GetPassengers(this Vehicle veh)
|
||||
{
|
||||
Dictionary<int, int> ps = new Dictionary<int, int>();
|
||||
var ps = new Dictionary<int, int>();
|
||||
var d = veh.Driver;
|
||||
if (d != null && d.IsSittingInVehicle())
|
||||
{
|
||||
ps.Add(-1, d.GetSyncEntity().ID);
|
||||
}
|
||||
foreach (Ped p in veh.Passengers)
|
||||
{
|
||||
if (d != null && d.IsSittingInVehicle()) ps.Add(-1, d.GetSyncEntity().ID);
|
||||
foreach (var p in veh.Passengers)
|
||||
if (p.IsSittingInVehicle())
|
||||
{
|
||||
ps.Add((int)p.SeatIndex, p.GetSyncEntity().ID);
|
||||
}
|
||||
}
|
||||
return ps;
|
||||
}
|
||||
|
||||
@ -244,25 +172,29 @@ namespace RageCoop.Client
|
||||
{
|
||||
Function.Call(Hash._SET_VEHICLE_HOVER_TRANSFORM_PERCENTAGE, deluxo, hover ? 1f : 0f);
|
||||
}
|
||||
|
||||
public static bool IsDeluxoHovering(this Vehicle deluxo)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public static float GetDeluxoWingRatio(this Vehicle v)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public static bool HasNozzle(this Vehicle v)
|
||||
{
|
||||
|
||||
switch (v.Model.Hash)
|
||||
{
|
||||
// Hydra
|
||||
@ -280,14 +212,16 @@ namespace RageCoop.Client
|
||||
// Avenger
|
||||
case 408970549:
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void SetNozzleAngel(this Vehicle plane, float ratio)
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane, ratio);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
@ -1,48 +1,56 @@
|
||||
using GTA;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
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
|
||||
{
|
||||
#region DUMP
|
||||
|
||||
class VehicleInfo
|
||||
internal class VehicleInfo
|
||||
{
|
||||
public VehicleBone[] Bones;
|
||||
public uint Hash;
|
||||
public string Name;
|
||||
public string[] Weapons;
|
||||
public uint Hash;
|
||||
public VehicleBone[] Bones;
|
||||
}
|
||||
class VehicleBone
|
||||
|
||||
internal class VehicleBone
|
||||
{
|
||||
public uint BoneID;
|
||||
public uint BoneIndex;
|
||||
public string BoneName;
|
||||
}
|
||||
class WeaponBones
|
||||
|
||||
internal class WeaponBones
|
||||
{
|
||||
public string Name;
|
||||
public VehicleBone[] Bones;
|
||||
public string Name;
|
||||
}
|
||||
class VehicleWeaponInfo
|
||||
|
||||
internal class VehicleWeaponInfo
|
||||
{
|
||||
public uint Hash;
|
||||
public string Name;
|
||||
public Dictionary<uint, WeaponBones> Weapons = new Dictionary<uint, WeaponBones>();
|
||||
|
||||
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);
|
||||
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");
|
||||
@ -51,52 +59,77 @@ namespace RageCoop.Client
|
||||
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++)
|
||||
{
|
||||
if (info.Weapons.Length == 0) return null;
|
||||
var result = new VehicleWeaponInfo { Hash = info.Hash, Name = info.Name };
|
||||
for (var 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()
|
||||
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
|
||||
|
||||
internal class WeaponInfo
|
||||
{
|
||||
public string Name;
|
||||
public uint Hash;
|
||||
public string Name;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 312)]
|
||||
public struct DlcWeaponData
|
||||
{
|
||||
}
|
||||
class WeaponFix
|
||||
|
||||
internal class WeaponFix
|
||||
{
|
||||
public Dictionary<uint,string> Bullet=new Dictionary<uint, string>();
|
||||
public Dictionary<uint, string> Bullet = new Dictionary<uint, string>();
|
||||
public Dictionary<uint, string> Lazer = new Dictionary<uint, string>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal static class WeaponUtil
|
||||
{
|
||||
public const string VehicleWeaponLocation = @"RageCoop\Data\VehicleWeapons.json";
|
||||
public const string WeaponFixLocation = @"RageCoop\Data\WeaponFixes.json";
|
||||
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";
|
||||
|
||||
public static readonly HashSet<uint> ExplosiveBullets = new HashSet<uint>
|
||||
{
|
||||
(uint)VehicleWeaponHash.PlayerLazer,
|
||||
(uint)WeaponHash.Railgun,
|
||||
1638077257
|
||||
};
|
||||
|
||||
public static readonly HashSet<WeaponHash> ProjectileWeapons = new HashSet<WeaponHash>
|
||||
{
|
||||
WeaponHash.HomingLauncher,
|
||||
WeaponHash.RPG,
|
||||
WeaponHash.Firework,
|
||||
WeaponHash.UpNAtomizer,
|
||||
WeaponHash.GrenadeLauncher,
|
||||
WeaponHash.GrenadeLauncherSmoke,
|
||||
WeaponHash.CompactGrenadeLauncher,
|
||||
WeaponHash.FlareGun
|
||||
};
|
||||
|
||||
public static readonly HashSet<VehicleWeaponHash> VehicleProjectileWeapons = new HashSet<VehicleWeaponHash>
|
||||
{
|
||||
VehicleWeaponHash.PlaneRocket,
|
||||
VehicleWeaponHash.SpaceRocket,
|
||||
VehicleWeaponHash.Tank,
|
||||
(VehicleWeaponHash)3565779982, // STROMBERG missiles
|
||||
(VehicleWeaponHash)3169388763 // SCRAMJET missiles
|
||||
};
|
||||
|
||||
static WeaponUtil()
|
||||
{
|
||||
if (!File.Exists(VehicleWeaponLocation))
|
||||
@ -107,17 +140,16 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
// Parse and load to memory
|
||||
foreach (var w in JsonConvert.DeserializeObject<VehicleWeaponInfo[]>(File.ReadAllText(VehicleWeaponLocation)))
|
||||
{
|
||||
VehicleWeapons.Add(w.Hash, w);
|
||||
}
|
||||
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 };
|
||||
var types = new HashSet<int> { 3 };
|
||||
P.IsInvincible = true;
|
||||
var fix = new WeaponFix();
|
||||
foreach (VehicleWeaponHash v in Enum.GetValues(typeof(VehicleWeaponHash)))
|
||||
@ -129,19 +161,15 @@ namespace RageCoop.Client
|
||||
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();
|
||||
}
|
||||
!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);
|
||||
@ -149,91 +177,70 @@ namespace RageCoop.Client
|
||||
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))
|
||||
{
|
||||
!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();
|
||||
}
|
||||
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")))
|
||||
var 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; }
|
||||
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>();
|
||||
var 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},";
|
||||
}
|
||||
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>();
|
||||
var 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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()}");
|
||||
}
|
||||
var 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},";
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
@ -242,10 +249,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
result = new Dictionary<uint, bool>();
|
||||
|
||||
foreach (var comp in weapon.Components)
|
||||
{
|
||||
result.Add((uint)comp.ComponentHash, comp.Active);
|
||||
}
|
||||
foreach (var comp in weapon.Components) result.Add((uint)comp.ComponentHash, comp.Active);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -253,90 +257,63 @@ namespace RageCoop.Client
|
||||
|
||||
public static Vector3 GetMuzzlePosition(this Ped p)
|
||||
{
|
||||
if (p.IsOnTurretSeat())
|
||||
{
|
||||
return p.CurrentVehicle.GetMuzzleBone(p.VehicleWeapon).Position;
|
||||
}
|
||||
if (p.IsOnTurretSeat()) return p.CurrentVehicle.GetMuzzleBone(p.VehicleWeapon).Position;
|
||||
var wb = p.Weapons?.CurrentWeaponObject?.Bones["gun_muzzle"];
|
||||
if (wb?.IsValid == true)
|
||||
{
|
||||
return wb.Position;
|
||||
}
|
||||
if (wb?.IsValid == true) return wb.Position;
|
||||
return p.Bones[Bone.SkelRightHand].Position;
|
||||
}
|
||||
|
||||
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);
|
||||
return Function.Call<float>(Hash.GET_WEAPON_DAMAGE, hash,
|
||||
comp.Active ? comp.ComponentHash : WeaponComponentHash.Invalid);
|
||||
}
|
||||
|
||||
public static int GetMuzzleIndex(this Vehicle v, VehicleWeaponHash hash)
|
||||
{
|
||||
if (VehicleWeapons.TryGetValue((uint)v.Model.Hash, out var veh) && veh.Weapons.TryGetValue((uint)hash, out var wp))
|
||||
{
|
||||
if (VehicleWeapons.TryGetValue((uint)v.Model.Hash, out var veh) &&
|
||||
veh.Weapons.TryGetValue((uint)hash, out var wp))
|
||||
return (int)wp.Bones[CoreUtils.RandInt(0, wp.Bones.Length)].BoneIndex;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static EntityBone GetMuzzleBone(this Vehicle v, VehicleWeaponHash hash)
|
||||
{
|
||||
if ((uint)hash == 1422046295) { hash = VehicleWeaponHash.WaterCannon; } // Weird...
|
||||
if ((uint)hash == 1422046295) hash = VehicleWeaponHash.WaterCannon;
|
||||
var i = v.GetMuzzleIndex(hash);
|
||||
if (i == -1) { return null; }
|
||||
if (i == -1) return null;
|
||||
return v.Bones[i];
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return type == 3 ? false : VehicleProjectileWeapons.Contains(vp) || (type == 5 && !ExplosiveBullets.Contains((uint)vp));
|
||||
}
|
||||
return type == 3
|
||||
? false
|
||||
: VehicleProjectileWeapons.Contains(vp) || (type == 5 && !ExplosiveBullets.Contains((uint)vp));
|
||||
|
||||
var w = p.Weapons.Current;
|
||||
return w.Group == WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
|
||||
}
|
||||
|
||||
public static 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 HashSet<WeaponHash> ProjectileWeapons = new HashSet<WeaponHash> {
|
||||
WeaponHash.HomingLauncher,
|
||||
WeaponHash.RPG,
|
||||
WeaponHash.Firework,
|
||||
WeaponHash.UpNAtomizer,
|
||||
WeaponHash.GrenadeLauncher,
|
||||
WeaponHash.GrenadeLauncherSmoke,
|
||||
WeaponHash.CompactGrenadeLauncher,
|
||||
WeaponHash.FlareGun,
|
||||
};
|
||||
public static readonly HashSet<VehicleWeaponHash> VehicleProjectileWeapons = new HashSet<VehicleWeaponHash> {
|
||||
VehicleWeaponHash.PlaneRocket,
|
||||
VehicleWeaponHash.SpaceRocket,
|
||||
VehicleWeaponHash.Tank,
|
||||
(VehicleWeaponHash)3565779982, // STROMBERG missiles
|
||||
(VehicleWeaponHash)3169388763, // SCRAMJET missiles
|
||||
};
|
||||
public static string GetFlashFX(this WeaponHash w,bool veh)
|
||||
|
||||
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:
|
||||
@ -378,6 +355,7 @@ namespace RageCoop.Client
|
||||
return "muz_assault_rifle";
|
||||
}
|
||||
}
|
||||
|
||||
public static WeaponGroup GetWeaponGroup(this WeaponHash hash)
|
||||
{
|
||||
return Function.Call<WeaponGroup>(Hash.GET_WEAPONTYPE_GROUP, hash);
|
||||
@ -397,4 +375,4 @@ namespace RageCoop.Client
|
||||
public float SweepPitchMax;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user