Fixed bug with weapon components. Partial EntitiesPed.cs
This commit is contained in:
@ -80,6 +80,8 @@
|
|||||||
<Compile Include="Entities\EntitiesPed.cs" />
|
<Compile Include="Entities\EntitiesPed.cs" />
|
||||||
<Compile Include="Entities\EntitiesPlayer.cs" />
|
<Compile Include="Entities\EntitiesPlayer.cs" />
|
||||||
<Compile Include="Entities\EntitiesThread.cs" />
|
<Compile Include="Entities\EntitiesThread.cs" />
|
||||||
|
<Compile Include="Entities\Sync\OnFootSync.cs" />
|
||||||
|
<Compile Include="Entities\Sync\VehicleSync.cs" />
|
||||||
<Compile Include="Main.cs" />
|
<Compile Include="Main.cs" />
|
||||||
<Compile Include="Menus\MenusMain.cs" />
|
<Compile Include="Menus\MenusMain.cs" />
|
||||||
<Compile Include="Menus\Sub\Servers.cs" />
|
<Compile Include="Menus\Sub\Servers.cs" />
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
using GTA;
|
using GTA;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
@ -14,7 +13,7 @@ namespace CoopClient.Entities
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// ?
|
/// ?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EntitiesPed
|
public partial class EntitiesPed
|
||||||
{
|
{
|
||||||
internal long NPCVehHandle { get; set; } = 0;
|
internal long NPCVehHandle { get; set; } = 0;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -62,98 +61,8 @@ namespace CoopClient.Entities
|
|||||||
/// The latest character position (may not have been applied yet)
|
/// The latest character position (may not have been applied yet)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Vector3 Position { get; internal set; }
|
public Vector3 Position { get; internal set; }
|
||||||
|
|
||||||
#region -- ON FOOT --
|
|
||||||
/// <summary>
|
|
||||||
/// The latest character rotation (may not have been applied yet)
|
|
||||||
/// </summary>
|
|
||||||
public Vector3 Rotation { get; internal set; }
|
|
||||||
/// <summary>
|
|
||||||
/// The latest character velocity (may not have been applied yet)
|
|
||||||
/// </summary>
|
|
||||||
public Vector3 Velocity { get; internal set; }
|
|
||||||
internal byte Speed { get; set; }
|
|
||||||
private bool LastIsJumping = false;
|
|
||||||
internal bool IsJumping { get; set; }
|
|
||||||
internal bool IsRagdoll { get; set; }
|
|
||||||
internal bool IsOnFire { get; set; }
|
|
||||||
internal Vector3 AimCoords { get; set; }
|
|
||||||
internal bool IsAiming { get; set; }
|
|
||||||
internal bool IsShooting { get; set; }
|
|
||||||
internal bool IsReloading { get; set; }
|
|
||||||
internal int CurrentWeaponHash { get; set; }
|
|
||||||
internal List<uint> WeaponComponents { get; set; }
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
internal Blip PedBlip = null;
|
internal Blip PedBlip = null;
|
||||||
|
internal Vector3 AimCoords { get; set; }
|
||||||
#region -- IN VEHICLE --
|
|
||||||
private ulong VehicleStopTime { get; set; }
|
|
||||||
|
|
||||||
internal bool IsInVehicle { get; set; }
|
|
||||||
private int LastVehicleModelHash = 0;
|
|
||||||
private int CurrentVehicleModelHash = 0;
|
|
||||||
/// <summary>
|
|
||||||
/// The latest vehicle model hash (may not have been applied yet)
|
|
||||||
/// </summary>
|
|
||||||
public int VehicleModelHash
|
|
||||||
{
|
|
||||||
get => CurrentVehicleModelHash;
|
|
||||||
internal set
|
|
||||||
{
|
|
||||||
LastVehicleModelHash = CurrentVehicleModelHash == 0 ? value : CurrentVehicleModelHash;
|
|
||||||
CurrentVehicleModelHash = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private int[] LastVehicleColors = new int[] { 0, 0 };
|
|
||||||
internal int[] VehicleColors { get; set; }
|
|
||||||
private Dictionary<int, int> LastVehicleMods = new Dictionary<int, int>();
|
|
||||||
internal Dictionary<int, int> VehicleMods { get; set; }
|
|
||||||
internal bool VehicleDead { get; set; }
|
|
||||||
internal float VehicleEngineHealth { get; set; }
|
|
||||||
internal int VehicleSeatIndex { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// ?
|
|
||||||
/// </summary>
|
|
||||||
public Vehicle MainVehicle { get; internal set; }
|
|
||||||
/// <summary>
|
|
||||||
/// The latest vehicle position (may not have been applied yet)
|
|
||||||
/// </summary>
|
|
||||||
public Vector3 VehiclePosition { get; internal set; }
|
|
||||||
/// <summary>
|
|
||||||
/// The latest vehicle rotation (may not have been applied yet)
|
|
||||||
/// </summary>
|
|
||||||
public Quaternion VehicleRotation { get; internal set; }
|
|
||||||
internal Vector3 VehicleVelocity { get; set; }
|
|
||||||
private float LastVehicleSpeed { get; set; }
|
|
||||||
private float CurrentVehicleSpeed { get; set; }
|
|
||||||
internal float VehicleSpeed
|
|
||||||
{
|
|
||||||
get => CurrentVehicleSpeed;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
LastVehicleSpeed = CurrentVehicleSpeed;
|
|
||||||
CurrentVehicleSpeed = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal float VehicleSteeringAngle { get; set; }
|
|
||||||
private int LastVehicleAim;
|
|
||||||
internal bool VehIsEngineRunning { get; set; }
|
|
||||||
internal float VehRPM { get; set; }
|
|
||||||
private bool LastTransformed = false;
|
|
||||||
internal bool Transformed { get; set; }
|
|
||||||
private bool LastHornActive = false;
|
|
||||||
internal bool IsHornActive { get; set; }
|
|
||||||
internal bool VehAreLightsOn { get; set; }
|
|
||||||
internal bool VehAreHighBeamsOn { get; set; }
|
|
||||||
internal byte VehLandingGear { get; set; }
|
|
||||||
|
|
||||||
internal bool VehIsSireneActive { get; set; }
|
|
||||||
private VehicleDoors[] LastVehDoors;
|
|
||||||
internal VehicleDoors[] VehDoors { get; set; }
|
|
||||||
private int LastVehTires;
|
|
||||||
internal int VehTires { get; set; }
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
internal void DisplayLocally(string username)
|
internal void DisplayLocally(string username)
|
||||||
{
|
{
|
||||||
@ -341,458 +250,6 @@ namespace CoopClient.Entities
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisplayInVehicle()
|
|
||||||
{
|
|
||||||
if (MainVehicle == null || !MainVehicle.Exists() || MainVehicle.Model.Hash != CurrentVehicleModelHash)
|
|
||||||
{
|
|
||||||
bool vehFound = false;
|
|
||||||
|
|
||||||
if (NPCVehHandle != 0)
|
|
||||||
{
|
|
||||||
lock (Main.NPCsVehicles)
|
|
||||||
{
|
|
||||||
if (Main.NPCsVehicles.ContainsKey(NPCVehHandle))
|
|
||||||
{
|
|
||||||
Vehicle targetVehicle = World.GetAllVehicles().First(x => x.Handle == Main.NPCsVehicles[NPCVehHandle]);
|
|
||||||
if (targetVehicle == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MainVehicle = targetVehicle;
|
|
||||||
vehFound = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Vehicle targetVehicle = World.GetClosestVehicle(Position, 7f, new Model[] { CurrentVehicleModelHash });
|
|
||||||
|
|
||||||
if (targetVehicle != null)
|
|
||||||
{
|
|
||||||
if (targetVehicle.IsSeatFree((VehicleSeat)VehicleSeatIndex))
|
|
||||||
{
|
|
||||||
MainVehicle = targetVehicle;
|
|
||||||
vehFound = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vehFound)
|
|
||||||
{
|
|
||||||
Model vehicleModel = CurrentVehicleModelHash.ModelRequest();
|
|
||||||
if (vehicleModel == null)
|
|
||||||
{
|
|
||||||
//GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
|
|
||||||
ModelNotFound = 2;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MainVehicle = World.CreateVehicle(vehicleModel, VehiclePosition);
|
|
||||||
vehicleModel.MarkAsNoLongerNeeded();
|
|
||||||
if (NPCVehHandle != 0)
|
|
||||||
{
|
|
||||||
Main.NPCsVehicles.Add(NPCVehHandle, MainVehicle.Handle);
|
|
||||||
}
|
|
||||||
MainVehicle.Quaternion = VehicleRotation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Character.IsInVehicle() || (int)Character.SeatIndex != VehicleSeatIndex || Character.CurrentVehicle.Handle != MainVehicle.Handle)
|
|
||||||
{
|
|
||||||
if (VehicleSeatIndex == -1 &&
|
|
||||||
Game.Player.Character.IsInVehicle() &&
|
|
||||||
(int)Game.Player.Character.SeatIndex == -1 &&
|
|
||||||
Game.Player.Character.CurrentVehicle.Handle == MainVehicle.Handle)
|
|
||||||
{
|
|
||||||
Game.Player.Character.Task.WarpOutOfVehicle(MainVehicle);
|
|
||||||
GTA.UI.Notification.Show("~r~Car jacked!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Character.SetIntoVehicle(MainVehicle, (VehicleSeat)VehicleSeatIndex);
|
|
||||||
Character.IsVisible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region -- VEHICLE SYNC --
|
|
||||||
if (AimCoords != default)
|
|
||||||
{
|
|
||||||
if (MainVehicle.IsTurretSeat(VehicleSeatIndex))
|
|
||||||
{
|
|
||||||
int gameTime = Game.GameTime;
|
|
||||||
if (gameTime - LastVehicleAim > 30)
|
|
||||||
{
|
|
||||||
Function.Call(Hash.TASK_VEHICLE_AIM_AT_COORD, Character.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z);
|
|
||||||
LastVehicleAim = gameTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MainVehicle.GetResponsiblePedHandle() != Character.Handle)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VehicleColors != null && VehicleColors != LastVehicleColors)
|
|
||||||
{
|
|
||||||
Function.Call(Hash.SET_VEHICLE_COLOURS, MainVehicle, VehicleColors[0], VehicleColors[1]);
|
|
||||||
|
|
||||||
LastVehicleColors = VehicleColors;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Character.IsOnBike && MainVehicle.ClassType == VehicleClass.Cycles)
|
|
||||||
{
|
|
||||||
bool isFastPedaling = Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Character.Handle, PedalingAnimDict(), "fast_pedal_char", 3);
|
|
||||||
if (CurrentVehicleSpeed < 0.2f)
|
|
||||||
{
|
|
||||||
StopPedalingAnim(isFastPedaling);
|
|
||||||
}
|
|
||||||
else if (CurrentVehicleSpeed < 11f && !Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Character.Handle, PedalingAnimDict(), "cruise_pedal_char", 3))
|
|
||||||
{
|
|
||||||
StartPedalingAnim(false);
|
|
||||||
}
|
|
||||||
else if (CurrentVehicleSpeed >= 11f && !isFastPedaling)
|
|
||||||
{
|
|
||||||
StartPedalingAnim(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (VehicleMods != null && VehicleMods != LastVehicleMods)
|
|
||||||
{
|
|
||||||
Function.Call(Hash.SET_VEHICLE_MOD_KIT, MainVehicle, 0);
|
|
||||||
|
|
||||||
foreach (KeyValuePair<int, int> mod in VehicleMods)
|
|
||||||
{
|
|
||||||
MainVehicle.Mods[(VehicleModType)mod.Key].Index = mod.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
LastVehicleMods = VehicleMods;
|
|
||||||
}
|
|
||||||
|
|
||||||
MainVehicle.EngineHealth = VehicleEngineHealth;
|
|
||||||
|
|
||||||
if (VehicleDead && !MainVehicle.IsDead)
|
|
||||||
{
|
|
||||||
MainVehicle.Explode();
|
|
||||||
}
|
|
||||||
else if (!VehicleDead && MainVehicle.IsDead)
|
|
||||||
{
|
|
||||||
MainVehicle.Repair();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VehIsEngineRunning != MainVehicle.IsEngineRunning)
|
|
||||||
{
|
|
||||||
MainVehicle.IsEngineRunning = VehIsEngineRunning;
|
|
||||||
}
|
|
||||||
|
|
||||||
MainVehicle.CurrentRPM = VehRPM;
|
|
||||||
|
|
||||||
if (VehAreLightsOn != MainVehicle.AreLightsOn)
|
|
||||||
{
|
|
||||||
MainVehicle.AreLightsOn = VehAreLightsOn;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VehAreHighBeamsOn != MainVehicle.AreHighBeamsOn)
|
|
||||||
{
|
|
||||||
MainVehicle.AreHighBeamsOn = VehAreHighBeamsOn;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MainVehicle.IsSubmarineCar)
|
|
||||||
{
|
|
||||||
if (Transformed && !LastTransformed)
|
|
||||||
{
|
|
||||||
LastTransformed = true;
|
|
||||||
Function.Call(Hash._TRANSFORM_VEHICLE_TO_SUBMARINE, MainVehicle, false);
|
|
||||||
}
|
|
||||||
else if (!Transformed && LastTransformed)
|
|
||||||
{
|
|
||||||
LastTransformed = false;
|
|
||||||
Function.Call(Hash._TRANSFORM_SUBMARINE_TO_VEHICLE, MainVehicle, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MainVehicle.IsPlane)
|
|
||||||
{
|
|
||||||
if (VehLandingGear != (byte)MainVehicle.LandingGearState)
|
|
||||||
{
|
|
||||||
MainVehicle.LandingGearState = (VehicleLandingGearState)VehLandingGear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (MainVehicle.HasSiren && VehIsSireneActive != MainVehicle.IsSirenActive)
|
|
||||||
{
|
|
||||||
MainVehicle.IsSirenActive = VehIsSireneActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsHornActive && !LastHornActive)
|
|
||||||
{
|
|
||||||
LastHornActive = true;
|
|
||||||
MainVehicle.SoundHorn(99999);
|
|
||||||
}
|
|
||||||
else if (!IsHornActive && LastHornActive)
|
|
||||||
{
|
|
||||||
LastHornActive = false;
|
|
||||||
MainVehicle.SoundHorn(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle, CurrentVehicleSpeed > 0.2f && LastVehicleSpeed > CurrentVehicleSpeed);
|
|
||||||
|
|
||||||
if (LastSyncWasFull)
|
|
||||||
{
|
|
||||||
if (VehDoors != null && VehDoors != LastVehDoors)
|
|
||||||
{
|
|
||||||
int doorLength = VehDoors.Length;
|
|
||||||
if (VehDoors.Length != 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < (doorLength - 1); i++)
|
|
||||||
{
|
|
||||||
VehicleDoor door = MainVehicle.Doors[(VehicleDoorIndex)i];
|
|
||||||
VehicleDoors aDoor = VehDoors[i];
|
|
||||||
|
|
||||||
if (aDoor.Broken)
|
|
||||||
{
|
|
||||||
if (!door.IsBroken)
|
|
||||||
{
|
|
||||||
door.Break();
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (!aDoor.Broken && door.IsBroken)
|
|
||||||
{
|
|
||||||
// Repair?
|
|
||||||
//MainVehicle.Repair();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aDoor.FullyOpen)
|
|
||||||
{
|
|
||||||
if (!door.IsFullyOpen)
|
|
||||||
{
|
|
||||||
door.Open(false, true);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (aDoor.Open)
|
|
||||||
{
|
|
||||||
if (!door.IsOpen)
|
|
||||||
{
|
|
||||||
door.Open();
|
|
||||||
}
|
|
||||||
|
|
||||||
door.AngleRatio = aDoor.AngleRatio;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
door.Close(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LastVehDoors = VehDoors;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VehTires != default && LastVehTires != VehTires)
|
|
||||||
{
|
|
||||||
foreach (var wheel in MainVehicle.Wheels.GetAllWheels())
|
|
||||||
{
|
|
||||||
if ((VehTires & 1 << (int)wheel.BoneId) != 0)
|
|
||||||
{
|
|
||||||
wheel.Puncture();
|
|
||||||
wheel.Burst();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LastVehTires = VehTires;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VehicleSteeringAngle != MainVehicle.SteeringAngle)
|
|
||||||
{
|
|
||||||
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * VehicleSteeringAngle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Good enough for now, but we need to create a better sync
|
|
||||||
if (CurrentVehicleSpeed > 0.05f && MainVehicle.IsInRange(VehiclePosition, 7.0f))
|
|
||||||
{
|
|
||||||
int forceMultiplier = (Game.Player.Character.IsInVehicle() && MainVehicle.IsTouching(Game.Player.Character.CurrentVehicle)) ? 1 : 3;
|
|
||||||
|
|
||||||
MainVehicle.Velocity = VehicleVelocity + forceMultiplier * (VehiclePosition - MainVehicle.Position);
|
|
||||||
MainVehicle.Quaternion = Quaternion.Slerp(MainVehicle.Quaternion, VehicleRotation, 0.5f);
|
|
||||||
|
|
||||||
VehicleStopTime = Util.GetTickCount64();
|
|
||||||
}
|
|
||||||
else if ((Util.GetTickCount64() - VehicleStopTime) <= 1000)
|
|
||||||
{
|
|
||||||
Vector3 posTarget = Util.LinearVectorLerp(MainVehicle.Position, VehiclePosition + (VehiclePosition - MainVehicle.Position), Util.GetTickCount64() - VehicleStopTime, 1000);
|
|
||||||
|
|
||||||
MainVehicle.PositionNoOffset = posTarget;
|
|
||||||
MainVehicle.Quaternion = Quaternion.Slerp(MainVehicle.Quaternion, VehicleRotation, 0.5f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MainVehicle.PositionNoOffset = VehiclePosition;
|
|
||||||
MainVehicle.Quaternion = VehicleRotation;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
#region -- PEDALING --
|
|
||||||
/*
|
|
||||||
* Thanks to @oldnapalm.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private string PedalingAnimDict()
|
|
||||||
{
|
|
||||||
switch ((VehicleHash)CurrentVehicleModelHash)
|
|
||||||
{
|
|
||||||
case VehicleHash.Bmx:
|
|
||||||
return "veh@bicycle@bmx@front@base";
|
|
||||||
case VehicleHash.Cruiser:
|
|
||||||
return "veh@bicycle@cruiserfront@base";
|
|
||||||
case VehicleHash.Scorcher:
|
|
||||||
return "veh@bicycle@mountainfront@base";
|
|
||||||
default:
|
|
||||||
return "veh@bicycle@roadfront@base";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string PedalingAnimName(bool fast)
|
|
||||||
{
|
|
||||||
return fast ? "fast_pedal_char" : "cruise_pedal_char";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartPedalingAnim(bool fast)
|
|
||||||
{
|
|
||||||
Character.Task.PlayAnimation(PedalingAnimDict(), PedalingAnimName(fast), 8.0f, -8.0f, -1, AnimationFlags.Loop | AnimationFlags.AllowRotation, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StopPedalingAnim(bool fast)
|
|
||||||
{
|
|
||||||
Character.Task.ClearAnimation(PedalingAnimDict(), PedalingAnimName(fast));
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private void DisplayOnFoot()
|
|
||||||
{
|
|
||||||
if (Character.IsInVehicle())
|
|
||||||
{
|
|
||||||
Character.Task.LeaveVehicle();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MainVehicle != null)
|
|
||||||
{
|
|
||||||
MainVehicle = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsOnFire && !Character.IsOnFire)
|
|
||||||
{
|
|
||||||
Character.IsInvincible = false;
|
|
||||||
|
|
||||||
Function.Call(Hash.START_ENTITY_FIRE, Character.Handle);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (!IsOnFire && Character.IsOnFire)
|
|
||||||
{
|
|
||||||
Function.Call(Hash.STOP_ENTITY_FIRE, Character.Handle);
|
|
||||||
|
|
||||||
Character.IsInvincible = true;
|
|
||||||
|
|
||||||
if (Character.IsDead)
|
|
||||||
{
|
|
||||||
Character.Resurrect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsJumping && !LastIsJumping)
|
|
||||||
{
|
|
||||||
Character.Task.Jump();
|
|
||||||
}
|
|
||||||
|
|
||||||
LastIsJumping = IsJumping;
|
|
||||||
|
|
||||||
if (IsRagdoll && !Character.IsRagdoll)
|
|
||||||
{
|
|
||||||
Character.CanRagdoll = true;
|
|
||||||
Character.Ragdoll();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (!IsRagdoll && Character.IsRagdoll)
|
|
||||||
{
|
|
||||||
Character.CancelRagdoll();
|
|
||||||
Character.CanRagdoll = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsJumping || IsOnFire)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsReloading)
|
|
||||||
{
|
|
||||||
if (!Character.IsReloading)
|
|
||||||
{
|
|
||||||
Character.Task.ClearAll();
|
|
||||||
Character.Task.ReloadWeapon();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Character.IsInRange(Position, 0.5f))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Character.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash)
|
|
||||||
{
|
|
||||||
if (WeaponComponents == null)
|
|
||||||
{
|
|
||||||
Character.Weapons.RemoveAll();
|
|
||||||
Character.Weapons.Give((WeaponHash)CurrentWeaponHash, -1, true, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int wObj = Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0);
|
|
||||||
|
|
||||||
WeaponComponents.ForEach(mod => Function.Call(Hash.GIVE_WEAPON_COMPONENT_TO_WEAPON_OBJECT, wObj, mod));
|
|
||||||
|
|
||||||
Function.Call(Hash.GIVE_WEAPON_OBJECT_TO_PED, wObj, Character);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsShooting)
|
|
||||||
{
|
|
||||||
if (!Character.IsInRange(Position, 0.5f))
|
|
||||||
{
|
|
||||||
Function.Call(Hash.TASK_GO_TO_COORD_WHILE_AIMING_AT_COORD, Character.Handle, Position.X, Position.Y,
|
|
||||||
Position.Z, AimCoords.X, AimCoords.Y, AimCoords.Z, Speed == 3 ? 3f : 2.5f, true, 0x3F000000, 0x40800000, false, 0, false,
|
|
||||||
unchecked((int)FiringPattern.FullAuto));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Function.Call(Hash.TASK_SHOOT_AT_COORD, Character.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z, 1500, unchecked((int)FiringPattern.FullAuto));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (IsAiming)
|
|
||||||
{
|
|
||||||
if (!Character.IsInRange(Position, 0.5f))
|
|
||||||
{
|
|
||||||
Function.Call(Hash.TASK_GO_TO_COORD_WHILE_AIMING_AT_COORD, Character.Handle, Position.X, Position.Y,
|
|
||||||
Position.Z, AimCoords.X, AimCoords.Y, AimCoords.Z, Speed == 3 ? 3f : 2.5f, false, 0x3F000000, 0x40800000, false, 512, false,
|
|
||||||
unchecked((int)FiringPattern.FullAuto));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Character.Task.AimAt(AimCoords, 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WalkTo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CreateCharacter(string username)
|
private bool CreateCharacter(string username)
|
||||||
{
|
{
|
||||||
if (PedBlip != null && PedBlip.Exists())
|
if (PedBlip != null && PedBlip.Exists())
|
||||||
@ -849,62 +306,5 @@ namespace CoopClient.Entities
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool LastMoving;
|
|
||||||
private void WalkTo()
|
|
||||||
{
|
|
||||||
if (!Character.IsInRange(Position, 6.0f) && (LastMoving = true))
|
|
||||||
{
|
|
||||||
Character.Position = Position;
|
|
||||||
Character.Rotation = Rotation;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Vector3 predictPosition = Position + (Position - Character.Position) + Velocity;
|
|
||||||
float range = predictPosition.DistanceToSquared(Character.Position);
|
|
||||||
|
|
||||||
switch (Speed)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
if ((!Character.IsWalking || range > 0.25f) && (LastMoving = true))
|
|
||||||
{
|
|
||||||
float nrange = range * 2;
|
|
||||||
if (nrange > 1.0f)
|
|
||||||
{
|
|
||||||
nrange = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
Character.Task.GoStraightTo(predictPosition);
|
|
||||||
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, Character.Handle, nrange);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if ((!Character.IsRunning || range > 0.50f) && (LastMoving = true))
|
|
||||||
{
|
|
||||||
Character.Task.RunTo(predictPosition, true);
|
|
||||||
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, Character.Handle, 1.0f);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if ((!Character.IsSprinting || range > 0.75f) && (LastMoving = true))
|
|
||||||
{
|
|
||||||
Function.Call(Hash.TASK_GO_STRAIGHT_TO_COORD, Character.Handle, predictPosition.X, predictPosition.Y, predictPosition.Z, 3.0f, -1, 0.0f, 0.0f);
|
|
||||||
Function.Call(Hash.SET_RUN_SPRINT_MULTIPLIER_FOR_PLAYER, Character.Handle, 1.49f);
|
|
||||||
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, Character.Handle, 1.0f);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!Character.IsInRange(Position, 0.5f))
|
|
||||||
{
|
|
||||||
Character.Task.RunTo(Position, true, 500);
|
|
||||||
}
|
|
||||||
else if (LastMoving && (LastMoving = false))
|
|
||||||
{
|
|
||||||
Character.Task.StandStill(1000);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
223
Client/Entities/Sync/OnFootSync.cs
Normal file
223
Client/Entities/Sync/OnFootSync.cs
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using GTA;
|
||||||
|
using GTA.Native;
|
||||||
|
using GTA.Math;
|
||||||
|
|
||||||
|
namespace CoopClient.Entities
|
||||||
|
{
|
||||||
|
public partial class EntitiesPed
|
||||||
|
{
|
||||||
|
#region -- ON FOOT --
|
||||||
|
/// <summary>
|
||||||
|
/// The latest character rotation (may not have been applied yet)
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 Rotation { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The latest character velocity (may not have been applied yet)
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 Velocity { get; internal set; }
|
||||||
|
internal byte Speed { get; set; }
|
||||||
|
private bool LastIsJumping = false;
|
||||||
|
internal bool IsJumping { get; set; }
|
||||||
|
internal bool IsRagdoll { get; set; }
|
||||||
|
internal bool IsOnFire { get; set; }
|
||||||
|
internal bool IsAiming { get; set; }
|
||||||
|
internal bool IsShooting { get; set; }
|
||||||
|
internal bool IsReloading { get; set; }
|
||||||
|
internal uint CurrentWeaponHash { get; set; }
|
||||||
|
private Dictionary<uint, bool> LastWeaponComponents = null;
|
||||||
|
internal Dictionary<uint, bool> WeaponComponents { get; set; } = null;
|
||||||
|
private int LastWeaponObj = 0;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void DisplayOnFoot()
|
||||||
|
{
|
||||||
|
if (Character.IsInVehicle())
|
||||||
|
{
|
||||||
|
Character.Task.LeaveVehicle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MainVehicle != null)
|
||||||
|
{
|
||||||
|
MainVehicle = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsOnFire && !Character.IsOnFire)
|
||||||
|
{
|
||||||
|
Character.IsInvincible = false;
|
||||||
|
|
||||||
|
Function.Call(Hash.START_ENTITY_FIRE, Character.Handle);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!IsOnFire && Character.IsOnFire)
|
||||||
|
{
|
||||||
|
Function.Call(Hash.STOP_ENTITY_FIRE, Character.Handle);
|
||||||
|
|
||||||
|
Character.IsInvincible = true;
|
||||||
|
|
||||||
|
if (Character.IsDead)
|
||||||
|
{
|
||||||
|
Character.Resurrect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsJumping && !LastIsJumping)
|
||||||
|
{
|
||||||
|
Character.Task.Jump();
|
||||||
|
}
|
||||||
|
|
||||||
|
LastIsJumping = IsJumping;
|
||||||
|
|
||||||
|
if (IsRagdoll && !Character.IsRagdoll)
|
||||||
|
{
|
||||||
|
Character.CanRagdoll = true;
|
||||||
|
Character.Ragdoll();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!IsRagdoll && Character.IsRagdoll)
|
||||||
|
{
|
||||||
|
Character.CancelRagdoll();
|
||||||
|
Character.CanRagdoll = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsJumping || IsOnFire)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsReloading)
|
||||||
|
{
|
||||||
|
if (!Character.IsReloading)
|
||||||
|
{
|
||||||
|
Character.Task.ClearAll();
|
||||||
|
Character.Task.ReloadWeapon();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Character.IsInRange(Position, 0.5f))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Character.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || WeaponComponents != LastWeaponComponents)
|
||||||
|
{
|
||||||
|
Character.Weapons.RemoveAll();
|
||||||
|
|
||||||
|
if (CurrentWeaponHash != (uint)WeaponHash.Unarmed)
|
||||||
|
{
|
||||||
|
if (WeaponComponents == null || WeaponComponents.Count == 0)
|
||||||
|
{
|
||||||
|
Character.Weapons.Give((WeaponHash)CurrentWeaponHash, -1, true, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LastWeaponObj = Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0);
|
||||||
|
|
||||||
|
foreach (KeyValuePair<uint, bool> comp in WeaponComponents)
|
||||||
|
{
|
||||||
|
if (comp.Value)
|
||||||
|
{
|
||||||
|
Function.Call(Hash.GIVE_WEAPON_COMPONENT_TO_WEAPON_OBJECT, LastWeaponObj, comp.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function.Call(Hash.GIVE_WEAPON_OBJECT_TO_PED, LastWeaponObj, Character);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LastWeaponComponents = WeaponComponents;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsShooting)
|
||||||
|
{
|
||||||
|
if (!Character.IsInRange(Position, 0.5f))
|
||||||
|
{
|
||||||
|
Function.Call(Hash.TASK_GO_TO_COORD_WHILE_AIMING_AT_COORD, Character.Handle, Position.X, Position.Y,
|
||||||
|
Position.Z, AimCoords.X, AimCoords.Y, AimCoords.Z, Speed == 3 ? 3f : 2.5f, true, 0x3F000000, 0x40800000, false, 0, false,
|
||||||
|
unchecked((int)FiringPattern.FullAuto));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Function.Call(Hash.TASK_SHOOT_AT_COORD, Character.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z, 1500, unchecked((int)FiringPattern.FullAuto));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (IsAiming)
|
||||||
|
{
|
||||||
|
if (!Character.IsInRange(Position, 0.5f))
|
||||||
|
{
|
||||||
|
Function.Call(Hash.TASK_GO_TO_COORD_WHILE_AIMING_AT_COORD, Character.Handle, Position.X, Position.Y,
|
||||||
|
Position.Z, AimCoords.X, AimCoords.Y, AimCoords.Z, Speed == 3 ? 3f : 2.5f, false, 0x3F000000, 0x40800000, false, 512, false,
|
||||||
|
unchecked((int)FiringPattern.FullAuto));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Character.Task.AimAt(AimCoords, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WalkTo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool LastMoving;
|
||||||
|
private void WalkTo()
|
||||||
|
{
|
||||||
|
if (!Character.IsInRange(Position, 6.0f) && (LastMoving = true))
|
||||||
|
{
|
||||||
|
Character.Position = Position;
|
||||||
|
Character.Rotation = Rotation;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vector3 predictPosition = Position + (Position - Character.Position) + Velocity;
|
||||||
|
float range = predictPosition.DistanceToSquared(Character.Position);
|
||||||
|
|
||||||
|
switch (Speed)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
if ((!Character.IsWalking || range > 0.25f) && (LastMoving = true))
|
||||||
|
{
|
||||||
|
float nrange = range * 2;
|
||||||
|
if (nrange > 1.0f)
|
||||||
|
{
|
||||||
|
nrange = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Character.Task.GoStraightTo(predictPosition);
|
||||||
|
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, Character.Handle, nrange);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if ((!Character.IsRunning || range > 0.50f) && (LastMoving = true))
|
||||||
|
{
|
||||||
|
Character.Task.RunTo(predictPosition, true);
|
||||||
|
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, Character.Handle, 1.0f);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if ((!Character.IsSprinting || range > 0.75f) && (LastMoving = true))
|
||||||
|
{
|
||||||
|
Function.Call(Hash.TASK_GO_STRAIGHT_TO_COORD, Character.Handle, predictPosition.X, predictPosition.Y, predictPosition.Z, 3.0f, -1, 0.0f, 0.0f);
|
||||||
|
Function.Call(Hash.SET_RUN_SPRINT_MULTIPLIER_FOR_PLAYER, Character.Handle, 1.49f);
|
||||||
|
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, Character.Handle, 1.0f);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!Character.IsInRange(Position, 0.5f))
|
||||||
|
{
|
||||||
|
Character.Task.RunTo(Position, true, 500);
|
||||||
|
}
|
||||||
|
else if (LastMoving && (LastMoving = false))
|
||||||
|
{
|
||||||
|
Character.Task.StandStill(1000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
413
Client/Entities/Sync/VehicleSync.cs
Normal file
413
Client/Entities/Sync/VehicleSync.cs
Normal file
@ -0,0 +1,413 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using GTA;
|
||||||
|
using GTA.Native;
|
||||||
|
using GTA.Math;
|
||||||
|
|
||||||
|
namespace CoopClient.Entities
|
||||||
|
{
|
||||||
|
public partial class EntitiesPed
|
||||||
|
{
|
||||||
|
#region -- VARIABLES --
|
||||||
|
private ulong VehicleStopTime { get; set; }
|
||||||
|
|
||||||
|
internal bool IsInVehicle { get; set; }
|
||||||
|
private int LastVehicleModelHash = 0;
|
||||||
|
private int CurrentVehicleModelHash = 0;
|
||||||
|
/// <summary>
|
||||||
|
/// The latest vehicle model hash (may not have been applied yet)
|
||||||
|
/// </summary>
|
||||||
|
public int VehicleModelHash
|
||||||
|
{
|
||||||
|
get => CurrentVehicleModelHash;
|
||||||
|
internal set
|
||||||
|
{
|
||||||
|
LastVehicleModelHash = CurrentVehicleModelHash == 0 ? value : CurrentVehicleModelHash;
|
||||||
|
CurrentVehicleModelHash = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private int[] LastVehicleColors = new int[] { 0, 0 };
|
||||||
|
internal int[] VehicleColors { get; set; }
|
||||||
|
private Dictionary<int, int> LastVehicleMods = new Dictionary<int, int>();
|
||||||
|
internal Dictionary<int, int> VehicleMods { get; set; }
|
||||||
|
internal bool VehicleDead { get; set; }
|
||||||
|
internal float VehicleEngineHealth { get; set; }
|
||||||
|
internal int VehicleSeatIndex { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// ?
|
||||||
|
/// </summary>
|
||||||
|
public Vehicle MainVehicle { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The latest vehicle position (may not have been applied yet)
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 VehiclePosition { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The latest vehicle rotation (may not have been applied yet)
|
||||||
|
/// </summary>
|
||||||
|
public Quaternion VehicleRotation { get; internal set; }
|
||||||
|
internal Vector3 VehicleVelocity { get; set; }
|
||||||
|
private float LastVehicleSpeed { get; set; }
|
||||||
|
private float CurrentVehicleSpeed { get; set; }
|
||||||
|
internal float VehicleSpeed
|
||||||
|
{
|
||||||
|
get => CurrentVehicleSpeed;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
LastVehicleSpeed = CurrentVehicleSpeed;
|
||||||
|
CurrentVehicleSpeed = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal float VehicleSteeringAngle { get; set; }
|
||||||
|
private int LastVehicleAim;
|
||||||
|
internal bool VehIsEngineRunning { get; set; }
|
||||||
|
internal float VehRPM { get; set; }
|
||||||
|
private bool LastTransformed = false;
|
||||||
|
internal bool Transformed { get; set; }
|
||||||
|
private bool LastHornActive = false;
|
||||||
|
internal bool IsHornActive { get; set; }
|
||||||
|
internal bool VehAreLightsOn { get; set; }
|
||||||
|
internal bool VehAreHighBeamsOn { get; set; }
|
||||||
|
internal byte VehLandingGear { get; set; }
|
||||||
|
|
||||||
|
internal bool VehIsSireneActive { get; set; }
|
||||||
|
private VehicleDoors[] LastVehDoors;
|
||||||
|
internal VehicleDoors[] VehDoors { get; set; }
|
||||||
|
private int LastVehTires;
|
||||||
|
internal int VehTires { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void DisplayInVehicle()
|
||||||
|
{
|
||||||
|
if (MainVehicle == null || !MainVehicle.Exists() || MainVehicle.Model.Hash != CurrentVehicleModelHash)
|
||||||
|
{
|
||||||
|
bool vehFound = false;
|
||||||
|
|
||||||
|
if (NPCVehHandle != 0)
|
||||||
|
{
|
||||||
|
lock (Main.NPCsVehicles)
|
||||||
|
{
|
||||||
|
if (Main.NPCsVehicles.ContainsKey(NPCVehHandle))
|
||||||
|
{
|
||||||
|
Vehicle targetVehicle = World.GetAllVehicles().First(x => x.Handle == Main.NPCsVehicles[NPCVehHandle]);
|
||||||
|
if (targetVehicle == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainVehicle = targetVehicle;
|
||||||
|
vehFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vehicle targetVehicle = World.GetClosestVehicle(Position, 7f, new Model[] { CurrentVehicleModelHash });
|
||||||
|
|
||||||
|
if (targetVehicle != null)
|
||||||
|
{
|
||||||
|
if (targetVehicle.IsSeatFree((VehicleSeat)VehicleSeatIndex))
|
||||||
|
{
|
||||||
|
MainVehicle = targetVehicle;
|
||||||
|
vehFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vehFound)
|
||||||
|
{
|
||||||
|
Model vehicleModel = CurrentVehicleModelHash.ModelRequest();
|
||||||
|
if (vehicleModel == null)
|
||||||
|
{
|
||||||
|
//GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
|
||||||
|
ModelNotFound = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainVehicle = World.CreateVehicle(vehicleModel, VehiclePosition);
|
||||||
|
vehicleModel.MarkAsNoLongerNeeded();
|
||||||
|
if (NPCVehHandle != 0)
|
||||||
|
{
|
||||||
|
Main.NPCsVehicles.Add(NPCVehHandle, MainVehicle.Handle);
|
||||||
|
}
|
||||||
|
MainVehicle.Quaternion = VehicleRotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Character.IsInVehicle() || (int)Character.SeatIndex != VehicleSeatIndex || Character.CurrentVehicle.Handle != MainVehicle.Handle)
|
||||||
|
{
|
||||||
|
if (VehicleSeatIndex == -1 &&
|
||||||
|
Game.Player.Character.IsInVehicle() &&
|
||||||
|
(int)Game.Player.Character.SeatIndex == -1 &&
|
||||||
|
Game.Player.Character.CurrentVehicle.Handle == MainVehicle.Handle)
|
||||||
|
{
|
||||||
|
Game.Player.Character.Task.WarpOutOfVehicle(MainVehicle);
|
||||||
|
GTA.UI.Notification.Show("~r~Car jacked!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Character.SetIntoVehicle(MainVehicle, (VehicleSeat)VehicleSeatIndex);
|
||||||
|
Character.IsVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region -- VEHICLE SYNC --
|
||||||
|
if (AimCoords != default)
|
||||||
|
{
|
||||||
|
if (MainVehicle.IsTurretSeat(VehicleSeatIndex))
|
||||||
|
{
|
||||||
|
int gameTime = Game.GameTime;
|
||||||
|
if (gameTime - LastVehicleAim > 30)
|
||||||
|
{
|
||||||
|
Function.Call(Hash.TASK_VEHICLE_AIM_AT_COORD, Character.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z);
|
||||||
|
LastVehicleAim = gameTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MainVehicle.GetResponsiblePedHandle() != Character.Handle)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VehicleColors != null && VehicleColors != LastVehicleColors)
|
||||||
|
{
|
||||||
|
Function.Call(Hash.SET_VEHICLE_COLOURS, MainVehicle, VehicleColors[0], VehicleColors[1]);
|
||||||
|
|
||||||
|
LastVehicleColors = VehicleColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Character.IsOnBike && MainVehicle.ClassType == VehicleClass.Cycles)
|
||||||
|
{
|
||||||
|
bool isFastPedaling = Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Character.Handle, PedalingAnimDict(), "fast_pedal_char", 3);
|
||||||
|
if (CurrentVehicleSpeed < 0.2f)
|
||||||
|
{
|
||||||
|
StopPedalingAnim(isFastPedaling);
|
||||||
|
}
|
||||||
|
else if (CurrentVehicleSpeed < 11f && !Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Character.Handle, PedalingAnimDict(), "cruise_pedal_char", 3))
|
||||||
|
{
|
||||||
|
StartPedalingAnim(false);
|
||||||
|
}
|
||||||
|
else if (CurrentVehicleSpeed >= 11f && !isFastPedaling)
|
||||||
|
{
|
||||||
|
StartPedalingAnim(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (VehicleMods != null && VehicleMods != LastVehicleMods)
|
||||||
|
{
|
||||||
|
Function.Call(Hash.SET_VEHICLE_MOD_KIT, MainVehicle, 0);
|
||||||
|
|
||||||
|
foreach (KeyValuePair<int, int> mod in VehicleMods)
|
||||||
|
{
|
||||||
|
MainVehicle.Mods[(VehicleModType)mod.Key].Index = mod.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
LastVehicleMods = VehicleMods;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainVehicle.EngineHealth = VehicleEngineHealth;
|
||||||
|
|
||||||
|
if (VehicleDead && !MainVehicle.IsDead)
|
||||||
|
{
|
||||||
|
MainVehicle.Explode();
|
||||||
|
}
|
||||||
|
else if (!VehicleDead && MainVehicle.IsDead)
|
||||||
|
{
|
||||||
|
MainVehicle.Repair();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VehIsEngineRunning != MainVehicle.IsEngineRunning)
|
||||||
|
{
|
||||||
|
MainVehicle.IsEngineRunning = VehIsEngineRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainVehicle.CurrentRPM = VehRPM;
|
||||||
|
|
||||||
|
if (VehAreLightsOn != MainVehicle.AreLightsOn)
|
||||||
|
{
|
||||||
|
MainVehicle.AreLightsOn = VehAreLightsOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VehAreHighBeamsOn != MainVehicle.AreHighBeamsOn)
|
||||||
|
{
|
||||||
|
MainVehicle.AreHighBeamsOn = VehAreHighBeamsOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MainVehicle.IsSubmarineCar)
|
||||||
|
{
|
||||||
|
if (Transformed && !LastTransformed)
|
||||||
|
{
|
||||||
|
LastTransformed = true;
|
||||||
|
Function.Call(Hash._TRANSFORM_VEHICLE_TO_SUBMARINE, MainVehicle, false);
|
||||||
|
}
|
||||||
|
else if (!Transformed && LastTransformed)
|
||||||
|
{
|
||||||
|
LastTransformed = false;
|
||||||
|
Function.Call(Hash._TRANSFORM_SUBMARINE_TO_VEHICLE, MainVehicle, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MainVehicle.IsPlane)
|
||||||
|
{
|
||||||
|
if (VehLandingGear != (byte)MainVehicle.LandingGearState)
|
||||||
|
{
|
||||||
|
MainVehicle.LandingGearState = (VehicleLandingGearState)VehLandingGear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (MainVehicle.HasSiren && VehIsSireneActive != MainVehicle.IsSirenActive)
|
||||||
|
{
|
||||||
|
MainVehicle.IsSirenActive = VehIsSireneActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsHornActive && !LastHornActive)
|
||||||
|
{
|
||||||
|
LastHornActive = true;
|
||||||
|
MainVehicle.SoundHorn(99999);
|
||||||
|
}
|
||||||
|
else if (!IsHornActive && LastHornActive)
|
||||||
|
{
|
||||||
|
LastHornActive = false;
|
||||||
|
MainVehicle.SoundHorn(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle, CurrentVehicleSpeed > 0.2f && LastVehicleSpeed > CurrentVehicleSpeed);
|
||||||
|
|
||||||
|
if (LastSyncWasFull)
|
||||||
|
{
|
||||||
|
if (VehDoors != null && VehDoors != LastVehDoors)
|
||||||
|
{
|
||||||
|
int doorLength = VehDoors.Length;
|
||||||
|
if (VehDoors.Length != 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (doorLength - 1); i++)
|
||||||
|
{
|
||||||
|
VehicleDoor door = MainVehicle.Doors[(VehicleDoorIndex)i];
|
||||||
|
VehicleDoors aDoor = VehDoors[i];
|
||||||
|
|
||||||
|
if (aDoor.Broken)
|
||||||
|
{
|
||||||
|
if (!door.IsBroken)
|
||||||
|
{
|
||||||
|
door.Break();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (!aDoor.Broken && door.IsBroken)
|
||||||
|
{
|
||||||
|
// Repair?
|
||||||
|
//MainVehicle.Repair();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aDoor.FullyOpen)
|
||||||
|
{
|
||||||
|
if (!door.IsFullyOpen)
|
||||||
|
{
|
||||||
|
door.Open(false, true);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (aDoor.Open)
|
||||||
|
{
|
||||||
|
if (!door.IsOpen)
|
||||||
|
{
|
||||||
|
door.Open();
|
||||||
|
}
|
||||||
|
|
||||||
|
door.AngleRatio = aDoor.AngleRatio;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
door.Close(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LastVehDoors = VehDoors;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VehTires != default && LastVehTires != VehTires)
|
||||||
|
{
|
||||||
|
foreach (var wheel in MainVehicle.Wheels.GetAllWheels())
|
||||||
|
{
|
||||||
|
if ((VehTires & 1 << (int)wheel.BoneId) != 0)
|
||||||
|
{
|
||||||
|
wheel.Puncture();
|
||||||
|
wheel.Burst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LastVehTires = VehTires;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VehicleSteeringAngle != MainVehicle.SteeringAngle)
|
||||||
|
{
|
||||||
|
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * VehicleSteeringAngle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good enough for now, but we need to create a better sync
|
||||||
|
if (CurrentVehicleSpeed > 0.05f && MainVehicle.IsInRange(VehiclePosition, 7.0f))
|
||||||
|
{
|
||||||
|
int forceMultiplier = (Game.Player.Character.IsInVehicle() && MainVehicle.IsTouching(Game.Player.Character.CurrentVehicle)) ? 1 : 3;
|
||||||
|
|
||||||
|
MainVehicle.Velocity = VehicleVelocity + forceMultiplier * (VehiclePosition - MainVehicle.Position);
|
||||||
|
MainVehicle.Quaternion = Quaternion.Slerp(MainVehicle.Quaternion, VehicleRotation, 0.5f);
|
||||||
|
|
||||||
|
VehicleStopTime = Util.GetTickCount64();
|
||||||
|
}
|
||||||
|
else if ((Util.GetTickCount64() - VehicleStopTime) <= 1000)
|
||||||
|
{
|
||||||
|
Vector3 posTarget = Util.LinearVectorLerp(MainVehicle.Position, VehiclePosition + (VehiclePosition - MainVehicle.Position), Util.GetTickCount64() - VehicleStopTime, 1000);
|
||||||
|
|
||||||
|
MainVehicle.PositionNoOffset = posTarget;
|
||||||
|
MainVehicle.Quaternion = Quaternion.Slerp(MainVehicle.Quaternion, VehicleRotation, 0.5f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MainVehicle.PositionNoOffset = VehiclePosition;
|
||||||
|
MainVehicle.Quaternion = VehicleRotation;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#region -- PEDALING --
|
||||||
|
/*
|
||||||
|
* Thanks to @oldnapalm.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private string PedalingAnimDict()
|
||||||
|
{
|
||||||
|
switch ((VehicleHash)CurrentVehicleModelHash)
|
||||||
|
{
|
||||||
|
case VehicleHash.Bmx:
|
||||||
|
return "veh@bicycle@bmx@front@base";
|
||||||
|
case VehicleHash.Cruiser:
|
||||||
|
return "veh@bicycle@cruiserfront@base";
|
||||||
|
case VehicleHash.Scorcher:
|
||||||
|
return "veh@bicycle@mountainfront@base";
|
||||||
|
default:
|
||||||
|
return "veh@bicycle@roadfront@base";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string PedalingAnimName(bool fast)
|
||||||
|
{
|
||||||
|
return fast ? "fast_pedal_char" : "cruise_pedal_char";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartPedalingAnim(bool fast)
|
||||||
|
{
|
||||||
|
Character.Task.PlayAnimation(PedalingAnimDict(), PedalingAnimName(fast), 8.0f, -8.0f, -1, AnimationFlags.Loop | AnimationFlags.AllowRotation, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopPedalingAnim(bool fast)
|
||||||
|
{
|
||||||
|
Character.Task.ClearAnimation(PedalingAnimDict(), PedalingAnimName(fast));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -251,6 +251,7 @@ namespace CoopClient
|
|||||||
private void Debug()
|
private void Debug()
|
||||||
{
|
{
|
||||||
Ped player = Game.Player.Character;
|
Ped player = Game.Player.Character;
|
||||||
|
|
||||||
if (!Players.ContainsKey(0))
|
if (!Players.ContainsKey(0))
|
||||||
{
|
{
|
||||||
Players.Add(0, new EntitiesPlayer() { SocialClubName = "DEBUG", Username = "DebugPlayer" });
|
Players.Add(0, new EntitiesPlayer() { SocialClubName = "DEBUG", Username = "DebugPlayer" });
|
||||||
@ -327,7 +328,7 @@ namespace CoopClient
|
|||||||
DebugSyncPed.Velocity = player.Velocity;
|
DebugSyncPed.Velocity = player.Velocity;
|
||||||
DebugSyncPed.Speed = player.GetPedSpeed();
|
DebugSyncPed.Speed = player.GetPedSpeed();
|
||||||
DebugSyncPed.AimCoords = player.GetPedAimCoords(false);
|
DebugSyncPed.AimCoords = player.GetPedAimCoords(false);
|
||||||
DebugSyncPed.CurrentWeaponHash = (int)player.Weapons.Current.Hash;
|
DebugSyncPed.CurrentWeaponHash = (uint)player.Weapons.Current.Hash;
|
||||||
DebugSyncPed.WeaponComponents = player.Weapons.Current.GetWeaponComponents();
|
DebugSyncPed.WeaponComponents = player.Weapons.Current.GetWeaponComponents();
|
||||||
DebugSyncPed.LastSyncWasFull = true;
|
DebugSyncPed.LastSyncWasFull = true;
|
||||||
DebugSyncPed.IsAiming = (flags.Value & (byte)PedDataFlags.IsAiming) > 0;
|
DebugSyncPed.IsAiming = (flags.Value & (byte)PedDataFlags.IsAiming) > 0;
|
||||||
|
@ -771,7 +771,7 @@ namespace CoopClient
|
|||||||
Velocity = player.Velocity.ToLVector(),
|
Velocity = player.Velocity.ToLVector(),
|
||||||
Speed = player.GetPedSpeed(),
|
Speed = player.GetPedSpeed(),
|
||||||
AimCoords = player.GetPedAimCoords(false).ToLVector(),
|
AimCoords = player.GetPedAimCoords(false).ToLVector(),
|
||||||
CurrentWeaponHash = (int)player.Weapons.Current.Hash,
|
CurrentWeaponHash = (uint)player.Weapons.Current.Hash,
|
||||||
WeaponComponents = player.Weapons.Current.GetWeaponComponents(),
|
WeaponComponents = player.Weapons.Current.GetWeaponComponents(),
|
||||||
Flag = player.GetPedFlags(true)
|
Flag = player.GetPedFlags(true)
|
||||||
}.PacketToNetOutGoingMessage(outgoingMessage);
|
}.PacketToNetOutGoingMessage(outgoingMessage);
|
||||||
@ -819,7 +819,7 @@ namespace CoopClient
|
|||||||
Velocity = player.Velocity.ToLVector(),
|
Velocity = player.Velocity.ToLVector(),
|
||||||
Speed = player.GetPedSpeed(),
|
Speed = player.GetPedSpeed(),
|
||||||
AimCoords = player.GetPedAimCoords(false).ToLVector(),
|
AimCoords = player.GetPedAimCoords(false).ToLVector(),
|
||||||
CurrentWeaponHash = (int)player.Weapons.Current.Hash,
|
CurrentWeaponHash = (uint)player.Weapons.Current.Hash,
|
||||||
Flag = player.GetPedFlags(true)
|
Flag = player.GetPedFlags(true)
|
||||||
}.PacketToNetOutGoingMessage(outgoingMessage);
|
}.PacketToNetOutGoingMessage(outgoingMessage);
|
||||||
}
|
}
|
||||||
@ -890,7 +890,7 @@ namespace CoopClient
|
|||||||
Velocity = npc.Velocity.ToLVector(),
|
Velocity = npc.Velocity.ToLVector(),
|
||||||
Speed = npc.GetPedSpeed(),
|
Speed = npc.GetPedSpeed(),
|
||||||
AimCoords = npc.GetPedAimCoords(true).ToLVector(),
|
AimCoords = npc.GetPedAimCoords(true).ToLVector(),
|
||||||
CurrentWeaponHash = (int)npc.Weapons.Current.Hash,
|
CurrentWeaponHash = (uint)npc.Weapons.Current.Hash,
|
||||||
Flag = npc.GetPedFlags(true)
|
Flag = npc.GetPedFlags(true)
|
||||||
}.PacketToNetOutGoingMessage(outgoingMessage);
|
}.PacketToNetOutGoingMessage(outgoingMessage);
|
||||||
}
|
}
|
||||||
|
@ -410,10 +410,10 @@ namespace CoopClient
|
|||||||
public LVector3 AimCoords { get; set; }
|
public LVector3 AimCoords { get; set; }
|
||||||
|
|
||||||
[ProtoMember(8)]
|
[ProtoMember(8)]
|
||||||
public int CurrentWeaponHash { get; set; }
|
public uint CurrentWeaponHash { get; set; }
|
||||||
|
|
||||||
[ProtoMember(9)]
|
[ProtoMember(9)]
|
||||||
public List<uint> WeaponComponents { get; set; }
|
public Dictionary<uint, bool> WeaponComponents { get; set; }
|
||||||
|
|
||||||
[ProtoMember(10)]
|
[ProtoMember(10)]
|
||||||
public byte? Flag { get; set; } = 0;
|
public byte? Flag { get; set; } = 0;
|
||||||
@ -564,7 +564,7 @@ namespace CoopClient
|
|||||||
public LVector3 AimCoords { get; set; }
|
public LVector3 AimCoords { get; set; }
|
||||||
|
|
||||||
[ProtoMember(6)]
|
[ProtoMember(6)]
|
||||||
public int CurrentWeaponHash { get; set; }
|
public uint CurrentWeaponHash { get; set; }
|
||||||
|
|
||||||
[ProtoMember(7)]
|
[ProtoMember(7)]
|
||||||
public byte? Flag { get; set; } = 0;
|
public byte? Flag { get; set; } = 0;
|
||||||
@ -855,7 +855,7 @@ namespace CoopClient
|
|||||||
public LVector3 AimCoords { get; set; }
|
public LVector3 AimCoords { get; set; }
|
||||||
|
|
||||||
[ProtoMember(10)]
|
[ProtoMember(10)]
|
||||||
public int CurrentWeaponHash { get; set; }
|
public uint CurrentWeaponHash { get; set; }
|
||||||
|
|
||||||
[ProtoMember(11)]
|
[ProtoMember(11)]
|
||||||
public byte? Flag { get; set; } = 0;
|
public byte? Flag { get; set; } = 0;
|
||||||
|
@ -236,17 +236,17 @@ namespace CoopClient
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<uint> GetWeaponComponents(this Weapon weapon)
|
public static Dictionary<uint, bool> GetWeaponComponents(this Weapon weapon)
|
||||||
{
|
{
|
||||||
List<uint> result = null;
|
Dictionary<uint, bool> result = null;
|
||||||
|
|
||||||
if (weapon.Components.Count > 0)
|
if (weapon.Components.Count > 0)
|
||||||
{
|
{
|
||||||
result = new List<uint>();
|
result = new Dictionary<uint, bool>();
|
||||||
|
|
||||||
foreach (var comp in weapon.Components)
|
foreach (var comp in weapon.Components)
|
||||||
{
|
{
|
||||||
result.Add((uint)comp.ComponentHash);
|
result.Add((uint)comp.ComponentHash, comp.Active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,10 +325,10 @@ namespace CoopServer
|
|||||||
public LVector3 AimCoords { get; set; }
|
public LVector3 AimCoords { get; set; }
|
||||||
|
|
||||||
[ProtoMember(8)]
|
[ProtoMember(8)]
|
||||||
public int CurrentWeaponHash { get; set; }
|
public uint CurrentWeaponHash { get; set; }
|
||||||
|
|
||||||
[ProtoMember(9)]
|
[ProtoMember(9)]
|
||||||
public List<uint> WeaponComponents { get; set; }
|
public Dictionary<uint, bool> WeaponComponents { get; set; }
|
||||||
|
|
||||||
[ProtoMember(10)]
|
[ProtoMember(10)]
|
||||||
public byte? Flag { get; set; } = 0;
|
public byte? Flag { get; set; } = 0;
|
||||||
@ -479,7 +479,7 @@ namespace CoopServer
|
|||||||
public LVector3 AimCoords { get; set; }
|
public LVector3 AimCoords { get; set; }
|
||||||
|
|
||||||
[ProtoMember(6)]
|
[ProtoMember(6)]
|
||||||
public int CurrentWeaponHash { get; set; }
|
public uint CurrentWeaponHash { get; set; }
|
||||||
|
|
||||||
[ProtoMember(7)]
|
[ProtoMember(7)]
|
||||||
public byte? Flag { get; set; } = 0;
|
public byte? Flag { get; set; } = 0;
|
||||||
@ -770,7 +770,7 @@ namespace CoopServer
|
|||||||
public LVector3 AimCoords { get; set; }
|
public LVector3 AimCoords { get; set; }
|
||||||
|
|
||||||
[ProtoMember(10)]
|
[ProtoMember(10)]
|
||||||
public int CurrentWeaponHash { get; set; }
|
public uint CurrentWeaponHash { get; set; }
|
||||||
|
|
||||||
[ProtoMember(11)]
|
[ProtoMember(11)]
|
||||||
public byte? Flag { get; set; } = 0;
|
public byte? Flag { get; set; } = 0;
|
||||||
|
Reference in New Issue
Block a user