using GTA;
using GTA.Math;
using GTA.Native;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
namespace RageCoop.Client
{
///
/// A synchronized vehicle instance
///
public partial class SyncedVehicle : SyncedEntity
{
#region -- CONSTRUCTORS --
///
/// Create a local entity (outgoing sync)
///
///
internal SyncedVehicle(Vehicle v)
{
ID=EntityPool.RequestNewID();
MainVehicle=v;
MainVehicle.CanPretendOccupants=false;
OwnerID=Main.LocalPlayerID;
SetUpFixedData();
}
private void SetUpFixedData(){
IsAircraft = MainVehicle.IsAircraft;
IsMotorcycle = MainVehicle.IsMotorcycle;
HasRocketBoost = MainVehicle.HasRocketBoost;
HasParachute = MainVehicle.HasParachute;
HasRoof = MainVehicle.HasRoof;
IsSubmarineCar=MainVehicle.IsSubmarineCar;
IsDeluxo=MainVehicle.Model==1483171323;
}
///
/// Create an empty VehicleEntity
///
internal SyncedVehicle()
{
}
internal SyncedVehicle(int id)
{
ID=id;
LastSynced=Main.Ticked;
}
#endregion
///
/// VehicleSeat,ID
///
internal override void Update()
{
#if DEBUG_VEH
foreach(var s in _predictedTrace)
{
World.DrawMarker(MarkerType.DebugSphere, s, default, default, new Vector3(0.3f, 0.3f, 0.3f), Color.AliceBlue);
}
foreach (var s in _orgTrace)
{
World.DrawMarker(MarkerType.DebugSphere, s, default, default, new Vector3(0.3f, 0.3f, 0.3f), Color.Orange);
}
#endif
// Check if all data avalible
if (!IsReady || Owner == null) { return; }
// Check existence
if ((MainVehicle == null) || (!MainVehicle.Exists()) || (MainVehicle.Model != Model))
{
if (!CreateVehicle())
{
return;
}
}
DisplayVehicle();
// Skip update if no new sync message has arrived.
if (!NeedUpdate)
{
return;
}
if (SteeringAngle != MainVehicle.SteeringAngle)
{
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * SteeringAngle);
}
MainVehicle.ThrottlePower=ThrottlePower;
MainVehicle.BrakePower=BrakePower;
if (IsDead)
{
if (MainVehicle.IsDead)
{
return;
}
MainVehicle.Explode();
}
else
{
if (MainVehicle.IsDead)
{
Main.Delay(() =>
{
if (MainVehicle.IsDead && !IsDead)
{
MainVehicle.Repair();
}
},1000);
}
}
if (MainVehicle.IsOnFire)
{
if (!Flags.HasVehFlag(VehicleDataFlags.IsOnFire))
{
Function.Call(Hash.STOP_ENTITY_FIRE, MainVehicle);
}
}
else if (Flags.HasVehFlag(VehicleDataFlags.IsOnFire))
{
Function.Call(Hash.START_ENTITY_FIRE, MainVehicle);
}
if (EngineRunning != MainVehicle.IsEngineRunning)
{
MainVehicle.IsEngineRunning = EngineRunning;
}
if (LightsOn != MainVehicle.AreLightsOn)
{
MainVehicle.AreLightsOn = LightsOn;
}
if (HighBeamsOn != MainVehicle.AreHighBeamsOn)
{
MainVehicle.AreHighBeamsOn = HighBeamsOn;
}
if (IsAircraft)
{
if (LandingGear != (byte)MainVehicle.LandingGearState)
{
MainVehicle.LandingGearState = (VehicleLandingGearState)LandingGear;
}
}
else
{
if (MainVehicle.HasSiren && SireneActive != MainVehicle.IsSirenActive)
{
MainVehicle.IsSirenActive = SireneActive;
}
if (HornActive)
{
if (!_lastHornActive)
{
_lastHornActive = true;
MainVehicle.SoundHorn(99999);
}
}
else if (_lastHornActive)
{
_lastHornActive = false;
MainVehicle.SoundHorn(1);
}
if (HasRoof && MainVehicle.RoofState!=RoofState)
{
MainVehicle.RoofState=RoofState;
}
if(HasRocketBoost && Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive) != MainVehicle.IsRocketBoostActive()){
MainVehicle.SetRocketBoostActive(Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive));
}
if(HasParachute && Flags.HasFlag(VehicleDataFlags.IsParachuteActive) != MainVehicle.IsParachuteActive()){
MainVehicle.SetParachuteActive(Flags.HasFlag(VehicleDataFlags.IsParachuteActive));
}
if (IsSubmarineCar)
{
if (Transformed)
{
if (!_lastTransformed)
{
_lastTransformed = true;
Function.Call(Hash._TRANSFORM_VEHICLE_TO_SUBMARINE, MainVehicle.Handle, false);
}
}
else if (_lastTransformed)
{
_lastTransformed = false;
Function.Call(Hash._TRANSFORM_SUBMARINE_TO_VEHICLE, MainVehicle.Handle, false);
}
}
else if(IsDeluxo && IsDeluxoHovering!=MainVehicle.IsDeluxoHovering()){
MainVehicle.SetDeluxoHoverState(IsDeluxoHovering);
if(IsDeluxoHovering){
MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
}
}
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
}
MainVehicle.LockStatus=LockStatus;
if (LastFullSynced>=LastUpdated)
{
if (Flags.HasVehFlag(VehicleDataFlags.Repaired))
{
MainVehicle.Repair();
}
if (Colors != null && Colors != _lastVehicleColors)
{
Function.Call(Hash.SET_VEHICLE_COLOURS, MainVehicle, Colors[0], Colors[1]);
_lastVehicleColors = Colors;
}
MainVehicle.EngineHealth=EngineHealth;
if (Mods != null && !Mods.Compare(_lastVehicleMods))
{
Function.Call(Hash.SET_VEHICLE_MOD_KIT, MainVehicle, 0);
foreach (KeyValuePair mod in Mods)
{
MainVehicle.Mods[(VehicleModType)mod.Key].Index = mod.Value;
}
_lastVehicleMods = Mods;
}
if (Function.Call(Hash.GET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle)!=LicensePlate)
{
Function.Call(Hash.SET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle, LicensePlate);
}
if (_lastLivery!=Livery)
{
Function.Call(Hash.SET_VEHICLE_LIVERY, MainVehicle, Livery);
_lastLivery=Livery;
}
MainVehicle.SetDamageModel(DamageModel);
}
LastUpdated=Main.Ticked;
}
void DisplayVehicle()
{
_elapsed = Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds;
_predictedPosition = Position + _elapsed * Velocity;
var current = MainVehicle.ReadPosition();
var dist = current.DistanceTo(_predictedPosition);
var cali = dist * (_predictedPosition - current);
if (Velocity.Length() < 0.1) { cali *= 10; }
if (dist > 10)
{
MainVehicle.Position = _predictedPosition;
MainVehicle.Velocity = Velocity;
MainVehicle.Quaternion = Quaternion;
return;
}
else if (dist <= 0.03)
{
return;
}
MainVehicle.Velocity = Velocity+cali;
Vector3 calirot;
if (IsFlipped || (calirot = GetCalibrationRotation()).Length()>50)
{
MainVehicle.Quaternion = Quaternion.Slerp(MainVehicle.ReadQuaternion(), Quaternion, 0.5f);
MainVehicle.RotationVelocity = RotationVelocity;
return;
}
else
{
MainVehicle.RotationVelocity = RotationVelocity + calirot * 0.2f;
}
#if DEBUG_VEH
if (_orgTrace.Count >= 30)
{
_orgTrace.RemoveAt(0);
}
if (_predictedTrace.Count >= 30)
{
_predictedTrace.RemoveAt(0);
}
_orgTrace.Add(Position);
_predictedTrace.Add(_predictedPos);
#endif
}
private Vector3 GetCalibrationRotation()
{
var rot = Quaternion.LookRotation(Quaternion*Vector3.RelativeFront, Quaternion*Vector3.RelativeTop).ToEulerAngles();
var curRot = Quaternion.LookRotation(MainVehicle.ReadQuaternion()*Vector3.RelativeFront, MainVehicle.ReadQuaternion()*Vector3.RelativeTop).ToEulerAngles();
var r = (rot-curRot).ToDegree();
if (r.X>180) { r.X=r.X-360; }
else if (r.X<-180) { r.X=360+r.X; }
if (r.Y>180) { r.Y=r.Y-360; }
else if (r.Y<-180) { r.Y=360+r.Y; }
if (r.Z>180) { r.Z=r.Z-360; }
else if (r.Z<-180) { r.Z=360+r.Z; }
return r;
}
private bool CreateVehicle()
{
MainVehicle?.Delete();
MainVehicle = Util.CreateVehicle(Model, Position);
if (!Model.IsInCdImage)
{
// GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
return false;
}
else if (MainVehicle==null)
{
Model.Request();
return false;
}
lock (EntityPool.VehiclesLock)
{
EntityPool.Add(this);
}
MainVehicle.Quaternion = Quaternion;
if (MainVehicle.HasRoof)
{
MainVehicle.RoofState=RoofState;
}
foreach(var w in MainVehicle.Wheels)
{
w.Fix();
}
if (IsInvincible) { MainVehicle.IsInvincible=true; }
SetUpFixedData();
Model.MarkAsNoLongerNeeded();
return true;
}
#region -- PEDALING --
/*
* Thanks to @oldnapalm.
*/
private string PedalingAnimDict()
{
switch ((VehicleHash)Model)
{
case VehicleHash.Bmx:
return "veh@bicycle@bmx@front@base";
case VehicleHash.Cruiser:
return "veh@bicycle@cruiserfront@base";
case VehicleHash.Scorcher:
return "veh@bicycle@mountainfront@base";
default:
return "veh@bicycle@roadfront@base";
}
}
private string PedalingAnimName(bool fast)
{
return fast ? "fast_pedal_char" : "cruise_pedal_char";
}
private void StartPedalingAnim(bool fast)
{
MainVehicle.Driver?.Task.PlayAnimation(PedalingAnimDict(), PedalingAnimName(fast), 8.0f, -8.0f, -1, AnimationFlags.Loop | AnimationFlags.AllowRotation, 1.0f);
}
private void StopPedalingAnim(bool fast)
{
MainVehicle.Driver.Task.ClearAnimation(PedalingAnimDict(), PedalingAnimName(fast));
}
#endregion
}
}