1
Fork 0
mirror of https://github.com/thegeneralist01/Scene-Manager-DevRepo synced 2026-01-11 23:50:29 +01:00

Added CollectedPed object

This commit is contained in:
Rich Dunne 2021-05-01 13:12:24 -06:00
parent 93951b3e28
commit 25acb3f66f
7 changed files with 490 additions and 507 deletions

View file

@ -0,0 +1,438 @@
using Rage;
using System.Collections.Generic;
using System.Linq;
using SceneManager.Utils;
namespace SceneManager.Objects
{
internal class CollectedPed : Ped
{
internal Path Path { get; private set; }
internal Waypoint CurrentWaypoint { get; private set; }
internal bool StoppedAtWaypoint { get; private set; } = false;
internal bool Dismissed { get; private set; } = false;
internal bool Directed { get; set; } = false;
internal bool SkipWaypoint { get; private set; } = false;
internal bool ReadyForDirectTasks { get; private set; } = true;
internal CollectedPed(Ped ped, Path path, Waypoint waypoint)
{
Handle = ped.Handle;
Path = path;
CurrentWaypoint = waypoint;
SetPersistence();
Game.LogTrivial($"Added {CurrentVehicle.Model.Name} to collection from path {Path.Number} waypoint {waypoint.Number}.");
GameFiber.StartNew(() => AssignWaypointTasks(), "Task Assignment Fiber");
}
private void SetPersistence()
{
IsPersistent = true;
BlockPermanentEvents = true;
CurrentVehicle.IsPersistent = true;
}
private void AssignWaypointTasks()
{
// Driving styles https://gtaforums.com/topic/822314-guide-driving-styles/
// also https://vespura.com/fivem/drivingstyle/
if (!VehicleAndDriverAreValid())
{
return;
}
AssignDirectedTask(); // This logic is a mess.
if (CurrentWaypoint.IsStopWaypoint)
{
StopAtWaypoint();
}
if (Path?.Waypoints?.Count > 0 && CurrentWaypoint != Path?.Waypoints?.Last())
{
DriveToNextWaypoint();
}
if (!Dismissed && !VehicleAndDriverAreValid() || Directed)
{
return;
}
Game.LogTrivial($"{CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] all Path {Path.Number} tasks complete.");
if (!Dismissed)
{
base.Dismiss();
}
}
private void AssignDirectedTask()
{
if (CurrentWaypoint != null && Directed)
{
Dismissed = false;
while (!ReadyForDirectTasks)
{
GameFiber.Yield();
}
if (!VehicleAndDriverAreValid())
{
return;
}
Tasks.Clear();
DriveToDirectedWaypoint();
}
}
void DriveToDirectedWaypoint()
{
Dismissed = false;
while (!ReadyForDirectTasks)
{
GameFiber.Yield();
}
Tasks.Clear();
AssignTasksForDirectedDriver();
}
private void AssignTasksForDirectedDriver()
{
float acceptedDistance = GetAcceptedStoppingDistance(Path.Waypoints, Path.Waypoints.IndexOf(CurrentWaypoint));
Vector3 oldPosition = CurrentWaypoint.Position;
Game.LogTrivial($"{CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] is driving to path {CurrentWaypoint.Path.Number} waypoint {CurrentWaypoint.Number} (directed)");
Tasks.DriveToPosition(CurrentWaypoint.Position, CurrentWaypoint.Speed, (VehicleDrivingFlags)CurrentWaypoint.DrivingFlagType, acceptedDistance);
LoopWhileDrivingToDirectedWaypoint();
void LoopWhileDrivingToDirectedWaypoint()
{
while (VehicleAndDriverAreValid() && !Dismissed && !SkipWaypoint && CurrentVehicle.FrontPosition.DistanceTo2D(oldPosition) > acceptedDistance)
{
if (oldPosition != CurrentWaypoint.Position)
{
oldPosition = CurrentWaypoint.Position;
}
GameFiber.Yield();
}
if (CurrentVehicle)
{
Tasks.PerformDrivingManeuver(CurrentVehicle, VehicleManeuver.GoForwardWithCustomSteeringAngle, 3).WaitForCompletion();
Game.LogTrivial($"{CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] directed task is complete, directed is now false");
}
Directed = false;
}
}
private float GetAcceptedStoppingDistance(List<Waypoint> waypoints, int nextWaypoint)
{
float dist;
if (Settings.SpeedUnit == SpeedUnits.MPH)
{
dist = (MathHelper.ConvertMilesPerHourToKilometersPerHour(waypoints[nextWaypoint].Speed) * MathHelper.ConvertMilesPerHourToKilometersPerHour(waypoints[nextWaypoint].Speed)) / (250 * 0.8f);
}
else
{
dist = (waypoints[nextWaypoint].Speed * waypoints[nextWaypoint].Speed) / (250 * 0.8f);
}
var acceptedDistance = MathHelper.Clamp(dist, 2, 10);
return acceptedDistance;
}
private void DriveToNextWaypoint()
{
if (!VehicleAndDriverAreValid() || CurrentWaypoint == null || Path == null)
{
Game.LogTrivial($"Vehicle, driver, waypoint, or path is null.");
return;
}
Game.LogTrivial($"Preparing to run task loop for {CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] on path {Path.Number}");
for (int currentWaypointTask = CurrentWaypoint.Number; currentWaypointTask < Path.Waypoints.Count; currentWaypointTask++)
{
var oldPosition = Path.Waypoints[currentWaypointTask].Position;
SkipWaypoint = false;
if (this == null || !CurrentVehicle || Dismissed || Directed)
{
Game.LogTrivial($"Vehicle dismissed, directed, or null, return");
return;
}
if (this == null || !this || !LastVehicle.HasDriver || !IsAlive || LastVehicle.Driver == Game.LocalPlayer.Character)
{
Game.LogTrivial($"{CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] does not have a driver/driver is null or driver is dead.");
return;
}
if (Path.Waypoints.ElementAtOrDefault(currentWaypointTask) != null && !StoppedAtWaypoint)
{
CurrentWaypoint = Path.Waypoints[currentWaypointTask];
float acceptedDistance = GetAcceptedStoppingDistance(Path.Waypoints, currentWaypointTask);
Game.LogTrivial($"{CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] is driving to path {Path.Number} waypoint {Path.Waypoints[currentWaypointTask].Number} (Stop: {CurrentWaypoint.IsStopWaypoint}, Driving flag: {CurrentWaypoint.DrivingFlagType})");
Tasks.DriveToPosition(Path.Waypoints[currentWaypointTask].Position, Path.Waypoints[currentWaypointTask].Speed, (VehicleDrivingFlags)Path.Waypoints[currentWaypointTask].DrivingFlagType, acceptedDistance);
LoopWhileDrivingToWaypoint(currentWaypointTask, acceptedDistance, oldPosition);
if (!VehicleAndDriverAreValid())
{
return;
}
if (SkipWaypoint)
{
SkipWaypoint = false;
continue;
}
if (!Dismissed && !Directed && Path.Waypoints.ElementAtOrDefault(currentWaypointTask) != null && Path.Waypoints[currentWaypointTask].IsStopWaypoint)
{
StopAtWaypoint();
}
if (!VehicleAndDriverAreValid() || Dismissed || Directed)
{
return;
}
Tasks.PerformDrivingManeuver(CurrentVehicle, VehicleManeuver.GoForwardWithCustomSteeringAngle, 3).WaitForCompletion();
}
}
void LoopWhileDrivingToWaypoint(int currentWaypointTask, float acceptedDistance, Vector3 oldPosition)
{
while (VehicleAndDriverAreValid() && !Dismissed && !SkipWaypoint && !Directed && Path.Waypoints.ElementAtOrDefault(currentWaypointTask) != null && CurrentVehicle.FrontPosition.DistanceTo2D(Path.Waypoints[currentWaypointTask].Position) > acceptedDistance)
{
if (oldPosition != Path.Waypoints[currentWaypointTask].Position)
{
Game.LogTrivial($"Waypoint position has changed, updating drive task.");
oldPosition = Path.Waypoints[currentWaypointTask].Position;
Tasks.DriveToPosition(Path.Waypoints[currentWaypointTask].Position, Path.Waypoints[currentWaypointTask].Speed, (VehicleDrivingFlags)Path.Waypoints[currentWaypointTask].DrivingFlagType, acceptedDistance);
}
if (Tasks.CurrentTaskStatus == TaskStatus.NoTask)
{
//Game.DisplayNotification($"~o~Scene Manager ~r~[Error]\n{Vehicle.Model.Name} [{Vehicle.Handle}] driver [{Driver.Handle}] has no task. Reassiging current waypoint task.");
Game.LogTrivial($"{CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] driver [{Handle}] has no task. Reassiging current waypoint task.");
if (CurrentVehicle)
{
Tasks.DriveToPosition(Path.Waypoints[currentWaypointTask].Position, Path.Waypoints[currentWaypointTask].Speed, (VehicleDrivingFlags)Path.Waypoints[currentWaypointTask].DrivingFlagType, acceptedDistance);
}
else
{
Game.LogTrivial($"{CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] driver [{Handle}] is not in a vehicle. Exiting loop.");
return;
}
}
GameFiber.Sleep(100);
}
}
}
private void StopAtWaypoint()
{
var stoppingDistance = GetAcceptedStoppingDistance(CurrentWaypoint.Path.Waypoints, CurrentWaypoint.Path.Waypoints.IndexOf(CurrentWaypoint));
Game.LogTrivial($"{CurrentVehicle.Model.Name} stopping at path {CurrentWaypoint.Path.Number} waypoint.");
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(CurrentVehicle, stoppingDistance, -1, true);
StoppedAtWaypoint = true;
while (CurrentWaypoint != null && VehicleAndDriverAreValid() && StoppedAtWaypoint && !Directed)
{
GameFiber.Yield();
}
if (this && CurrentVehicle)
{
Game.LogTrivial($"{CurrentVehicle.Model.Name} releasing from stop waypoint.");
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(CurrentVehicle, 0f, 1, true);
Tasks.CruiseWithVehicle(5f);
}
}
private bool VehicleAndDriverAreValid()
{
if (this == null || !this)
{
Game.LogTrivial($"CollectedVehicle is null");
return false;
}
if (!CurrentVehicle)
{
Game.LogTrivial($"Vehicle is null");
Dismiss();
return false;
}
if (!IsAlive)
{
Game.LogTrivial($"Driver is null or dead or not in a vehicle");
Dismiss();
return false;
}
return true;
}
internal void Dismiss(Dismiss dismissOption = Utils.Dismiss.FromPath, Path newPath = null)
{
if(CurrentVehicle)
{
if (StoppedAtWaypoint)
{
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(LastVehicle, 0f, 1, true);
}
CurrentVehicle.Dismiss();
}
if (this)
{
base.Dismiss();
}
if (!CurrentVehicle)
{
Game.LogTrivial($"Vehicle is null.");
return;
}
if (!this)
{
Game.LogTrivial($"Driver is null.");
return;
}
if (dismissOption == Utils.Dismiss.FromWorld)
{
DismissFromWorld();
return;
}
if (dismissOption == Utils.Dismiss.FromPlayer)
{
DismissFromPlayer();
return;
}
if(CurrentVehicle && StoppedAtWaypoint)
{
StoppedAtWaypoint = false;
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(LastVehicle, 0f, 1, true);
Tasks.CruiseWithVehicle(5f);
}
Tasks.Clear();
if (dismissOption == Utils.Dismiss.FromWaypoint)
{
DismissFromWaypoint();
}
if (dismissOption == Utils.Dismiss.FromPath)
{
DismissFromPath();
}
if(dismissOption == Utils.Dismiss.FromDirected)
{
DismissFromDirect();
}
void DismissFromPlayer()
{
Dismissed = true;
base.Dismiss();
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(CurrentVehicle, 0f, 1, true);
CurrentVehicle.Dismiss();
Path.CollectedPeds.Remove(this);
}
void DismissFromWorld()
{
Game.LogTrivial($"Dismissed {CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] from the world");
while (CurrentVehicle.HasOccupants)
{
foreach (Ped occupant in CurrentVehicle.Occupants)
{
occupant.Dismiss();
occupant.Delete();
}
GameFiber.Yield();
}
CurrentVehicle.Delete();
}
void DismissFromWaypoint()
{
if (CurrentWaypoint == null || Path == null)
{
Game.LogTrivial($"CurrentWaypoint or Path is null");
return;
}
if (CurrentWaypoint?.Number != Path?.Waypoints.Count)
{
Game.LogTrivial($"{CurrentVehicle?.Model.Name} [{CurrentVehicle?.Handle}] dismissed from waypoint.");
SkipWaypoint = true;
}
else if (CurrentWaypoint?.Number == Path?.Waypoints.Count)
{
DismissFromPath();
}
}
void DismissFromPath()
{
Game.LogTrivial($"Dismissing {CurrentVehicle?.Model.Name} [{CurrentVehicle?.Handle}] from path");
Dismissed = true;
// Check if the vehicle is near any of the path's collector waypoints
GameFiber.StartNew(() =>
{
var nearestCollectorWaypoint = Path.Waypoints.Where(wp => wp.IsCollector).OrderBy(wp => CurrentVehicle.DistanceTo2D(wp.Position)).FirstOrDefault();
if(nearestCollectorWaypoint == null)
{
Game.LogTrivial($"Nearest collector is null");
}
else
{
while (nearestCollectorWaypoint != null && CurrentVehicle && CurrentVehicle.HasDriver && this && IsAlive && CurrentVehicle.FrontPosition.DistanceTo2D(nearestCollectorWaypoint.Position) <= nearestCollectorWaypoint.CollectorRadius)
{
GameFiber.Yield();
}
}
if (!CurrentVehicle || !this)
{
Game.LogTrivial($"Vehicle or driver is null");
return;
}
if (!Directed)
{
Path.CollectedPeds.Remove(this);
Game.LogTrivial($"{CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] dismissed successfully.");
if (this)
{
if (GetAttachedBlip())
{
GetAttachedBlip().Delete();
}
BlockPermanentEvents = false;
base.Dismiss();
}
if (CurrentVehicle)
{
CurrentVehicle.Dismiss();
CurrentVehicle.IsSirenOn = false;
CurrentVehicle.IsSirenSilent = true;
}
}
}, "DismissFromPath Fiber");
}
void DismissFromDirect()
{
Dismissed = true;
Directed = true;
if (newPath != null)
{
newPath.CollectedPeds.Add(this);
Path.CollectedPeds.Remove(this);
}
Tasks.Clear();
}
}
}
}

