Projectile refactor

This commit is contained in:
Sardelka 2022-08-14 17:08:43 +08:00
parent 4acf964f0a
commit b5f6fc578d
9 changed files with 120 additions and 75 deletions

View File

@ -416,17 +416,17 @@ namespace RageCoop.Client
var p = EntityPool.GetProjectileByID(packet.ID); var p = EntityPool.GetProjectileByID(packet.ID);
if (p==null) if (p==null)
{ {
if (packet.Flags.HasProjDataFlag(ProjectileDataFlags.Exploded)) { return; }
if (packet.Exploded) { return; }
// Main.Logger.Debug($"Creating new projectile: {(WeaponHash)packet.WeaponHash}"); // Main.Logger.Debug($"Creating new projectile: {(WeaponHash)packet.WeaponHash}");
EntityPool.ThreadSafe.Add(p=new SyncedProjectile(packet.ID)); EntityPool.ThreadSafe.Add(p=new SyncedProjectile(packet.ID));
} }
p.Flags=packet.Flags;
p.Position=packet.Position; p.Position=packet.Position;
p.Rotation=packet.Rotation; p.Rotation=packet.Rotation;
p.Velocity=packet.Velocity; p.Velocity=packet.Velocity;
p.Hash=(WeaponHash)packet.WeaponHash; p.WeaponHash=(WeaponHash)packet.WeaponHash;
p.ShooterID=packet.ShooterID; p.Shooter= packet.Flags.HasProjDataFlag(ProjectileDataFlags.IsShotByVehicle) ?
p.Exploded=packet.Exploded; (SyncedEntity)EntityPool.GetVehicleByID(packet.ShooterID) : EntityPool.GetPedByID(packet.ShooterID);
p.LastSynced=Main.Ticked; p.LastSynced=Main.Ticked;
} }
} }

View File

@ -164,17 +164,9 @@ namespace RageCoop.Client
} }
public static void SendProjectile(SyncedProjectile sp) public static void SendProjectile(SyncedProjectile sp)
{ {
var p = sp.MainProjectile; sp.ExtractData(ref SendPackets.ProjectilePacket);
var packet = SendPackets.ProjectilePacket; if (sp.MainProjectile.IsDead) { EntityPool.RemoveProjectile(sp.ID, "Dead"); }
packet.ID =sp.ID; SendSync(SendPackets.ProjectilePacket, ConnectionChannel.ProjectileSync);
packet.ShooterID=sp.ShooterID;
packet.Rotation=p.Rotation;
packet.Position=p.Position;
packet.Velocity=p.Velocity;
packet.WeaponHash=(uint)p.WeaponHash;
packet.Exploded=p.IsDead;
if (p.IsDead) { EntityPool.RemoveProjectile(sp.ID, "Dead"); }
SendSync(packet, ConnectionChannel.ProjectileSync);
} }

View File

@ -39,7 +39,7 @@ namespace RageCoop.Client
} }
} }
internal Player Owner { get; private set; } internal virtual Player Owner { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>

View File

@ -667,9 +667,12 @@ namespace RageCoop.Client
MainPed.PositionNoOffset=Position; MainPed.PositionNoOffset=Position;
return; return;
} }
if (!(localRagdoll || MainPed.IsDead || IsAiming)) if (!(localRagdoll || MainPed.IsDead))
{ {
MainPed.Heading=Heading; if (!IsAiming)
{
MainPed.Heading=Heading;
}
MainPed.Velocity=Velocity+5*dist*(Position-MainPed.ReadPosition()); MainPed.Velocity=Velocity+5*dist*(Position-MainPed.ReadPosition());
} }
else if (Main.Ticked-_lastRagdollTime<10) else if (Main.Ticked-_lastRagdollTime<10)

View File