View file

@ -1,449 +0,0 @@
using Rage;
using System.Collections.Generic;
using System.Linq;
using SceneManager.Utils;
namespace SceneManager.Objects
{
internal class CollectedVehicle
{
internal Ped Driver { get; private set; }
internal Vehicle Vehicle { get; private set; }
internal Path Path { get; private set; }
internal Waypoint CurrentWaypoint { get; private set; }
internal bool StoppedAtWaypoint { get; private set; } = false;
internal bool Dismissed { get; private set; } = false;
internal bool Directed { get; set; } = false;
internal bool SkipWaypoint { get; private set; } = false;
internal bool ReadyForDirectTasks { get; private set; } = true;
internal CollectedVehicle(Vehicle vehicle, Path path)
{
Vehicle = vehicle;
Driver = vehicle.Driver;
Path = path;
SetPersistence();
}
private void SetPersistence()
{
Vehicle.IsPersistent = true;
Driver.IsPersistent = true;
Driver.BlockPermanentEvents = true;
}
internal void AssignWaypointTasks(Path path, Waypoint currentWaypoint)
{
// Driving styles https://gtaforums.com/topic/822314-guide-driving-styles/
// also https://vespura.com/fivem/drivingstyle/
if (!VehicleAndDriverAreValid())
{
return;
}
AssignPathAndCurrentWaypoint();
AssignDirectedTask();
if (currentWaypoint.IsStopWaypoint)
{
StopAtWaypoint();
}
if (path?.Waypoints?.Count > 0 && currentWaypoint != path?.Waypoints?.Last())
{
DriveToNextWaypoint();
}
if (!Dismissed && !VehicleAndDriverAreValid() || Directed)
{
return;
}
Game.LogTrivial($"{Vehicle.Model.Name} [{Vehicle.Handle}] all Path {path.Number} tasks complete.");
if (!Dismissed)
{
Dismiss();
}
void AssignPathAndCurrentWaypoint()
{
Path = path;
if (currentWaypoint != null)
{
CurrentWaypoint = currentWaypoint;
}
else
{
CurrentWaypoint = path.Waypoints[0];
}
}
void AssignDirectedTask()
{
if (currentWaypoint != null && Directed)
{
Dismissed = false;
while (!ReadyForDirectTasks)
{
GameFiber.Yield();
}
if (!VehicleAndDriverAreValid())
{
return;
}
Driver.Tasks.Clear();
DriveToDirectedWaypoint();
}
}
void DriveToDirectedWaypoint()
{
Dismissed = false;
while (!ReadyForDirectTasks)
{
GameFiber.Yield();
}
Driver.Tasks.Clear();
AssignTasksForDirectedDriver();
void AssignTasksForDirectedDriver()
{
float acceptedDistance = GetAcceptedStoppingDistance(Path.Waypoints, Path.Waypoints.IndexOf(currentWaypoint));
Vector3 oldPosition = currentWaypoint.Position;
Game.LogTrivial($"{Vehicle.Model.Name} [{Vehicle.Handle}] is driving to path {currentWaypoint.Path.Number} waypoint {currentWaypoint.Number} (directed)");
Driver.Tasks.DriveToPosition(currentWaypoint.Position, currentWaypoint.Speed, (VehicleDrivingFlags)currentWaypoint.DrivingFlagType, acceptedDistance);
LoopWhileDrivingToDirectedWaypoint();
void LoopWhileDrivingToDirectedWaypoint()
{
while (VehicleAndDriverAreValid() && !Dismissed && !SkipWaypoint && Vehicle.FrontPosition.DistanceTo2D(oldPosition) > acceptedDistance)
{
if (oldPosition != currentWaypoint.Position)
{
oldPosition = currentWaypoint.Position;
}
GameFiber.Yield();
}
if (Vehicle)
{
Driver.Tasks.PerformDrivingManeuver(Vehicle, VehicleManeuver.GoForwardWithCustomSteeringAngle, 3).WaitForCompletion();
Game.LogTrivial($"{Vehicle.Model.Name} [{Vehicle.Handle}] directed task is complete, directed is now false");
}
Directed = false;
}
}
}
void DriveToNextWaypoint()
{
if (!VehicleAndDriverAreValid() || CurrentWaypoint == null || Path == null)
{
Game.LogTrivial($"Vehicle, driver, waypoint, or path is null.");
return;
}
Game.LogTrivial($"Preparing to run task loop for {Vehicle.Model.Name} [{Vehicle.Handle}] on path {Path.Number}");
for (int currentWaypointTask = CurrentWaypoint.Number; currentWaypointTask < Path.Waypoints.Count; currentWaypointTask++)
{
var oldPosition = Path.Waypoints[currentWaypointTask].Position;
SkipWaypoint = false;
if (this == null || !Vehicle || Dismissed || Directed)
{
Game.LogTrivial($"Vehicle dismissed, directed, or null, return");
return;
}
if (Driver == null || !Driver || !Vehicle.HasDriver || !Driver.IsAlive || Vehicle.Driver == Game.LocalPlayer.Character)
{
Game.LogTrivial($"{Vehicle.Model.Name} [{Vehicle.Handle}] does not have a driver/driver is null or driver is dead.");
return;
}
if (Path.Waypoints.ElementAtOrDefault(currentWaypointTask) != null && !StoppedAtWaypoint)
{
CurrentWaypoint = Path.Waypoints[currentWaypointTask];
float acceptedDistance = GetAcceptedStoppingDistance(Path.Waypoints, currentWaypointTask);
Game.LogTrivial($"{Vehicle.Model.Name} [{Vehicle.Handle}] is driving to path {Path.Number} waypoint {Path.Waypoints[currentWaypointTask].Number} (Stop: {CurrentWaypoint.IsStopWaypoint}, Driving flag: {CurrentWaypoint.DrivingFlagType})");
Driver.Tasks.DriveToPosition(Path.Waypoints[currentWaypointTask].Position, Path.Waypoints[currentWaypointTask].Speed, (VehicleDrivingFlags)Path.Waypoints[currentWaypointTask].DrivingFlagType, acceptedDistance);
LoopWhileDrivingToWaypoint(currentWaypointTask, acceptedDistance, oldPosition);
if (!VehicleAndDriverAreValid())
{
return;
}
if (SkipWaypoint)
{
SkipWaypoint = false;
continue;
}
if (!Dismissed && !Directed && Path.Waypoints.ElementAtOrDefault(currentWaypointTask) != null && Path.Waypoints[currentWaypointTask].IsStopWaypoint)
{
StopAtWaypoint();
}
if (!VehicleAndDriverAreValid() || Dismissed || Directed)
{
return;
}
Driver.Tasks.PerformDrivingManeuver(Vehicle, VehicleManeuver.GoForwardWithCustomSteeringAngle, 3).WaitForCompletion();
}
}
void LoopWhileDrivingToWaypoint(int currentWaypointTask, float acceptedDistance, Vector3 oldPosition)
{
while (VehicleAndDriverAreValid() && !Dismissed && !SkipWaypoint && !Directed && Path.Waypoints.ElementAtOrDefault(currentWaypointTask) != null && Vehicle.FrontPosition.DistanceTo2D(Path.Waypoints[currentWaypointTask].Position) > acceptedDistance)
{
if (oldPosition != Path.Waypoints[currentWaypointTask].Position)
{
Game.LogTrivial($"Waypoint position has changed, updating drive task.");
oldPosition = Path.Waypoints[currentWaypointTask].Position;
Driver.Tasks.DriveToPosition(Path.Waypoints[currentWaypointTask].Position, Path.Waypoints[currentWaypointTask].Speed, (VehicleDrivingFlags)Path.Waypoints[currentWaypointTask].DrivingFlagType, acceptedDistance);
}
if(Driver.Tasks.CurrentTaskStatus == TaskStatus.NoTask)
{
//Game.DisplayNotification($"~o~Scene Manager ~r~[Error]\n{Vehicle.Model.Name} [{Vehicle.Handle}] driver [{Driver.Handle}] has no task. Reassiging current waypoint task.");
Game.LogTrivial($"{Vehicle.Model.Name} [{Vehicle.Handle}] driver [{Driver.Handle}] has no task. Reassiging current waypoint task.");
if (Driver.CurrentVehicle)
{
Driver.Tasks.DriveToPosition(Path.Waypoints[currentWaypointTask].Position, Path.Waypoints[currentWaypointTask].Speed, (VehicleDrivingFlags)Path.Waypoints[currentWaypointTask].DrivingFlagType, acceptedDistance);
}
else
{
Game.LogTrivial($"{Vehicle.Model.Name} [{Vehicle.Handle}] driver [{Driver.Handle}] is not in a vehicle. Exiting loop.");
return;
}
}
GameFiber.Sleep(100);
}
}
}
float GetAcceptedStoppingDistance(List<Waypoint> waypoints, int nextWaypoint)
{
float dist;
if (Settings.SpeedUnit == SpeedUnits.MPH)
{
dist = (MathHelper.ConvertMilesPerHourToKilometersPerHour(waypoints[nextWaypoint].Speed) * MathHelper.ConvertMilesPerHourToKilometersPerHour(waypoints[nextWaypoint].Speed)) / (250 * 0.8f);
}
else
{
dist = (waypoints[nextWaypoint].Speed * waypoints[nextWaypoint].Speed) / (250 * 0.8f);
}
var acceptedDistance = MathHelper.Clamp(dist, 2, 10);
return acceptedDistance;
}
void StopAtWaypoint()
{
var stoppingDistance = GetAcceptedStoppingDistance(currentWaypoint.Path.Waypoints, currentWaypoint.Path.Waypoints.IndexOf(currentWaypoint));
Game.LogTrivial($"{Vehicle.Model.Name} stopping at path {currentWaypoint.Path.Number} waypoint.");
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(Vehicle, stoppingDistance, -1, true);
StoppedAtWaypoint = true;
while (currentWaypoint != null && VehicleAndDriverAreValid() && StoppedAtWaypoint && !Directed)
{
GameFiber.Yield();
}
if (Driver && Driver.CurrentVehicle)
{
Game.LogTrivial($"{Vehicle.Model.Name} releasing from stop waypoint.");
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(Vehicle, 0f, 1, true);
Driver.Tasks.CruiseWithVehicle(5f);
}
}
bool VehicleAndDriverAreValid()
{
if (this == null)
{
Game.LogTrivial($"CollectedVehicle is null");
return false;
}
if (!Vehicle)// && !Dismissed)
{
Game.LogTrivial($"Vehicle is null");
Dismiss();
return false;
}
if (!Driver || !Driver.CurrentVehicle || !Driver.IsAlive)
{
Game.LogTrivial($"Driver is null or dead or not in a vehicle");
Dismiss();
return false;
}
return true;
}
}
internal void Dismiss(Dismiss dismissOption = Utils.Dismiss.FromPath, Path newPath = null)
{
if(Vehicle)
{
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(Driver.LastVehicle, 0f, 1, true);
Vehicle.Dismiss();
}
if (Driver)
{
Driver.Dismiss();
}
if (!Vehicle)
{
Game.LogTrivial($"Vehicle is null.");
return;
}
if (!Driver)
{
Game.LogTrivial($"Driver is null.");
return;
}
if (dismissOption == Utils.Dismiss.FromWorld)
{
DismissFromWorld();
return;
}
if (dismissOption == Utils.Dismiss.FromPlayer)
{
DismissFromPlayer();
return;
}
if(Driver.CurrentVehicle && StoppedAtWaypoint)
{
StoppedAtWaypoint = false;
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(Driver.LastVehicle, 0f, 1, true);
Driver.Tasks.CruiseWithVehicle(5f);
}
Driver.Tasks.Clear();
if (dismissOption == Utils.Dismiss.FromWaypoint)
{
DismissFromWaypoint();
}
if (dismissOption == Utils.Dismiss.FromPath)
{
DismissFromPath();
}
if(dismissOption == Utils.Dismiss.FromDirected)
{
DismissFromDirect();
}
void DismissFromPlayer()
{
Dismissed = true;
Driver.Dismiss();
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(Vehicle, 0f, 1, true);
Vehicle.Dismiss();
Path.CollectedVehicles.Remove(this);
}
void DismissFromWorld()
{
Game.LogTrivial($"Dismissed {Vehicle.Model.Name} [{Vehicle.Handle}] from the world");
while (Vehicle.HasOccupants)
{
foreach (Ped occupant in Vehicle.Occupants)
{
occupant.Dismiss();
occupant.Delete();
}
GameFiber.Yield();
}
Vehicle.Delete();
}
void DismissFromWaypoint()
{
if (CurrentWaypoint == null || Path == null)
{
Game.LogTrivial($"CurrentWaypoint or Path is null");
return;
}
if (CurrentWaypoint?.Number != Path?.Waypoints.Count)
{
Game.LogTrivial($"{Vehicle?.Model.Name} [{Vehicle?.Handle}] dismissed from waypoint.");
SkipWaypoint = true;
}
else if (CurrentWaypoint?.Number == Path?.Waypoints.Count)
{
DismissFromPath();
}
}
void DismissFromPath()
{
Game.LogTrivial($"Dismissing {Vehicle?.Model.Name} [{Vehicle?.Handle}] from path");
Dismissed = true;
// Check if the vehicle is near any of the path's collector waypoints
GameFiber.StartNew(() =>
{
var nearestCollectorWaypoint = Path.Waypoints.Where(wp => wp.IsCollector).OrderBy(wp => Vehicle.DistanceTo2D(wp.Position)).FirstOrDefault();
if(nearestCollectorWaypoint == null)
{
Game.LogTrivial($"Nearest collector is null");
}
else
{
while (nearestCollectorWaypoint != null && Vehicle && Vehicle.HasDriver && Driver && Driver.IsAlive && Vehicle.FrontPosition.DistanceTo2D(nearestCollectorWaypoint.Position) <= nearestCollectorWaypoint.CollectorRadius)
{
GameFiber.Yield();
}
}
if (!Vehicle || !Driver)
{
Game.LogTrivial($"Vehicle or driver is null");
return;
}
if (!Directed)
{
Path.CollectedVehicles.Remove(this);
Game.LogTrivial($"{Vehicle.Model.Name} [{Vehicle.Handle}] dismissed successfully.");
if (Driver)
{
if (Driver.GetAttachedBlip())
{
Driver.GetAttachedBlip().Delete();
}
Driver.BlockPermanentEvents = false;
Driver.Dismiss();
}
if (Vehicle)
{
Vehicle.Dismiss();
Vehicle.IsSirenOn = false;
Vehicle.IsSirenSilent = true;
}
}
}, "DismissFromPath Fiber");
}
void DismissFromDirect()
{
Dismissed = true;
Directed = true;
if (newPath != null)
{
newPath.CollectedVehicles.Add(this);
Path.CollectedVehicles.Remove(this);
}
Driver.Tasks.Clear();
}
}
}
}

View file

@ -21,7 +21,7 @@ namespace SceneManager.Objects
[XmlArray("Waypoints")] [XmlArray("Waypoints")]
[XmlArrayItem("Waypoint")] [XmlArrayItem("Waypoint")]
public List<Waypoint> Waypoints { get; set; } = new List<Waypoint>(); public List<Waypoint> Waypoints { get; set; } = new List<Waypoint>();
internal List<CollectedVehicle> CollectedVehicles { get; } = new List<CollectedVehicle>(); internal List<CollectedPed> CollectedPeds { get; } = new List<CollectedPed>();
private List<Vehicle> BlacklistedVehicles { get; } = new List<Vehicle>(); private List<Vehicle> BlacklistedVehicles { get; } = new List<Vehicle>();
private Path() { } private Path() { }
@ -138,24 +138,23 @@ namespace SceneManager.Objects
} }
GameFiber.Yield(); GameFiber.Yield();
} }
}); }, "3D Waypoint Line Drawing Fiber");
} }
internal void LoopForVehiclesToBeDismissed() internal void LoopForVehiclesToBeDismissed()
{ {
while (PathManager.Paths.Contains(this)) while (PathManager.Paths.Contains(this))
{ {
//Logger.Log($"Dismissing unused vehicles for cleanup"); foreach (CollectedPed cp in CollectedPeds.Where(x => x && x.CurrentVehicle && (!x.CurrentVehicle.IsDriveable || x.CurrentVehicle.IsUpsideDown || !x.CurrentVehicle.HasDriver)))
foreach (CollectedVehicle cv in CollectedVehicles.Where(cv => cv.Vehicle && (!cv.Vehicle.IsDriveable || cv.Vehicle.IsUpsideDown || !cv.Vehicle.HasDriver)))
{ {
if (cv.Vehicle.HasDriver) if (cp.CurrentVehicle.HasDriver)
{ {
cv.Vehicle.Driver.Dismiss(); cp.CurrentVehicle.Driver.Dismiss();
} }
cv.Vehicle.Dismiss(); cp.CurrentVehicle.Dismiss();
} }
CollectedVehicles.RemoveAll(cv => !cv.Vehicle); CollectedPeds.RemoveAll(cp => !cp || !cp.CurrentVehicle);
BlacklistedVehicles.RemoveAll(v => !v); BlacklistedVehicles.RemoveAll(v => !v);
GameFiber.Sleep(60000); GameFiber.Sleep(60000);
} }
@ -174,13 +173,11 @@ namespace SceneManager.Objects
{ {
foreach (Waypoint waypoint in Waypoints.Where(x => x != null && x.IsCollector)) foreach (Waypoint waypoint in Waypoints.Where(x => x != null && x.IsCollector))
{ {
foreach (Vehicle v in World.GetAllVehicles()) foreach (Vehicle vehicle in World.GetAllVehicles())
{ {
if (VehicleIsValidForCollection(v) && VehicleIsNearWaypoint(v, waypoint)) if (VehicleIsValidForCollection(vehicle) && VehicleIsNearWaypoint(vehicle, waypoint))
{ {
CollectedVehicle newCollectedVehicle = AddVehicleToCollection(v); CollectedPeds.Add(new CollectedPed(vehicle.Driver, this, waypoint));
GameFiber AssignTasksFiber = new GameFiber(() => newCollectedVehicle.AssignWaypointTasks(this, waypoint));
AssignTasksFiber.Start();
} }
checksDone++; // Increment the counter inside the vehicle loop checksDone++; // Increment the counter inside the vehicle loop
@ -200,14 +197,6 @@ namespace SceneManager.Objects
lastProcessTime = Game.GameTime; lastProcessTime = Game.GameTime;
} }
CollectedVehicle AddVehicleToCollection(Vehicle vehicle)
{
var collectedVehicle = new CollectedVehicle(vehicle, this);
CollectedVehicles.Add(collectedVehicle);
Game.LogTrivial($"Added {vehicle.Model.Name} to collection from path {Number} waypoint {1}.");
return collectedVehicle;
}
bool VehicleIsNearWaypoint(Vehicle v, Waypoint wp) bool VehicleIsNearWaypoint(Vehicle v, Waypoint wp)
{ {
return v.FrontPosition.DistanceTo2D(wp.Position) <= wp.CollectorRadius && Math.Abs(wp.Position.Z - v.Position.Z) < 3; return v.FrontPosition.DistanceTo2D(wp.Position) <= wp.CollectorRadius && Math.Abs(wp.Position.Z - v.Position.Z) < 3;
@ -215,9 +204,13 @@ namespace SceneManager.Objects
bool VehicleIsValidForCollection(Vehicle v) bool VehicleIsValidForCollection(Vehicle v)
{ {
if (v && v != Game.LocalPlayer.Character.LastVehicle && (v.IsCar || v.IsBike || v.IsBicycle || v.IsQuadBike) && !v.IsSirenOn && v.IsEngineOn && v.IsOnAllWheels && v.Speed > 1 && !CollectedVehicles.Any(cv => cv?.Vehicle == v) && !BlacklistedVehicles.Contains(v)) if(!v)
{ {
var vehicleCollectedOnAnotherPath = PathManager.Paths.Any(p => p.Number != Number && p.CollectedVehicles.Any(cv => cv.Vehicle == v)); return false;
}
if (v != Game.LocalPlayer.Character.LastVehicle && (v.IsCar || v.IsBike || v.IsBicycle || v.IsQuadBike) && !v.IsSirenOn && v.IsEngineOn && v.IsOnAllWheels && v.Speed > 1 && !CollectedPeds.Any(cp => cp && cp.CurrentVehicle == v) && !BlacklistedVehicles.Contains(v))
{
var vehicleCollectedOnAnotherPath = PathManager.Paths.Any(p => p.Number != Number && p.CollectedPeds.Any(cp => cp && cp.CurrentVehicle == v));
if (vehicleCollectedOnAnotherPath) if (vehicleCollectedOnAnotherPath)
{ {
return false; return false;
@ -232,6 +225,7 @@ namespace SceneManager.Objects
} }
if (v.IsPoliceVehicle && !v.Driver.IsAmbient()) if (v.IsPoliceVehicle && !v.Driver.IsAmbient())
{ {
Game.LogTrivial($"Vehicle's driver not ambient.");
BlacklistedVehicles.Add(v); BlacklistedVehicles.Add(v);
return false; return false;
} }
@ -271,23 +265,23 @@ namespace SceneManager.Objects
private void DismissCollectedDrivers() private void DismissCollectedDrivers()
{ {
List<CollectedVehicle> pathVehicles = CollectedVehicles.ToList(); // Have to enumerate over a copied list because you can't delete from the same list you're enumerating through List<CollectedPed> collectedPedsCopy = CollectedPeds.ToList(); // Have to enumerate over a copied list because you can't delete from the same list you're enumerating through
foreach (CollectedVehicle collectedVehicle in pathVehicles.Where(x => x != null && x.Vehicle && x.Driver)) foreach (CollectedPed collectedPed in collectedPedsCopy.Where(x => x != null && x && x.CurrentVehicle))
{ {
if (collectedVehicle.StoppedAtWaypoint) if (collectedPed.StoppedAtWaypoint)
{ {
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(collectedVehicle.Vehicle, 1f, 1, true); Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(collectedPed.CurrentVehicle, 1f, 1, true);
} }
if (collectedVehicle.Driver.GetAttachedBlip()) if (collectedPed.GetAttachedBlip())
{ {
collectedVehicle.Driver.GetAttachedBlip().Delete(); collectedPed.GetAttachedBlip().Delete();
} }
collectedVehicle.Driver.Dismiss(); collectedPed.Dismiss();
collectedVehicle.Vehicle.IsSirenOn = false; collectedPed.CurrentVehicle.IsSirenOn = false;
collectedVehicle.Vehicle.IsSirenSilent = true; collectedPed.CurrentVehicle.IsSirenSilent = true;
collectedVehicle.Vehicle.Dismiss(); collectedPed.CurrentVehicle.Dismiss();
CollectedVehicles.Remove(collectedVehicle); CollectedPeds.Remove(collectedPed);
} }
} }

View file

@ -75,10 +75,10 @@ namespace SceneManager.Objects
if (IsStopWaypoint && !stopWaypoint) if (IsStopWaypoint && !stopWaypoint)
{ {
Blip.Color = Color.Green; Blip.Color = Color.Green;
foreach(CollectedVehicle cv in Path.CollectedVehicles.Where(cv => cv.Vehicle && cv.Path == Path && cv.CurrentWaypoint == this && cv.StoppedAtWaypoint)) foreach(CollectedPed cp in Path.CollectedPeds.Where(cp => cp.CurrentVehicle && cp.Path == Path && cp.CurrentWaypoint == this && cp.StoppedAtWaypoint))
{ {
// Logger.Log($"Setting StoppedAtWaypoint to false for {cv.Vehicle.Model.Name}"); // Logger.Log($"Setting StoppedAtWaypoint to false for {cv.Vehicle.Model.Name}");
cv.Dismiss(Dismiss.FromWaypoint); cp.Dismiss(Dismiss.FromWaypoint);
} }
} }
else if(stopWaypoint && !IsStopWaypoint) else if(stopWaypoint && !IsStopWaypoint)
@ -148,11 +148,11 @@ namespace SceneManager.Objects
{ {
if (Blip) if (Blip)
{ {
Blip.Position = Game.LocalPlayer.Character.Position; Blip.Position = newWaypointPosition;
} }
if (CollectorRadiusBlip) if (CollectorRadiusBlip)
{ {
CollectorRadiusBlip.Position = Game.LocalPlayer.Character.Position; CollectorRadiusBlip.Position = newWaypointPosition;
} }
} }
} }

View file

@ -10,18 +10,18 @@ namespace SceneManager.Utils
{ {
internal static class ConsoleCommands internal static class ConsoleCommands
{ {
[ConsoleCommand] [ConsoleCommand("ShowCollectedVehicleInfo")]
internal static void Command_ShowCollectedVehicleInfo([ConsoleCommandParameter(AutoCompleterType = typeof(ConsoleCommandAutoCompleterVehicle), Name = "ShowCollectedVehicleInfo")] Vehicle vehicle) internal static void Command_ShowCollectedVehicleInfo([ConsoleCommandParameter(AutoCompleterType = typeof(ConsoleCommandAutoCompleterVehicle), Name = "ShowCollectedVehicleInfo")] Vehicle vehicle)
{ {
foreach(Path path in PathManager.Paths) foreach(Path path in PathManager.Paths)
{ {
var collectedVehicle = path.CollectedVehicles.Where(v => v.Vehicle == vehicle).FirstOrDefault(); var collectedVehicle = path.CollectedPeds.Where(v => v.CurrentVehicle == vehicle).FirstOrDefault();
if(collectedVehicle != null) if(collectedVehicle != null)
{ {
Game.LogTrivial($"Vehicle: {collectedVehicle.Vehicle.Model.Name} [{collectedVehicle.Vehicle.Handle}]"); Game.LogTrivial($"Vehicle: {collectedVehicle.CurrentVehicle.Model.Name} [{collectedVehicle.CurrentVehicle.Handle}]");
Rage.Native.NativeFunction.Natives.xA6E9C38DB51D7748(collectedVehicle.Vehicle, out uint script); Rage.Native.NativeFunction.Natives.xA6E9C38DB51D7748(collectedVehicle.CurrentVehicle, out uint script);
Game.LogTrivial($"Vehicle spawned by: {script}"); Game.LogTrivial($"Vehicle spawned by: {script}");
Game.LogTrivial($"Driver handle: {collectedVehicle.Driver.Handle}"); Game.LogTrivial($"Driver handle: {collectedVehicle.Handle}");
Game.LogTrivial($"Path: {collectedVehicle.Path.Number}"); Game.LogTrivial($"Path: {collectedVehicle.Path.Number}");
Game.LogTrivial($"Current waypoint: {collectedVehicle.CurrentWaypoint.Number}"); Game.LogTrivial($"Current waypoint: {collectedVehicle.CurrentWaypoint.Number}");
Game.LogTrivial($"StoppedAtWaypoint: {collectedVehicle.StoppedAtWaypoint}"); Game.LogTrivial($"StoppedAtWaypoint: {collectedVehicle.StoppedAtWaypoint}");
@ -29,18 +29,18 @@ namespace SceneManager.Utils
Game.LogTrivial($"ReadyForDirectTasks: {collectedVehicle.ReadyForDirectTasks}"); Game.LogTrivial($"ReadyForDirectTasks: {collectedVehicle.ReadyForDirectTasks}");
Game.LogTrivial($"Directed: {collectedVehicle.Directed}"); Game.LogTrivial($"Directed: {collectedVehicle.Directed}");
Game.LogTrivial($"Dismissed: {collectedVehicle.Dismissed}"); Game.LogTrivial($"Dismissed: {collectedVehicle.Dismissed}");
Game.LogTrivial($"Task status: {collectedVehicle.Driver.Tasks.CurrentTaskStatus}"); Game.LogTrivial($"Task status: {collectedVehicle.Tasks.CurrentTaskStatus}");
return; return;
} }
} }
Game.LogTrivial($"{vehicle.Model.Name} [{vehicle.Handle}] was not found collected by any path."); Game.LogTrivial($"{vehicle.Model.Name} [{vehicle.Handle}] was not found collected by any path.");
} }
[ConsoleCommand] [ConsoleCommand("GetPedsActiveTasks")]
internal static void Command_GetPedsActiveTasks([ConsoleCommandParameter(AutoCompleterType = typeof(ConsoleCommandAutoCompleterPedAliveOnly), Name = "GetPedsActiveTasks")] Ped ped) internal static void Command_GetPedsActiveTasks([ConsoleCommandParameter(AutoCompleterType = typeof(ConsoleCommandAutoCompleterPedAliveOnly), Name = "GetPedsActiveTasks")] Ped ped)
{ {
var tasks = new List<PedTask>(); var tasks = (PedTask[])Enum.GetValues(typeof(PedTask));
foreach (PedTask task in (PedTask[])Enum.GetValues(typeof(PedTask))) foreach (PedTask task in tasks)
{ {
if(Rage.Native.NativeFunction.Natives.GET_IS_TASK_ACTIVE<bool>(ped, (int)task)) if(Rage.Native.NativeFunction.Natives.GET_IS_TASK_ACTIVE<bool>(ped, (int)task))
{ {

View file

@ -49,14 +49,14 @@ namespace SceneManager.Utils
internal static void Direct(Vehicle nearbyVehicle, Path path, Waypoint targetWaypoint) internal static void Direct(Vehicle nearbyVehicle, Path path, Waypoint targetWaypoint)
{ {
var nearbyVehiclesPath = PathManager.Paths.FirstOrDefault(p => p.CollectedVehicles.Any(v => v.Vehicle == nearbyVehicle)); var nearbyVehiclesPath = PathManager.Paths.FirstOrDefault(p => p.CollectedPeds.Any(v => v.CurrentVehicle == nearbyVehicle));
if(nearbyVehiclesPath == null) if(nearbyVehiclesPath == null)
{ {
Game.LogTrivial($"Nearby vehicle does not belong to any path."); Game.LogTrivial($"Nearby vehicle does not belong to any path.");
} }
var collectedVehicleOnThisPath = path.CollectedVehicles.FirstOrDefault(v => v.Vehicle == nearbyVehicle); var collectedVehicleOnThisPath = path.CollectedPeds.FirstOrDefault(v => v.CurrentVehicle == nearbyVehicle);
var nearbyCollectedVehicleOtherPath = nearbyVehiclesPath?.CollectedVehicles.FirstOrDefault(v => v.Vehicle == nearbyVehicle); var nearbyCollectedVehicleOtherPath = nearbyVehiclesPath?.CollectedPeds.FirstOrDefault(p => p.CurrentVehicle == nearbyVehicle);
if (collectedVehicleOnThisPath == null) if (collectedVehicleOnThisPath == null)
{ {
Game.LogTrivial($"Nearby vehicle does not belong to this path."); Game.LogTrivial($"Nearby vehicle does not belong to this path.");
@ -66,12 +66,12 @@ namespace SceneManager.Utils
nearbyCollectedVehicleOtherPath.Dismiss(Dismiss.FromDirected, path); nearbyCollectedVehicleOtherPath.Dismiss(Dismiss.FromDirected, path);
} }
Game.LogTrivial($"[Direct Driver] Adding {nearbyVehicle.Model.Name} to directed path."); Game.LogTrivial($"[Direct Driver] Adding {nearbyVehicle.Model.Name} to directed path.");
path.CollectedVehicles.Add(collectedVehicleOnThisPath = new CollectedVehicle(nearbyVehicle, path)); path.CollectedPeds.Add(collectedVehicleOnThisPath = new CollectedPed(nearbyVehicle.Driver, path, targetWaypoint) { Directed = true });
collectedVehicleOnThisPath.Directed = true; //collectedVehicleOnThisPath.Directed = true;
collectedVehicleOnThisPath.Driver.Tasks.Clear(); collectedVehicleOnThisPath.Tasks.Clear();
} }
GameFiber.StartNew(() => collectedVehicleOnThisPath.AssignWaypointTasks(path, targetWaypoint)); //GameFiber.StartNew(() => collectedVehicleOnThisPath.AssignWaypointTasks(path, targetWaypoint));
} }
} }
} }

View file

@ -8,7 +8,7 @@ namespace SceneManager.Utils
{ {
internal static void Dismiss(int dismissIndex) internal static void Dismiss(int dismissIndex)
{ {
var nearbyVehicle = Game.LocalPlayer.Character.GetNearbyVehicles(16).FirstOrDefault(v => v != Game.LocalPlayer.Character.CurrentVehicle && v.VehicleAndDriverValid()); var nearbyVehicle = Game.LocalPlayer.Character.GetNearbyVehicles(16).FirstOrDefault(v => v.VehicleAndDriverValid() && v != Game.LocalPlayer.Character.CurrentVehicle);
if (!nearbyVehicle) if (!nearbyVehicle)
{ {
Game.LogTrivial($"Nearby vehicle is null."); Game.LogTrivial($"Nearby vehicle is null.");
@ -32,10 +32,10 @@ namespace SceneManager.Utils
} }
else else
{ {
CollectedVehicle collectedVehicle = PathManager.Paths.SelectMany(x => x.CollectedVehicles).FirstOrDefault(x => x.Vehicle == nearbyVehicle); CollectedPed collectedPed = PathManager.Paths.SelectMany(x => x.CollectedPeds).FirstOrDefault(x => x.CurrentVehicle == nearbyVehicle);
if(collectedVehicle != null) if(collectedPed != null)
{ {
collectedVehicle.Dismiss((Dismiss)dismissIndex); collectedPed.Dismiss((Dismiss)dismissIndex);
} }
} }
} }