@ -1,61 +1,95 @@
using GTA; using GTA;
using GTA.Math; using GTA.Math;
using RageCoop.Core; using RageCoop.Core;
using GTA.Native;
namespace RageCoop.Client namespace RageCoop.Client
{ {
internal class SyncedProjectile : SyncedEntity internal class SyncedProjectile : SyncedEntity
{ {
public ProjectileDataFlags Flags { private get; set; }=ProjectileDataFlags.None;
public readonly Vector3 Origin;
private bool _firstSend = false;
public bool IsValid { get; private set; } = true;
public new bool IsLocal { get; private set; } = false;
public Projectile MainProjectile { get; set; }
public SyncedEntity Shooter { get; set; }
public bool Exploded => Flags.HasProjDataFlag(ProjectileDataFlags.Exploded);
/// <summary>
/// Invalid property for projectile.
/// </summary>
private new int OwnerID { set { } }
internal override Player Owner => Shooter.Owner;
public WeaponHash WeaponHash { get; set; }
private WeaponAsset Asset { get; set; }
public void ExtractData(ref Packets.ProjectileSync p)
{
p.Position=MainProjectile.Position;
p.Velocity=MainProjectile.Velocity;
p.Rotation=MainProjectile.Rotation;
p.ID=ID;
p.ShooterID=Shooter.ID;
p.WeaponHash=(uint)MainProjectile.WeaponHash;
p.Flags=ProjectileDataFlags.None;
if (MainProjectile.IsDead)
{
p.Flags |= ProjectileDataFlags.Exploded;
}
if (MainProjectile.AttachedEntity!=null)
{
p.Flags |= ProjectileDataFlags.IsAttached;
}
if (Shooter is SyncedVehicle)
{
p.Flags |= ProjectileDataFlags.IsShotByVehicle;
}
if (_firstSend)
{
p.Flags |= ProjectileDataFlags.IsAttached;
_firstSend=false;
}
}
public SyncedProjectile(Projectile p) public SyncedProjectile(Projectile p)
{ {
var owner = p.OwnerEntity;
if (owner==null) { IsValid=false;return; }
ID=EntityPool.RequestNewID(); ID=EntityPool.RequestNewID();
MainProjectile = p; MainProjectile = p;
Origin=p.Position; Origin=p.Position;
var shooter = EntityPool.GetPedByHandle((p.OwnerEntity?.Handle).GetValueOrDefault()); if(EntityPool.PedsByHandle.TryGetValue(owner.Handle,out var shooter))
if (shooter==null)
{ {
// Owner will be the vehicle if projectile is shot with a vehicle if (shooter.MainPed!=null
var shooterVeh = EntityPool.GetVehicleByHandle((p.OwnerEntity?.Handle).GetValueOrDefault()); && (p.AttachedEntity==shooter.MainPed.Weapons.CurrentWeaponObject
if (shooterVeh!=null && shooterVeh.MainVehicle.Driver!=null) || p.AttachedEntity== shooter.MainPed))
{
shooter=shooterVeh.MainVehicle.Driver?.GetSyncEntity();
}
else
{
Main.Logger.Warning($"Could not find owner for projectile:{Hash}");
}
}
if (shooter != null)
{
if (shooter.MainPed!=null && (p.AttachedEntity==shooter.MainPed.Weapons.CurrentWeaponObject || p.AttachedEntity== shooter.MainPed))
{ {
// Reloading // Reloading
IsValid=false; IsValid=false;
return;
} }
ShooterID=shooter.ID; Shooter=shooter;
IsLocal=shooter.IsLocal; IsLocal=shooter.IsLocal;
} }
else if(EntityPool.VehiclesByHandle.TryGetValue(owner.Handle,out var shooterVeh))
{
Shooter=shooterVeh;
IsLocal=shooterVeh.IsLocal;
}
else
{
IsValid=false;
}
} }
public SyncedProjectile(int id) public SyncedProjectile(int id)
{ {
ID= id; ID= id;
IsLocal=false; IsLocal=false;
} }
public bool IsValid { get; private set; } = true;
public new bool IsLocal { get; private set; } = false;
public bool Exploded { get; set; } = false;
public Projectile MainProjectile { get; set; }
public int ShooterID { get; set; }
private SyncedPed Shooter { get; set; }
public Vector3 Origin { get; set; }
/// <summary>
/// Invalid property for projectile.
/// </summary>
private new int OwnerID { set { } }
public WeaponHash Hash { get; set; }
private WeaponAsset Asset { get; set; }
internal override void Update() internal override void Update()
{ {
@ -74,19 +108,20 @@ namespace RageCoop.Client
private void CreateProjectile() private void CreateProjectile()
{ {
Asset=new WeaponAsset(Hash); Asset=new WeaponAsset(WeaponHash);
if (!Asset.IsLoaded) { Asset.Request(); } if (!Asset.IsLoaded) { Asset.Request(); return; }
World.ShootBullet(Position, Position+Velocity, (Shooter=EntityPool.GetPedByID(ShooterID))?.MainPed, Asset, 0); if(Shooter == null) { return; }
Entity owner;
owner=(Shooter as SyncedPed)?.MainPed ?? (Entity)(Shooter as SyncedVehicle)?.MainVehicle;
var end = Position+Velocity;
Function.Call(Hash.SHOOT_SINGLE_BULLET_BETWEEN_COORDS_IGNORE_ENTITY, Position.X, Position.Y, Position.Z, end.X, end.Y, end.Z, 0, 1, WeaponHash, owner?.Handle ?? 0, 1, 0, -1,owner);
var ps = World.GetAllProjectiles(); var ps = World.GetAllProjectiles();
MainProjectile=ps[ps.Length-1]; MainProjectile=ps[ps.Length-1];
if (Hash==(WeaponHash)VehicleWeaponHash.Tank) MainProjectile.IsCollisionEnabled=false;
{ MainProjectile.Position=Position;
var v = Shooter?.MainPed?.CurrentVehicle; MainProjectile.Rotation =Rotation;
if (v!=null) MainProjectile.Velocity=Velocity;
{ Main.Delay(()=>MainProjectile.IsCollisionEnabled=true, 100);
World.CreateParticleEffectNonLooped(SyncEvents.CorePFXAsset, "muz_tank", v.Bones[v.GetMuzzleIndex()].Position, v.Bones[35].ForwardVector.ToEulerRotation(v.Bones[35].UpVector), 1);
}
}
EntityPool.Add(this); EntityPool.Add(this);
} }
} }

View File

@ -19,15 +19,15 @@ namespace RageCoop.Client
#endif #endif
#region ACTIVE INSTANCES #region ACTIVE INSTANCES
private static Dictionary<int, SyncedPed> PedsByID = new Dictionary<int, SyncedPed>(); public static Dictionary<int, SyncedPed> PedsByID = new Dictionary<int, SyncedPed>();
private static Dictionary<int, SyncedPed> PedsByHandle = new Dictionary<int, SyncedPed>(); public static Dictionary<int, SyncedPed> PedsByHandle = new Dictionary<int, SyncedPed>();
private static Dictionary<int, SyncedVehicle> VehiclesByID = new Dictionary<int, SyncedVehicle>(); public static Dictionary<int, SyncedVehicle> VehiclesByID = new Dictionary<int, SyncedVehicle>();
private static Dictionary<int, SyncedVehicle> VehiclesByHandle = new Dictionary<int, SyncedVehicle>(); public static Dictionary<int, SyncedVehicle> VehiclesByHandle = new Dictionary<int, SyncedVehicle>();
private static Dictionary<int, SyncedProjectile> ProjectilesByID = new Dictionary<int, SyncedProjectile>(); public static Dictionary<int, SyncedProjectile> ProjectilesByID = new Dictionary<int, SyncedProjectile>();
private static Dictionary<int, SyncedProjectile> ProjectilesByHandle = new Dictionary<int, SyncedProjectile>(); public static Dictionary<int, SyncedProjectile> ProjectilesByHandle = new Dictionary<int, SyncedProjectile>();
public static Dictionary<int, SyncedProp> ServerProps = new Dictionary<int, SyncedProp>(); public static Dictionary<int, SyncedProp> ServerProps = new Dictionary<int, SyncedProp>();
public static Dictionary<int, Blip> ServerBlips = new Dictionary<int, Blip>(); public static Dictionary<int, Blip> ServerBlips = new Dictionary<int, Blip>();
@ -62,7 +62,7 @@ namespace RageCoop.Client
foreach (var p in ProjectilesByID.Values) foreach (var p in ProjectilesByID.Values)
{ {
if (p.ShooterID!=Main.LocalPlayerID && p.MainProjectile!=null && p.MainProjectile.Exists()) if (p.Shooter.ID!=Main.LocalPlayerID && p.MainProjectile!=null && p.MainProjectile.Exists())
{ {
p.MainProjectile.Delete(); p.MainProjectile.Delete();
} }
@ -242,6 +242,10 @@ namespace RageCoop.Client
public static void Add(SyncedProjectile p) public static void Add(SyncedProjectile p)
{ {
if (!p.IsValid) { return; } if (!p.IsValid) { return; }
if (p.WeaponHash==(WeaponHash)VehicleWeaponHash.Tank)
{
Networking.SendBullet(p.Position, p.Position+p.Velocity, (uint)VehicleWeaponHash.Tank, ((SyncedVehicle)p.Shooter).MainVehicle.Driver.GetSyncEntity().ID);
}
if (ProjectilesByID.ContainsKey(p.ID)) if (ProjectilesByID.ContainsKey(p.ID))
{ {
ProjectilesByID[p.ID]=p; ProjectilesByID[p.ID]=p;
@ -339,12 +343,10 @@ namespace RageCoop.Client
if (p.MainProjectile.AttachedEntity==null) if (p.MainProjectile.AttachedEntity==null)
{ {
// Prevent projectiles from exploding next to vehicle // Prevent projectiles from exploding next to vehicle
if (WeaponUtil.VehicleProjectileWeapons.Contains((VehicleWeaponHash)p.MainProjectile.WeaponHash) && if (p.WeaponHash==(WeaponHash)VehicleWeaponHash.Tank )
p.MainProjectile.WeaponHash != (WeaponHash)VehicleWeaponHash.Tank && p.Origin.DistanceTo(p.MainProjectile.Position) < 2)
{ {
continue; continue;
} }
Networking.SendProjectile(p); Networking.SendProjectile(p);
} }
} }

View File

@ -305,6 +305,10 @@ namespace RageCoop.Core
{ {
return (flagToCheck & flag)!=0; return (flagToCheck & flag)!=0;
} }
public static bool HasProjDataFlag(this ProjectileDataFlags flagToCheck, ProjectileDataFlags flag)
{
return (flagToCheck & flag)!=0;
}
public static bool HasVehFlag(this VehicleDataFlags flagToCheck, VehicleDataFlags flag) public static bool HasVehFlag(this VehicleDataFlags flagToCheck, VehicleDataFlags flag)
{ {

View File

@ -97,6 +97,15 @@ namespace RageCoop.Core
IsInCover = 1 << 10, IsInCover = 1 << 10,
IsFullSync = 1<<15 , IsFullSync = 1<<15 ,
} }
internal enum ProjectileDataFlags:byte
{
None = 0,
Exploded = 1 << 0,
IsAttached = 1 << 1,
IsOrgin = 1 << 2,
IsShotByVehicle = 1 << 3,
}
#region ===== VEHICLE DATA ===== #region ===== VEHICLE DATA =====
internal enum VehicleDataFlags:ushort internal enum VehicleDataFlags:ushort
{ {

View File

@ -22,7 +22,7 @@ namespace RageCoop.Core
public Vector3 Velocity { get; set; } public Vector3 Velocity { get; set; }
public bool Exploded { get; set; } public ProjectileDataFlags Flags { get; set; }
@ -48,7 +48,7 @@ namespace RageCoop.Core
// Write velocity // Write velocity
byteArray.AddVector3(Velocity); byteArray.AddVector3(Velocity);
byteArray.AddBool(Exploded); byteArray.Add((byte)Flags);
return byteArray.ToArray(); return byteArray.ToArray();
@ -76,7 +76,7 @@ namespace RageCoop.Core
// Read velocity // Read velocity
Velocity =reader.ReadVector3(); Velocity =reader.ReadVector3();
Exploded=reader.ReadBoolean(); Flags=(ProjectileDataFlags)reader.ReadByte();
#endregion #endregion
} }