mirror of
https://github.com/thegeneralist01/Scene-Manager-DevRepo
synced 2026-03-07 12:29:55 +01:00
Merge from testing
This commit is contained in:
commit
85be2cab53
43 changed files with 3623 additions and 2811 deletions
209
SceneManager/Barriers/Barrier.cs
Normal file
209
SceneManager/Barriers/Barrier.cs
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
using Rage;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Paths;
|
||||
using SceneManager.Utils;
|
||||
|
||||
namespace SceneManager.Barriers
|
||||
{
|
||||
public class Barrier : IDeletable, IHandleable, ISpatial
|
||||
{
|
||||
private Object _object { get; }
|
||||
public string ModelName { get; set; }
|
||||
public Vector3 Position { get; set; }
|
||||
public float Heading { get; set; }
|
||||
public bool Invincible { get; set; }
|
||||
public bool Immobile { get; set; }
|
||||
public bool LightsEnabled { get; set; }
|
||||
public int TextureVariation { get; set; }
|
||||
internal Path Path { get; set; }
|
||||
|
||||
public PoolHandle Handle => ((IHandleable)_object).Handle;
|
||||
|
||||
private Barrier() { }
|
||||
|
||||
internal Barrier(Barrier obj, bool invincible, bool immobile, int textureVariation = 0, bool lightsEnabled = false)
|
||||
{
|
||||
ModelName = obj.ModelName;
|
||||
Position = obj.Position;
|
||||
Heading = obj.Heading;
|
||||
Invincible = invincible;
|
||||
Immobile = immobile;
|
||||
TextureVariation = textureVariation;
|
||||
LightsEnabled = lightsEnabled;
|
||||
if (obj.IsValid())
|
||||
{
|
||||
obj.Delete();
|
||||
}
|
||||
|
||||
if (ModelName == "0xa2c44e80") // Flare
|
||||
{
|
||||
var flare = new Weapon("weapon_flare", Position, 1);
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(flare, true);
|
||||
_object = flare;
|
||||
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(_object, true);
|
||||
GameFiber.Sleep(1000);
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(_object, false);
|
||||
}, "Spawn Flare Fiber");
|
||||
}
|
||||
else // Any other barrier object
|
||||
{
|
||||
_object = new Object(ModelName, Position, Heading);
|
||||
_object.SetPositionWithSnap(Position);
|
||||
Rage.Native.NativeFunction.Natives.PLACE_OBJECT_ON_GROUND_PROPERLY<bool>(_object);
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(_object, true);
|
||||
|
||||
if (Invincible)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_DISABLE_FRAG_DAMAGE(_object, true);
|
||||
if (ModelName != "prop_barrier_wat_03a")
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_DISABLE_BREAKING(_object, true);
|
||||
}
|
||||
}
|
||||
_object.IsPositionFrozen = Immobile;
|
||||
|
||||
if (Settings.EnableAdvancedBarricadeOptions)
|
||||
{
|
||||
SetAdvancedOptions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal Barrier(Object obj, bool invincible, bool immobile, int textureVariation = 0, bool lightsEnabled = false)
|
||||
{
|
||||
ModelName = obj.Model.Name;
|
||||
Position = obj.Position;
|
||||
Heading = obj.Heading;
|
||||
Invincible = invincible;
|
||||
Immobile = immobile;
|
||||
TextureVariation = textureVariation;
|
||||
LightsEnabled = lightsEnabled;
|
||||
if(BarrierManager.PlaceholderBarrier)
|
||||
{
|
||||
BarrierManager.PlaceholderBarrier.Delete();
|
||||
}
|
||||
|
||||
if (ModelName == "0xa2c44e80") // Flare
|
||||
{
|
||||
_object = obj;
|
||||
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(_object, true);
|
||||
GameFiber.Sleep(1000);
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(_object, false);
|
||||
}, "Spawn Flare Fiber");
|
||||
}
|
||||
else // Any other barrier object
|
||||
{
|
||||
_object = new Object(ModelName, Position, Heading);
|
||||
_object.SetPositionWithSnap(Position);
|
||||
Rage.Native.NativeFunction.Natives.PLACE_OBJECT_ON_GROUND_PROPERLY<bool>(_object);
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(_object, true);
|
||||
|
||||
if (Invincible)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_DISABLE_FRAG_DAMAGE(_object, true);
|
||||
if (ModelName != "prop_barrier_wat_03a")
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_DISABLE_BREAKING(_object, true);
|
||||
}
|
||||
}
|
||||
_object.IsPositionFrozen = Immobile;
|
||||
|
||||
if (Settings.EnableAdvancedBarricadeOptions)
|
||||
{
|
||||
SetAdvancedOptions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetAdvancedOptions()
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.x971DA0055324D033(_object, TextureVariation);
|
||||
if (LightsEnabled)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_LIGHTS(_object, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_LIGHTS(_object, true);
|
||||
}
|
||||
|
||||
//Rage.Native.NativeFunction.Natives.SET_ENTITY_TRAFFICLIGHT_OVERRIDE(barrier, setBarrierTrafficLight.Index);
|
||||
_object.IsPositionFrozen = true;
|
||||
GameFiber.Sleep(50);
|
||||
if (_object && !Immobile)
|
||||
{
|
||||
_object.IsPositionFrozen = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal void LoadFromImport(Path path)
|
||||
{
|
||||
Path = path;
|
||||
Game.LogTrivial($"===== BARRIER DATA =====");
|
||||
Game.LogTrivial($"Model: {ModelName}");
|
||||
Game.LogTrivial($"Position: {Position}");
|
||||
Game.LogTrivial($"Heading: {Heading}");
|
||||
Game.LogTrivial($"Invincible: {Invincible}");
|
||||
Game.LogTrivial($"Immobile: {Immobile}");
|
||||
Game.LogTrivial($"LightsEnabled: {LightsEnabled}");
|
||||
Game.LogTrivial($"Texture Variation: {TextureVariation}");
|
||||
var barrier = new Barrier(this, Invincible, Immobile, TextureVariation, LightsEnabled);
|
||||
Path.Barriers.Add(barrier);
|
||||
BarrierManager.Barriers.Add(barrier);
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
if (_object)
|
||||
{
|
||||
((IDeletable)_object).Delete();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
return _object != null;
|
||||
}
|
||||
|
||||
public bool Equals(IHandleable other)
|
||||
{
|
||||
return ((System.IEquatable<IHandleable>)_object).Equals(other);
|
||||
}
|
||||
|
||||
public float DistanceTo(Vector3 position)
|
||||
{
|
||||
return ((ISpatial)_object).DistanceTo(position);
|
||||
}
|
||||
|
||||
public float DistanceTo(ISpatial spatialObject)
|
||||
{
|
||||
return ((ISpatial)_object).DistanceTo(spatialObject);
|
||||
}
|
||||
|
||||
public float DistanceTo2D(Vector3 position)
|
||||
{
|
||||
return ((ISpatial)_object).DistanceTo2D(position);
|
||||
}
|
||||
|
||||
public float DistanceTo2D(ISpatial spatialObject)
|
||||
{
|
||||
return ((ISpatial)_object).DistanceTo2D(spatialObject);
|
||||
}
|
||||
|
||||
public float TravelDistanceTo(Vector3 position)
|
||||
{
|
||||
return ((ISpatial)_object).TravelDistanceTo(position);
|
||||
}
|
||||
|
||||
public float TravelDistanceTo(ISpatial spatialObject)
|
||||
{
|
||||
return ((ISpatial)_object).TravelDistanceTo(spatialObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
456
SceneManager/CollectedPeds/CollectedPed.cs
Normal file
456
SceneManager/CollectedPeds/CollectedPed.cs
Normal file
|
|
@ -0,0 +1,456 @@
|
|||
using Rage;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SceneManager.Utils;
|
||||
using SceneManager.Waypoints;
|
||||
using SceneManager.Paths;
|
||||
|
||||
namespace SceneManager.CollectedPeds
|
||||
{
|
||||
internal class CollectedPed : Ped
|
||||
{
|
||||
internal Path Path { get; set; }
|
||||
internal Waypoint CurrentWaypoint { get; 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 basePed, Path path, Waypoint waypoint) : base(basePed.Handle)
|
||||
{
|
||||
Handle = basePed.Handle;
|
||||
Path = path;
|
||||
CurrentWaypoint = waypoint;
|
||||
SetPersistence();
|
||||
Game.LogTrivial($"Added {CurrentVehicle.Model.Name} to collection from path \"{Path.Name}\" waypoint {CurrentWaypoint.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 (Path.State == State.Deleting || !VehicleAndDriverAreValid())
|
||||
{
|
||||
Dismiss();
|
||||
return;
|
||||
}
|
||||
|
||||
if(Directed)
|
||||
{
|
||||
Dismiss(Utils.Dismiss.FromDirected);
|
||||
}
|
||||
|
||||
Game.LogTrivial($"{CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] all path \"{Path.Name}\" tasks complete.");
|
||||
Dismiss();
|
||||
}
|
||||
|
||||
private void AssignDirectedTask()
|
||||
{
|
||||
if (CurrentWaypoint != null && Directed)
|
||||
{
|
||||
Dismissed = false;
|
||||
|
||||
while (!ReadyForDirectTasks)
|
||||
{
|
||||
GameFiber.Yield();
|
||||
}
|
||||
if (!VehicleAndDriverAreValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Tasks.Clear();
|
||||
DriveToDirectedWaypoint();
|
||||
}
|
||||
}
|
||||
|
||||
private 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 \"{Path.Name}\" 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(!VehicleAndDriverAreValid() || Path.State == State.Deleting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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.Name}\"");
|
||||
for (int currentWaypointTask = CurrentWaypoint.Number; currentWaypointTask < Path.Waypoints.Count; currentWaypointTask++)
|
||||
{
|
||||
var oldPosition = Path.Waypoints[currentWaypointTask].Position;
|
||||
SkipWaypoint = false;
|
||||
|
||||
if (this == null || !this || !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.Name}\" 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)
|
||||
{
|
||||
int lostTasks = 0;
|
||||
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(lostTasks == 3)
|
||||
{
|
||||
Game.LogTrivial($"{CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] driver [{Handle}] lost their task too many times. Dismissing from world to prevent problems.");
|
||||
Dismiss(Utils.Dismiss.FromWorld);
|
||||
return;
|
||||
}
|
||||
if (CurrentVehicle)
|
||||
{
|
||||
Tasks.DriveToPosition(Path.Waypoints[currentWaypointTask].Position, Path.Waypoints[currentWaypointTask].Speed, (VehicleDrivingFlags)Path.Waypoints[currentWaypointTask].DrivingFlagType, acceptedDistance);
|
||||
lostTasks++;
|
||||
Game.LogTrivial($"{CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] driver [{Handle}] should have a task now.");
|
||||
}
|
||||
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.Name}\" waypoint.");
|
||||
var vehicleToStop = CurrentVehicle;
|
||||
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(vehicleToStop, stoppingDistance, -1, true);
|
||||
StoppedAtWaypoint = true;
|
||||
|
||||
while (CurrentWaypoint != null && VehicleAndDriverAreValid() && StoppedAtWaypoint && !Directed && IsInVehicle(CurrentVehicle, false))
|
||||
{
|
||||
GameFiber.Yield();
|
||||
}
|
||||
if(vehicleToStop)
|
||||
{
|
||||
Game.LogTrivial($"{vehicleToStop.Model.Name} releasing from stop waypoint.");
|
||||
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(vehicleToStop, 0f, 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
private bool VehicleAndDriverAreValid()
|
||||
{
|
||||
if (!this)
|
||||
{
|
||||
Game.LogTrivial($"CollectedPed is null");
|
||||
return false;
|
||||
}
|
||||
if (!CurrentVehicle)
|
||||
{
|
||||
Game.LogTrivial($"Vehicle is null");
|
||||
return false;
|
||||
}
|
||||
if (!IsAlive)
|
||||
{
|
||||
Game.LogTrivial($"Driver is null or dead or not in a vehicle");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void Dismiss(Dismiss dismissOption = Utils.Dismiss.FromPath, Path newPath = null)
|
||||
{
|
||||
if(!this)
|
||||
{
|
||||
Game.LogTrivial($"CollectedPed is not valid in Dismiss.");
|
||||
Path.CollectedPeds.Remove(this);
|
||||
return;
|
||||
}
|
||||
if(Dismissed)
|
||||
{
|
||||
Game.LogTrivial($"CollectedPed is already dismissed.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dismissOption == Utils.Dismiss.FromWorld)
|
||||
{
|
||||
DismissFromWorld();
|
||||
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 DismissFromWorld()
|
||||
{
|
||||
Game.LogTrivial($"Dismissed {CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] from the world");
|
||||
if (GetAttachedBlip())
|
||||
{
|
||||
GetAttachedBlip().Delete();
|
||||
}
|
||||
while (this && CurrentVehicle && CurrentVehicle.HasOccupants)
|
||||
{
|
||||
foreach (Ped occupant in CurrentVehicle.Occupants)
|
||||
{
|
||||
occupant.Delete();
|
||||
}
|
||||
GameFiber.Yield();
|
||||
}
|
||||
if(!this)
|
||||
{
|
||||
Path.CollectedPeds.Remove(this);
|
||||
return;
|
||||
}
|
||||
if (CurrentVehicle)
|
||||
{
|
||||
CurrentVehicle.Delete();
|
||||
}
|
||||
Path.CollectedPeds.Remove(this);
|
||||
}
|
||||
|
||||
void DismissFromWaypoint()
|
||||
{
|
||||
if (Path == null)
|
||||
{
|
||||
Game.LogTrivial($"Path is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if(CurrentWaypoint == null)
|
||||
{
|
||||
Game.LogTrivial($"CurrentWaypoint 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()
|
||||
{
|
||||
if(!this)
|
||||
{
|
||||
Game.LogTrivial($"CollectedPed is not valid in DismissFromPath.");
|
||||
Path.CollectedPeds.Remove(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if(Dismissed)
|
||||
{
|
||||
Game.LogTrivial($"CollectedPed is already dismissed.");
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
//{
|
||||
// while (nearestCollectorWaypoint != null && CurrentVehicle && CurrentVehicle.HasDriver && this && IsAlive && CurrentVehicle.FrontPosition.DistanceTo2D(nearestCollectorWaypoint.Position) <= nearestCollectorWaypoint.CollectorRadius)
|
||||
// {
|
||||
// GameFiber.Yield();
|
||||
// }
|
||||
//}
|
||||
|
||||
if (!Directed)
|
||||
{
|
||||
if (this)
|
||||
{
|
||||
if (GetAttachedBlip())
|
||||
{
|
||||
GetAttachedBlip().Delete();
|
||||
}
|
||||
BlockPermanentEvents = false;
|
||||
IsPersistent = false;
|
||||
base.Dismiss();
|
||||
}
|
||||
|
||||
if (CurrentVehicle)
|
||||
{
|
||||
Game.LogTrivial($"{CurrentVehicle.Model.Name} [{CurrentVehicle.Handle}] dismissed successfully.");
|
||||
LastVehicle.Dismiss();
|
||||
|
||||
if (CurrentVehicle)
|
||||
{
|
||||
LastVehicle.IsSirenOn = false;
|
||||
LastVehicle.IsSirenSilent = true;
|
||||
}
|
||||
}
|
||||
Path.CollectedPeds.Remove(this);
|
||||
}
|
||||
//}, "DismissFromPath Fiber");
|
||||
}
|
||||
|
||||
void DismissFromDirect()
|
||||
{
|
||||
Dismissed = true;
|
||||
Directed = true;
|
||||
if (newPath != null)
|
||||
{
|
||||
newPath.CollectedPeds.Add(this);
|
||||
Path.CollectedPeds.Remove(this);
|
||||
}
|
||||
Tasks.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
using Rage;
|
||||
using SceneManager.Objects;
|
||||
using SceneManager.Utils;
|
||||
using SceneManager.Menus;
|
||||
using SceneManager.Managers;
|
||||
|
||||
[assembly: Rage.Attributes.Plugin("Scene Manager", Author = "Rich", Description = "Control your scenes with custom AI pathing and traffic barrier management.", PrefersSingleInstance = true)]
|
||||
|
||||
|
|
@ -17,10 +15,9 @@ namespace SceneManager
|
|||
[Obfuscation(Exclude = false, Feature = "-rename")]
|
||||
internal static void Main()
|
||||
{
|
||||
if(!InputManagerChecker() || !CheckRNUIVersion())
|
||||
if (!DependencyChecker.DependenciesInstalled())
|
||||
{
|
||||
Game.UnloadActivePlugin();
|
||||
return;
|
||||
}
|
||||
|
||||
while (Game.IsLoading)
|
||||
|
|
@ -28,15 +25,13 @@ namespace SceneManager
|
|||
GameFiber.Yield();
|
||||
}
|
||||
|
||||
AppDomain.CurrentDomain.DomainUnload += MyTerminationHandler;
|
||||
AppDomain.CurrentDomain.DomainUnload += TerminationHandler;
|
||||
Settings.LoadSettings();
|
||||
GetAssemblyVersion();
|
||||
MenuManager.InstantiateMenus();
|
||||
MenuManager.InitializeMenus();
|
||||
Hints.DisplayHintsToOpenMenu();
|
||||
|
||||
DisplayHintsToOpenMenu();
|
||||
|
||||
GameFiber UserInputFiber = new GameFiber(() => GetUserInput.LoopForUserInput());
|
||||
UserInputFiber.Start();
|
||||
GameFiber.StartNew(() => UserInput.HandleKeyPress(), "Handle User Input");
|
||||
|
||||
void GetAssemblyVersion()
|
||||
{
|
||||
|
|
@ -45,84 +40,22 @@ namespace SceneManager
|
|||
}
|
||||
}
|
||||
|
||||
private static bool CheckRNUIVersion()
|
||||
private static void TerminationHandler(object sender, EventArgs e)
|
||||
{
|
||||
var directory = Directory.GetCurrentDirectory();
|
||||
var exists = File.Exists(directory + @"\RAGENativeUI.dll");
|
||||
if (!exists)
|
||||
try
|
||||
{
|
||||
Game.LogTrivial($"RNUI was not found in the user's GTA V directory.");
|
||||
Game.DisplayNotification($"~o~Scene Manager ~r~[Error]\n~w~RAGENativeUI.dll was not found in your GTA V directory. Please install RAGENativeUI and try again.");
|
||||
return false;
|
||||
ExportPathMenu.ExportOnUnload();
|
||||
}
|
||||
|
||||
var userVersion = Assembly.LoadFrom(directory + @"\RAGENativeUI.dll").GetName().Version;
|
||||
Version requiredMinimumVersion = new Version("1.7.0.0");
|
||||
if(userVersion >= requiredMinimumVersion)
|
||||
catch(Exception ex)
|
||||
{
|
||||
Game.LogTrivial($"User's RNUI version: {userVersion}");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.DisplayNotification($"~o~Scene Manager~r~[Error]\n~w~Your RAGENativeUI.dll version is below 1.7. Please update RAGENativeUI and try again.");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static bool InputManagerChecker()
|
||||
{
|
||||
var directory = Directory.GetCurrentDirectory();
|
||||
var exists = File.Exists(directory + @"\InputManager.dll");
|
||||
if (!exists)
|
||||
{
|
||||
Game.LogTrivial($"InputManager was not found in the user's GTA V directory.");
|
||||
Game.DisplayNotification($"~o~Scene Manager ~r~[Error]\n~w~InputManager.dll was not found in your GTA V directory. Please install InputManager.dll and try again.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void DisplayHintsToOpenMenu()
|
||||
{
|
||||
if (Settings.ModifierKey == Keys.None && Settings.ModifierButton == ControllerButtons.None)
|
||||
{
|
||||
Hints.Display($"~o~Scene Manager ~y~[Hint]\n~w~To open the menu, press the ~b~{Settings.ToggleKey} key ~w~or ~b~{Settings.ToggleButton} button");
|
||||
}
|
||||
else if (Settings.ModifierKey == Keys.None)
|
||||
{
|
||||
Hints.Display($"~o~Scene Manager ~y~[Hint]\n~w~To open the menu, press the ~b~{Settings.ToggleKey} key ~w~or ~b~{Settings.ModifierButton} ~w~+ ~b~{Settings.ToggleButton} buttons");
|
||||
}
|
||||
else if (Settings.ModifierButton == ControllerButtons.None)
|
||||
{
|
||||
Hints.Display($"~o~Scene Manager ~y~[Hint]\n~w~To open the menu, press ~b~{Settings.ModifierKey} ~w~+ ~b~{Settings.ToggleKey} ~w~or the ~b~{Settings.ToggleButton} button");
|
||||
}
|
||||
else
|
||||
{
|
||||
Hints.Display($"~o~Scene Manager ~y~[Hint]\n~w~To open the menu, press the ~b~{Settings.ModifierKey} ~w~+ ~b~{Settings.ToggleKey} keys ~w~or ~b~{Settings.ModifierButton} ~w~+ ~b~{Settings.ToggleButton} buttons");
|
||||
}
|
||||
}
|
||||
private static void MyTerminationHandler(object sender, EventArgs e)
|
||||
{
|
||||
// Clean up cones
|
||||
foreach (Barrier barrier in BarrierMenu.barriers.Where(b => b.Object))
|
||||
{
|
||||
barrier.Object.Delete();
|
||||
}
|
||||
if (BarrierMenu.shadowBarrier)
|
||||
{
|
||||
BarrierMenu.shadowBarrier.Delete();
|
||||
}
|
||||
|
||||
// Clean up paths
|
||||
for (int i = 0; i < PathMainMenu.paths.Count; i++)
|
||||
{
|
||||
PathMainMenu.DeletePath(PathMainMenu.paths[i], Delete.All);
|
||||
Game.LogTrivial($"Autosave error: {ex.Message}");
|
||||
Game.DisplayNotification($"~o~Scene Manager ~r~[Error]\n~w~There was a problem autosaving the paths.");
|
||||
}
|
||||
BarrierMenu.Cleanup();
|
||||
PathManager.DeleteAllPaths();
|
||||
|
||||
Game.LogTrivial($"Plugin has shut down.");
|
||||
Game.DisplayNotification($"~o~Scene Manager ~r~[Terminated]\n~w~The plugin has shut down.");
|
||||
//Game.DisplayNotification($"~o~Scene Manager ~r~[Terminated]\n~w~The plugin has shut down.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
using Rage;
|
||||
|
||||
namespace SceneManager
|
||||
{
|
||||
class Hints
|
||||
{
|
||||
internal static bool Enabled { get; set; } = SettingsMenu.hints.Checked;
|
||||
|
||||
internal static void Display(string message)
|
||||
{
|
||||
if (Enabled)
|
||||
{
|
||||
Game.DisplayNotification($"{message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
272
SceneManager/Managers/BarrierManager.cs
Normal file
272
SceneManager/Managers/BarrierManager.cs
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Rage;
|
||||
using RAGENativeUI;
|
||||
using SceneManager.Barriers;
|
||||
using SceneManager.Menus;
|
||||
using SceneManager.Paths;
|
||||
using SceneManager.Utils;
|
||||
|
||||
namespace SceneManager.Managers
|
||||
{
|
||||
internal static class BarrierManager
|
||||
{
|
||||
internal static Object PlaceholderBarrier { get; private set; }
|
||||
internal static List<Barrier> Barriers { get; } = new List<Barrier>();
|
||||
|
||||
internal static void CreatePlaceholderBarrier()
|
||||
{
|
||||
Hints.Display($"~o~Scene Manager ~y~[Hint]\n~w~The shadow barrier will disappear if you aim too far away.");
|
||||
if (PlaceholderBarrier)
|
||||
{
|
||||
PlaceholderBarrier.Delete();
|
||||
}
|
||||
|
||||
var barrierKey = Settings.BarrierModels.Where(x => x.Key == BarrierMenu.BarrierList.SelectedItem).FirstOrDefault().Key;
|
||||
var barrierValue = Settings.BarrierModels[barrierKey].Name;
|
||||
PlaceholderBarrier = new Object(barrierValue, UserInput.PlayerMousePositionForBarrier, BarrierMenu.RotateBarrier.Value);
|
||||
if (!PlaceholderBarrier)
|
||||
{
|
||||
BarrierMenu.Menu.Close();
|
||||
Game.LogTrivial($"Something went wrong creating the placeholder barrier. Mouse position: {UserInput.PlayerMousePositionForBarrier}");
|
||||
Game.DisplayNotification($"~o~Scene Manager ~r~[Error]\n~w~Something went wrong creating the placeholder barrier. This is a rare problem that only happens in certain areas of the world. Please try again somewhere else.");
|
||||
return;
|
||||
}
|
||||
|
||||
//Rage.Native.NativeFunction.Natives.SET_ENTITY_TRAFFICLIGHT_OVERRIDE(shadowBarrier, setBarrierTrafficLight.Index);
|
||||
Rage.Native.NativeFunction.Natives.PLACE_OBJECT_ON_GROUND_PROPERLY(PlaceholderBarrier);
|
||||
PlaceholderBarrier.IsGravityDisabled = true;
|
||||
PlaceholderBarrier.IsCollisionEnabled = false;
|
||||
PlaceholderBarrier.Opacity = 0.7f;
|
||||
|
||||
// Start with lights off for Parks's objects
|
||||
if (Settings.EnableAdvancedBarricadeOptions)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.x971DA0055324D033(PlaceholderBarrier, BarrierMenu.BarrierTexture.Value); // _SET_OBJECT_TEXTURE_VARIATION
|
||||
SetBarrierLights();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SetBarrierLights()
|
||||
{
|
||||
if (BarrierMenu.SetBarrierLights.Checked)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_LIGHTS(PlaceholderBarrier, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_LIGHTS(PlaceholderBarrier, true);
|
||||
}
|
||||
|
||||
//Rage.Native.NativeFunction.Natives.SET_ENTITY_TRAFFICLIGHT_OVERRIDE(shadowBarrier, setBarrierTrafficLight.Index);
|
||||
}
|
||||
|
||||
internal static void UpdatePlaceholderBarrierPosition()
|
||||
{
|
||||
DisableBarrierMenuOptionsIfPlaceholderTooFar();
|
||||
if (PlaceholderBarrier)
|
||||
{
|
||||
PlaceholderBarrier.Heading = BarrierMenu.RotateBarrier.Value;
|
||||
PlaceholderBarrier.Position = UserInput.PlayerMousePositionForBarrier;
|
||||
Rage.Native.NativeFunction.Natives.PLACE_OBJECT_ON_GROUND_PROPERLY<bool>(PlaceholderBarrier);
|
||||
//Rage.Native.NativeFunction.Natives.SET_ENTITY_TRAFFICLIGHT_OVERRIDE(shadowBarrier, setBarrierTrafficLight.Index);
|
||||
}
|
||||
|
||||
void DisableBarrierMenuOptionsIfPlaceholderTooFar()
|
||||
{
|
||||
if (!PlaceholderBarrier && UserInput.PlayerMousePositionForBarrier.DistanceTo2D(Game.LocalPlayer.Character.Position) <= Settings.BarrierPlacementDistance)
|
||||
{
|
||||
CreatePlaceholderBarrier();
|
||||
|
||||
}
|
||||
else if (PlaceholderBarrier && PlaceholderBarrier.Position.DistanceTo2D(Game.LocalPlayer.Character.Position) > Settings.BarrierPlacementDistance)
|
||||
{
|
||||
BarrierMenu.BarrierList.Enabled = false;
|
||||
BarrierMenu.RotateBarrier.Enabled = false;
|
||||
PlaceholderBarrier.Delete();
|
||||
}
|
||||
else if (PlaceholderBarrier && PlaceholderBarrier.Position.DistanceTo2D(Game.LocalPlayer.Character.Position) <= Settings.BarrierPlacementDistance && BarrierMenu.BarrierList.SelectedItem == "Flare")
|
||||
{
|
||||
BarrierMenu.BarrierList.Enabled = true;
|
||||
BarrierMenu.RotateBarrier.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
BarrierMenu.BarrierList.Enabled = true;
|
||||
BarrierMenu.RotateBarrier.Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void LoopToRenderPlaceholderBarrier()
|
||||
{
|
||||
while (BarrierMenu.Menu.Visible)
|
||||
{
|
||||
if (BarrierMenu.BarrierList.Selected || BarrierMenu.RotateBarrier.Selected || BarrierMenu.Invincible.Selected || BarrierMenu.Immobile.Selected || BarrierMenu.BarrierTexture.Selected || BarrierMenu.SetBarrierLights.Selected || BarrierMenu.SetBarrierTrafficLight.Selected)
|
||||
{
|
||||
if (PlaceholderBarrier)
|
||||
{
|
||||
UpdatePlaceholderBarrierPosition();
|
||||
}
|
||||
else if (UserInput.PlayerMousePositionForBarrier.DistanceTo2D(Game.LocalPlayer.Character.Position) <= Settings.BarrierPlacementDistance)
|
||||
{
|
||||
CreatePlaceholderBarrier();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PlaceholderBarrier)
|
||||
{
|
||||
PlaceholderBarrier.Delete();
|
||||
}
|
||||
}
|
||||
GameFiber.Yield();
|
||||
}
|
||||
|
||||
if (PlaceholderBarrier)
|
||||
{
|
||||
PlaceholderBarrier.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SpawnBarrier()
|
||||
{
|
||||
Barrier barrier;
|
||||
|
||||
if (BarrierMenu.BarrierList.SelectedItem == "Flare")
|
||||
{
|
||||
SpawnFlare();
|
||||
}
|
||||
else
|
||||
{
|
||||
barrier = new Barrier(PlaceholderBarrier, BarrierMenu.Invincible.Checked, BarrierMenu.Immobile.Checked, BarrierMenu.BarrierTexture.Value, BarrierMenu.SetBarrierLights.Checked);
|
||||
Barriers.Add(barrier);
|
||||
|
||||
BarrierMenu.AddUnassignedToPath.Enabled = true;
|
||||
BarrierMenu.RemoveBarrierOptions.Enabled = true;
|
||||
BarrierMenu.ResetBarriers.Enabled = true;
|
||||
}
|
||||
|
||||
if (barrier != null && BarrierMenu.BelongsToPath.Checked)
|
||||
{
|
||||
var matchingPath = PathManager.Paths.FirstOrDefault(x => x.Name == BarrierMenu.AddToPath.OptionText);
|
||||
if(matchingPath != null)
|
||||
{
|
||||
matchingPath.Barriers.Add(barrier);
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnFlare()
|
||||
{
|
||||
var flare = new Weapon("weapon_flare", PlaceholderBarrier.Position, 1);
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(flare, true);
|
||||
|
||||
barrier = new Barrier(flare, BarrierMenu.Invincible.Checked, BarrierMenu.Immobile.Checked);
|
||||
Barriers.Add(barrier);
|
||||
|
||||
BarrierMenu.AddUnassignedToPath.Enabled = true;
|
||||
BarrierMenu.RemoveBarrierOptions.Enabled = true;
|
||||
BarrierMenu.ResetBarriers.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void RemoveBarrier(int removeBarrierOptionsIndex)
|
||||
{
|
||||
Path path;
|
||||
switch (removeBarrierOptionsIndex)
|
||||
{
|
||||
case 0:
|
||||
var barrierToRemove = Barriers[Barriers.Count - 1];
|
||||
path = PathManager.Paths.FirstOrDefault(x => x != null && x.Barriers.Contains(barrierToRemove));
|
||||
if(path != null)
|
||||
{
|
||||
path.Barriers.Remove(barrierToRemove);
|
||||
}
|
||||
|
||||
barrierToRemove.Delete();
|
||||
Barriers.RemoveAt(Barriers.Count - 1);
|
||||
break;
|
||||
case 1:
|
||||
var nearestBarrier = Barriers.OrderBy(b => b.DistanceTo2D(Game.LocalPlayer.Character)).FirstOrDefault();
|
||||
if (nearestBarrier != null)
|
||||
{
|
||||
path = PathManager.Paths.FirstOrDefault(x => x != null && x.Barriers.Contains(nearestBarrier));
|
||||
if (path != null)
|
||||
{
|
||||
path.Barriers.Remove(nearestBarrier);
|
||||
}
|
||||
|
||||
nearestBarrier.Delete();
|
||||
Barriers.Remove(nearestBarrier);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
foreach (Barrier barrier in Barriers)
|
||||
{
|
||||
if(barrier.Path != null)
|
||||
{
|
||||
barrier.Path.Barriers.Remove(barrier);
|
||||
}
|
||||
|
||||
barrier.Delete();
|
||||
}
|
||||
if (Barriers.Count > 0)
|
||||
{
|
||||
Barriers.Clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
BarrierMenu.AddUnassignedToPath.Enabled = Barriers.Any(x => x.Path == null);
|
||||
BarrierMenu.RemoveBarrierOptions.Enabled = Barriers.Count != 0;
|
||||
BarrierMenu.ResetBarriers.Enabled = Barriers.Count != 0;
|
||||
}
|
||||
|
||||
internal static void ResetBarriers()
|
||||
{
|
||||
//GameFiber.StartNew(() =>
|
||||
//{
|
||||
Game.DisplayHelp($"~{InstructionalKey.SymbolBusySpinner.GetId()}~ Resetting barriers...");
|
||||
var currentBarriers = Barriers.Where(b => b.ModelName != "0xa2c44e80").ToList(); // 0xa2c44e80 is the flare weapon hash
|
||||
foreach (Barrier barrier in currentBarriers)
|
||||
{
|
||||
var newBarrier = new Barrier(barrier, barrier.Invincible, barrier.Immobile, barrier.TextureVariation, barrier.LightsEnabled);
|
||||
Barriers.Add(newBarrier);
|
||||
|
||||
//barrier.Delete();
|
||||
Barriers.Remove(barrier);
|
||||
}
|
||||
currentBarriers.Clear();
|
||||
//}, "Barrier Reset Fiber");
|
||||
|
||||
}
|
||||
|
||||
internal static void RotateBarrier()
|
||||
{
|
||||
PlaceholderBarrier.Heading = BarrierMenu.RotateBarrier.Value;
|
||||
PlaceholderBarrier.Position = UserInput.PlayerMousePositionForBarrier;
|
||||
Rage.Native.NativeFunction.Natives.PLACE_OBJECT_ON_GROUND_PROPERLY(PlaceholderBarrier);
|
||||
}
|
||||
|
||||
internal static void AddBarrierToPath()
|
||||
{
|
||||
var unassignedBarriers = Barriers.Where(x => x.Path == null);
|
||||
if(unassignedBarriers.Count() == 0)
|
||||
{
|
||||
Game.LogTrivial($"There are no unassigned barriers.");
|
||||
return;
|
||||
}
|
||||
|
||||
var pathToAssignTo = PathManager.Paths.First(x => x.Name == BarrierMenu.AddUnassignedToPath.OptionText);
|
||||
foreach (Barrier barrier in unassignedBarriers)
|
||||
{
|
||||
pathToAssignTo.Barriers.Add(barrier);
|
||||
}
|
||||
|
||||
Game.LogTrivial($"Added {unassignedBarriers.Count()} unassigned barrier to {pathToAssignTo.Name}");
|
||||
Game.DisplayNotification($"~o~Scene Manager ~y~[Barriers]\n~w~Assigned ~b~{unassignedBarriers.Count()} ~w~barrier(s) to ~b~{pathToAssignTo.Name}~w~.");
|
||||
|
||||
BarrierMenu.AddUnassignedToPath.Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
134
SceneManager/Managers/MenuManager.cs
Normal file
134
SceneManager/Managers/MenuManager.cs
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
using RAGENativeUI;
|
||||
using SceneManager.Menus;
|
||||
using SceneManager.Utils;
|
||||
using Rage;
|
||||
using System.Linq;
|
||||
using RAGENativeUI.Elements;
|
||||
using System.Drawing;
|
||||
|
||||
namespace SceneManager.Managers
|
||||
{
|
||||
// The only reason this class should change is to modify how menus are are being handled
|
||||
internal static class MenuManager
|
||||
{
|
||||
internal static MenuPool MenuPool { get; } = new MenuPool();
|
||||
|
||||
internal static void InitializeMenus()
|
||||
{
|
||||
MainMenu.Initialize();
|
||||
SettingsMenu.Initialize();
|
||||
ImportPathMenu.Initialize();
|
||||
PathMainMenu.Initialize();
|
||||
PathCreationMenu.Initialize();
|
||||
ExportPathMenu.Initialize();
|
||||
DriverMenu.Initialize();
|
||||
BarrierMenu.Initialize();
|
||||
EditPathMenu.Initialize();
|
||||
EditWaypointMenu.Initialize();
|
||||
|
||||
BuildMenus();
|
||||
ColorMenuItems();
|
||||
DefineMenuMouseSettings();
|
||||
}
|
||||
|
||||
private static void DefineMenuMouseSettings()
|
||||
{
|
||||
foreach (UIMenu menu in MenuPool)
|
||||
{
|
||||
menu.MouseControlsEnabled = false;
|
||||
menu.AllowCameraMovement = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void BuildMenus()
|
||||
{
|
||||
MainMenu.Build();
|
||||
SettingsMenu.Build();
|
||||
ImportPathMenu.Build();
|
||||
ExportPathMenu.Build();
|
||||
DriverMenu.Build();
|
||||
PathMainMenu.Build();
|
||||
PathCreationMenu.Build();
|
||||
EditPathMenu.Build();
|
||||
BarrierMenu.Build();
|
||||
foreach(UIMenu menu in MenuPool)
|
||||
{
|
||||
//Game.LogTrivial($"Setting with of {menu.SubtitleText} menu.");
|
||||
SetMenuWidth(menu);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ColorMenuItems()
|
||||
{
|
||||
foreach(UIMenuItem menuItem in MenuPool.SelectMany(x => x.MenuItems))
|
||||
{
|
||||
if (menuItem.Enabled)
|
||||
{
|
||||
menuItem.HighlightedBackColor = menuItem.ForeColor;
|
||||
}
|
||||
if(!menuItem.Enabled)
|
||||
{
|
||||
menuItem.HighlightedBackColor = Color.DarkGray;
|
||||
menuItem.DisabledForeColor = Color.Gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ProcessMenus()
|
||||
{
|
||||
while (MenuPool.Any(x => x.Visible))
|
||||
{
|
||||
MenuPool.ProcessMenus();
|
||||
ColorMenuItems();
|
||||
GameFiber.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SetMenuWidth(UIMenu menu)
|
||||
{
|
||||
float MINIMUM_WIDTH = 0.25f;
|
||||
//float PADDING = 0.00390625f * 2; // typical padding used in RNUI
|
||||
float widthToAssign = MINIMUM_WIDTH;
|
||||
//float scrollerItemWidth = 0;
|
||||
//float totalWidth = 0;
|
||||
|
||||
//Game.LogTrivial($"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
foreach(UIMenuItem menuItem in menu.MenuItems)
|
||||
{
|
||||
//Game.LogTrivial($"========== Menu Item: {menuItem.Text}");
|
||||
float textWidth = menuItem.GetTextWidth();
|
||||
//Game.LogTrivial($"Menu Item Text Width: {textWidth}");
|
||||
|
||||
float newWidth = textWidth;
|
||||
if (menuItem.GetType() == typeof(UIMenuListScrollerItem<string>))
|
||||
{
|
||||
var scrollerItem = menuItem as UIMenuListScrollerItem<string>;
|
||||
float selectedItemTextWidth = scrollerItem.GetSelectedItemTextWidth();
|
||||
//Game.LogTrivial($"Menu Item Scroller Text Width: {selectedItemTextWidth}");
|
||||
|
||||
//totalWidth = textWidth + selectedItemTextWidth;
|
||||
//Game.LogTrivial($"Total Width: {totalWidth}");
|
||||
|
||||
newWidth += selectedItemTextWidth * 1.3f;
|
||||
//Game.LogTrivial($"========== New Width from Longer Selected Item Text: {newWidth}");
|
||||
}
|
||||
|
||||
if (menuItem.LeftBadge != UIMenuItem.BadgeStyle.None)
|
||||
{
|
||||
newWidth += 0.02f;
|
||||
}
|
||||
|
||||
if(newWidth > 0.25f && menuItem.LeftBadge != UIMenuItem.BadgeStyle.None)
|
||||
{
|
||||
newWidth += 0.02f;
|
||||
}
|
||||
|
||||
if (newWidth > widthToAssign)
|
||||
{
|
||||
widthToAssign = newWidth;
|
||||
}
|
||||
}
|
||||
menu.Width = widthToAssign;
|
||||
}
|
||||
}
|
||||
}
|
||||
268
SceneManager/Managers/PathManager.cs
Normal file
268
SceneManager/Managers/PathManager.cs
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
using Rage;
|
||||
using RAGENativeUI;
|
||||
using SceneManager.Menus;
|
||||
using SceneManager.Utils;
|
||||
using SceneManager.Waypoints;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace SceneManager.Managers
|
||||
{
|
||||
internal class PathManager
|
||||
{
|
||||
internal static Paths.Path[] Paths { get; } = new Paths.Path[10];
|
||||
internal static Dictionary<string, List<Paths.Path>> ImportedPaths { get; } = new Dictionary<string, List<Paths.Path>>();
|
||||
internal static List<string> LoadedFiles { get; } = new List<string>();
|
||||
|
||||
internal static Paths.Path InitializeNewPath()
|
||||
{
|
||||
PathCreationMenu.PathCreationState = State.Creating;
|
||||
|
||||
Paths.Path newPath = new Paths.Path();
|
||||
var firstEmptyIndex = Array.IndexOf(Paths, Paths.First(x => x == null));
|
||||
Game.LogTrivial($"First empty index: {firstEmptyIndex}");
|
||||
Paths[firstEmptyIndex] = newPath;
|
||||
newPath.Name = newPath.Number.ToString();
|
||||
|
||||
PathMainMenu.CreateNewPath.Text = $"Continue Creating Path {newPath.Name}";
|
||||
Game.LogTrivial($"Creating path {newPath.Name} at Paths[{firstEmptyIndex}]");
|
||||
Game.DisplayNotification($"~o~Scene Manager ~y~[Creating]\n~w~Path ~b~{newPath.Name} ~w~started.");
|
||||
|
||||
PathCreationMenu.RemoveLastWaypoint.Enabled = false;
|
||||
PathCreationMenu.EndPathCreation.Enabled = false;
|
||||
|
||||
return newPath;
|
||||
}
|
||||
|
||||
internal static void AddNewEditWaypoint(Paths.Path currentPath)
|
||||
{
|
||||
DrivingFlagType drivingFlag = EditWaypointMenu.DirectWaypointBehavior.Checked ? DrivingFlagType.Direct : DrivingFlagType.Normal;
|
||||
|
||||
if (EditWaypointMenu.CollectorWaypoint.Checked)
|
||||
{
|
||||
currentPath.Waypoints.Add(new Waypoint(currentPath, UserInput.PlayerMousePosition, ConvertDriveSpeedForWaypoint(EditWaypointMenu.ChangeWaypointSpeed.Value), drivingFlag, EditWaypointMenu.StopWaypointType.Checked, true, EditWaypointMenu.ChangeCollectorRadius.Value, EditWaypointMenu.ChangeSpeedZoneRadius.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPath.Waypoints.Add(new Waypoint(currentPath, UserInput.PlayerMousePosition, ConvertDriveSpeedForWaypoint(EditWaypointMenu.ChangeWaypointSpeed.Value), drivingFlag, EditWaypointMenu.StopWaypointType.Checked));
|
||||
}
|
||||
Game.LogTrivial($"New waypoint (#{currentPath.Waypoints.Last().Number}) added.");
|
||||
}
|
||||
|
||||
internal static void UpdateWaypoint()
|
||||
{
|
||||
var currentPath = Paths.FirstOrDefault(x => x.Name == PathMainMenu.EditPath.OptionText);
|
||||
var currentWaypoint = currentPath.Waypoints[EditWaypointMenu.EditWaypoint.Index];
|
||||
DrivingFlagType drivingFlag = EditWaypointMenu.DirectWaypointBehavior.Checked ? DrivingFlagType.Direct : DrivingFlagType.Normal;
|
||||
|
||||
if (currentPath.Waypoints.Count == 1)
|
||||
{
|
||||
currentWaypoint.UpdateWaypoint(currentWaypoint, UserInput.PlayerMousePosition, drivingFlag, EditWaypointMenu.StopWaypointType.Checked, ConvertDriveSpeedForWaypoint(EditWaypointMenu.ChangeWaypointSpeed.Value), true, EditWaypointMenu.ChangeCollectorRadius.Value, EditWaypointMenu.ChangeSpeedZoneRadius.Value, EditWaypointMenu.UpdateWaypointPosition.Checked);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentWaypoint.UpdateWaypoint(currentWaypoint, UserInput.PlayerMousePosition, drivingFlag, EditWaypointMenu.StopWaypointType.Checked, ConvertDriveSpeedForWaypoint(EditWaypointMenu.ChangeWaypointSpeed.Value), EditWaypointMenu.CollectorWaypoint.Checked, EditWaypointMenu.ChangeCollectorRadius.Value, EditWaypointMenu.ChangeSpeedZoneRadius.Value, EditWaypointMenu.UpdateWaypointPosition.Checked);
|
||||
}
|
||||
Game.LogTrivial($"Path {currentPath.Number} Waypoint {currentWaypoint.Number} updated [Driving style: {drivingFlag} | Stop waypoint: {EditWaypointMenu.StopWaypointType.Checked} | Speed: {EditWaypointMenu.ChangeWaypointSpeed.Value} | Collector: {currentWaypoint.IsCollector}]");
|
||||
|
||||
EditWaypointMenu.UpdateWaypointPosition.Checked = false;
|
||||
Game.DisplayNotification($"~o~Scene Manager ~g~[Success]~w~\nWaypoint {currentWaypoint.Number} updated.");
|
||||
}
|
||||
|
||||
private static float ConvertDriveSpeedForWaypoint(float speed)
|
||||
{
|
||||
float convertedSpeed = SettingsMenu.SpeedUnits.SelectedItem == SpeedUnits.MPH
|
||||
? MathHelper.ConvertMilesPerHourToMetersPerSecond(speed)
|
||||
: MathHelper.ConvertKilometersPerHourToMetersPerSecond(speed);
|
||||
return convertedSpeed;
|
||||
}
|
||||
|
||||
internal static void RemoveEditWaypoint(Paths.Path currentPath)
|
||||
{
|
||||
var currentWaypoint = currentPath.Waypoints[EditWaypointMenu.EditWaypoint.Index];
|
||||
if (currentPath.Waypoints.Count == 1)
|
||||
{
|
||||
Game.LogTrivial($"Deleting the last waypoint from the path.");
|
||||
currentPath.Delete();
|
||||
Paths[Array.IndexOf(Paths, currentPath)] = null;
|
||||
PathMainMenu.Build();
|
||||
|
||||
EditWaypointMenu.Menu.Visible = false;
|
||||
PathMainMenu.Menu.Visible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
currentWaypoint.Delete();
|
||||
currentPath.Waypoints.Remove(currentWaypoint);
|
||||
Game.LogTrivial($"[Path {currentPath.Number}] Waypoint {currentWaypoint.Number} ({currentWaypoint.DrivingFlagType}) removed");
|
||||
currentPath.Waypoints.ForEach(x => x.Number = currentPath.Waypoints.IndexOf(x) + 1);
|
||||
|
||||
DefaultWaypointToCollector(currentPath);
|
||||
}
|
||||
|
||||
private static void DefaultWaypointToCollector(Paths.Path currentPath)
|
||||
{
|
||||
if (currentPath.Waypoints.Count == 1)
|
||||
{
|
||||
DrivingFlagType drivingFlag = EditWaypointMenu.DirectWaypointBehavior.Checked ? DrivingFlagType.Direct : DrivingFlagType.Normal;
|
||||
Hints.Display($"~o~Scene Manager ~y~[Hint]~w~\nYour path's first waypoint ~b~must~w~ be a collector. If it's not, it will automatically be made into one.");
|
||||
Game.LogTrivial($"The path only has 1 waypoint left, this waypoint must be a collector.");
|
||||
currentPath.Waypoints[0].UpdateWaypoint(currentPath.Waypoints.First(), UserInput.PlayerMousePosition, drivingFlag, EditWaypointMenu.StopWaypointType.Checked, ConvertDriveSpeedForWaypoint(EditWaypointMenu.ChangeWaypointSpeed.Value), true, EditWaypointMenu.ChangeCollectorRadius.Value, EditWaypointMenu.ChangeSpeedZoneRadius.Value, EditWaypointMenu.UpdateWaypointPosition.Checked);
|
||||
EditWaypointMenu.CollectorWaypoint.Checked = true;
|
||||
EditWaypointMenu.ChangeCollectorRadius.Enabled = true;
|
||||
EditWaypointMenu.ChangeSpeedZoneRadius.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void TogglePathCreationMenuItems(Paths.Path currentPath)
|
||||
{
|
||||
if(currentPath.Waypoints.Count == 1)
|
||||
{
|
||||
PathCreationMenu.CollectorWaypoint.Enabled = true;
|
||||
PathCreationMenu.CollectorWaypoint.Checked = false;
|
||||
PathCreationMenu.RemoveLastWaypoint.Enabled = true;
|
||||
PathCreationMenu.EndPathCreation.Enabled = true;
|
||||
}
|
||||
|
||||
if (currentPath.Waypoints.Count < 1)
|
||||
{
|
||||
PathCreationMenu.CollectorWaypoint.Enabled = false;
|
||||
PathCreationMenu.CollectorWaypoint.Checked = true;
|
||||
PathCreationMenu.RemoveLastWaypoint.Enabled = false;
|
||||
PathCreationMenu.EndPathCreation.Enabled = false;
|
||||
PathCreationMenu.PathName.Enabled = false;
|
||||
PathCreationMenu.PathName.Description = "Add your first waypoint to enable this option.";
|
||||
currentPath.Delete();
|
||||
|
||||
PathCreationMenu.PathCreationState = State.Uninitialized;
|
||||
PathMainMenu.CreateNewPath.Text = "Create New Path";
|
||||
PathMainMenu.Build();
|
||||
GameFiber.Yield();
|
||||
PathCreationMenu.Menu.Visible = true;
|
||||
}
|
||||
|
||||
if (PathCreationMenu.CollectorWaypoint.Checked)
|
||||
{
|
||||
PathCreationMenu.CollectorRadius.Enabled = true;
|
||||
PathCreationMenu.SpeedZoneRadius.Enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
PathCreationMenu.CollectorRadius.Enabled = false;
|
||||
PathCreationMenu.SpeedZoneRadius.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ToggleBlips(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
Paths.SelectMany(x => x.Waypoints).ToList().ForEach(x => x.EnableBlip());
|
||||
}
|
||||
else
|
||||
{
|
||||
Paths.SelectMany(x => x.Waypoints).ToList().ForEach(x => x.DisableBlip());
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ToggleAllPaths(bool disable)
|
||||
{
|
||||
var nonNullPaths = Paths.Where(x => x != null).ToList();
|
||||
if (disable)
|
||||
{
|
||||
nonNullPaths.ForEach(x => x.Disable());
|
||||
Game.LogTrivial($"All paths disabled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
nonNullPaths.ForEach(x => x.Enable());
|
||||
Game.LogTrivial($"All paths enabled.");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DeleteAllPaths()
|
||||
{
|
||||
for(int i = 0; i < Paths.Length; i++)
|
||||
{
|
||||
if(Paths[i] != null)
|
||||
{
|
||||
Paths[i].Delete();
|
||||
}
|
||||
}
|
||||
Array.Clear(Paths, 0, Paths.Length);
|
||||
Game.LogTrivial($"All paths deleted");
|
||||
Game.DisplayNotification($"~o~Scene Manager\n~w~All paths deleted.");
|
||||
Menus.MainMenu.Build();
|
||||
}
|
||||
|
||||
internal static List<Paths.Path> ImportPathsFromFile(string file)
|
||||
{
|
||||
List<Paths.Path> importedPaths;
|
||||
var GAME_DIRECTORY = Directory.GetCurrentDirectory();
|
||||
var SAVED_PATHS_DIRECTORY = GAME_DIRECTORY + "\\plugins\\SceneManager\\Saved Paths\\";
|
||||
if (!Directory.Exists(SAVED_PATHS_DIRECTORY))
|
||||
{
|
||||
Game.LogTrivial($"Directory '\\plugins\\SceneManager\\Saved Paths' does not exist. No paths available to import.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var overrides = Serializer.DefineOverrides();
|
||||
try
|
||||
{
|
||||
importedPaths = Serializer.LoadItemFromXML<List<Paths.Path>>(SAVED_PATHS_DIRECTORY + Path.GetFileName(file) + ".xml", overrides);
|
||||
ImportedPaths.Add(file, importedPaths);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Game.DisplayNotification($"~y~Scene Manager ~w~[~r~ERROR~w~]: There was a problem importing file ~b~{file}~w~. This is likely due to an XML error. Double check any changes you've made to this file.");
|
||||
Game.LogTrivial($"Error: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return importedPaths;
|
||||
}
|
||||
|
||||
internal static void LoadImportedPaths(List<Paths.Path> paths, string file)
|
||||
{
|
||||
foreach (Paths.Path path in paths)
|
||||
{
|
||||
if (Paths.Any(x => x != null && x.Name == path.Name))
|
||||
{
|
||||
Game.DisplayHelp($"~y~Scene Manager ~w~[~o~WARNING~w~]:\nA path with the name ~b~{path.Name} ~w~already exists. Do you want to replace it? ~{Keys.Y.GetInstructionalId()}~ or ~{Keys.N.GetInstructionalId()}~");
|
||||
GameFiber.Sleep(100);
|
||||
GameFiber.SleepUntil(() => Game.IsKeyDown(Keys.Y) || Game.IsKeyDown(Keys.N), 8300);
|
||||
|
||||
if (Game.IsKeyDown(Keys.Y))
|
||||
{
|
||||
var pathToReplace = Paths.First(x => x.Name == path.Name);
|
||||
var pathToReplaceIndex = Array.IndexOf(Paths, pathToReplace);
|
||||
pathToReplace.Delete();
|
||||
Paths[pathToReplaceIndex] = path;
|
||||
path.Load();
|
||||
Rage.Native.NativeFunction.Natives.CLEAR_ALL_HELP_MESSAGES();
|
||||
LoadedFiles.Add(file);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.DisplayNotification($"~o~Scene Manager ~y~[Import]\n~w~Path ~b~{path.Name} ~w~was not imported.");
|
||||
Rage.Native.NativeFunction.Natives.CLEAR_ALL_HELP_MESSAGES();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var firstNullPathIndex = Array.IndexOf(Paths, Paths.First(x => x == null));
|
||||
Paths[firstNullPathIndex] = path;
|
||||
path.Load();
|
||||
LoadedFiles.Add(file);
|
||||
|
||||
var numberOfNonNullPaths = Paths.Where(x => x != null).Count();
|
||||
Game.LogTrivial($"{path.Name} added to paths collection. Paths count: {numberOfNonNullPaths}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,433 +4,193 @@ using System.Linq;
|
|||
using Rage;
|
||||
using RAGENativeUI;
|
||||
using RAGENativeUI.Elements;
|
||||
using SceneManager.Objects;
|
||||
using SceneManager.Barriers;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Utils;
|
||||
|
||||
namespace SceneManager
|
||||
namespace SceneManager.Menus
|
||||
{
|
||||
class BarrierMenu
|
||||
{
|
||||
private static List<TrafficLight> trafficLightList = new List<TrafficLight>() { TrafficLight.Green, TrafficLight.Red, TrafficLight.Yellow, TrafficLight.None };
|
||||
internal static UIMenu barrierMenu = new UIMenu("Scene Manager", "~o~Barrier Management");
|
||||
internal static List<Barrier> barriers = new List<Barrier>();
|
||||
private static UIMenuListScrollerItem<string> barrierList = new UIMenuListScrollerItem<string>("Spawn Barrier", "", Settings.barriers.Keys); // Settings.barrierKeys
|
||||
private static UIMenuNumericScrollerItem<int> rotateBarrier = new UIMenuNumericScrollerItem<int>("Rotate Barrier", "", 0, 350, 10);
|
||||
// ADD CHECKBOX FOR BARRIER TO STOP TRAFFIC? ADD 3D MARKER TO SHOW WHERE TRAFFIC WILL STOP. ONLY NEED ONE CONE TO DO IT PER LANE
|
||||
private static UIMenuCheckboxItem invincible = new UIMenuCheckboxItem("Indestructible", false);
|
||||
private static UIMenuCheckboxItem immobile = new UIMenuCheckboxItem("Immobile", false);
|
||||
private static UIMenuNumericScrollerItem<int> barrierTexture = new UIMenuNumericScrollerItem<int>("Change Texture", "", 0, 15, 1);
|
||||
private static UIMenuCheckboxItem setBarrierLights = new UIMenuCheckboxItem("Enable Barrier Lights", Settings.EnableBarrierLightsDefaultOn);
|
||||
private static UIMenuListScrollerItem<TrafficLight> setBarrierTrafficLight = new UIMenuListScrollerItem<TrafficLight>("Set Barrier Traffic Light", "", trafficLightList);
|
||||
private static UIMenuListScrollerItem<string> removeBarrierOptions = new UIMenuListScrollerItem<string>("Remove Barrier", "", new[] { "Last Barrier", "Nearest Barrier", "All Barriers" });
|
||||
private static UIMenuItem resetBarriers = new UIMenuItem("Reset Barriers", "Reset all spawned barriers to their original position and rotation");
|
||||
internal static Object shadowBarrier;
|
||||
private static List<TrafficLight> TrafficLightList { get; } = new List<TrafficLight>() { TrafficLight.Green, TrafficLight.Red, TrafficLight.Yellow, TrafficLight.None };
|
||||
internal static UIMenu Menu { get; } = new UIMenu("Scene Manager", "~o~Barrier Management");
|
||||
internal static UIMenuListScrollerItem<string> BarrierList { get; } = new UIMenuListScrollerItem<string>("Spawn Barrier", "", Settings.BarrierModels.Keys); // Settings.barrierKeys
|
||||
internal static UIMenuNumericScrollerItem<int> RotateBarrier { get; } = new UIMenuNumericScrollerItem<int>("Rotate Barrier", "", 0, 350, 10);
|
||||
internal static UIMenuCheckboxItem Invincible { get; } = new UIMenuCheckboxItem("Indestructible", false, "If checked, the barrier will not break, or will be harder to break. The barrier will still able to be moved around.");
|
||||
internal static UIMenuCheckboxItem Immobile { get; } = new UIMenuCheckboxItem("Immobile", false, "If checked, the barrier will be frozen in place.");
|
||||
internal static UIMenuNumericScrollerItem<int> BarrierTexture { get; } = new UIMenuNumericScrollerItem<int>("Change Texture", "If the barrier has multiple textures, changing this value will apply them to the barrier.", 0, 15, 1);
|
||||
internal static UIMenuCheckboxItem SetBarrierLights { get; } = new UIMenuCheckboxItem("Enable Barrier Lights", Settings.EnableBarrierLightsDefaultOn, "If the barrier has functional lights, checking this option will turn them on.");
|
||||
internal static UIMenuCheckboxItem BelongsToPath { get; } = new UIMenuCheckboxItem("Belongs to Path", false, "If checked, the barrier will be saved with the path when the path is exported.");
|
||||
internal static UIMenuListScrollerItem<string> AddToPath { get; private set; }
|
||||
internal static UIMenuListScrollerItem<string> AddUnassignedToPath { get; private set; }
|
||||
internal static UIMenuListScrollerItem<TrafficLight> SetBarrierTrafficLight { get; } = new UIMenuListScrollerItem<TrafficLight>("Set Barrier Traffic Light", "", TrafficLightList);
|
||||
internal static UIMenuListScrollerItem<string> RemoveBarrierOptions { get; } = new UIMenuListScrollerItem<string>("Remove Barrier", "", new[] { "Last Barrier", "Nearest Barrier", "All Barriers" });
|
||||
internal static UIMenuItem ResetBarriers { get; } = new UIMenuItem("Reset Barriers", "Reset all spawned barriers to their original position and rotation");
|
||||
|
||||
internal static void InstantiateMenu()
|
||||
internal static void Initialize()
|
||||
{
|
||||
barrierMenu.ParentMenu = MainMenu.mainMenu;
|
||||
MenuManager.menuPool.Add(barrierMenu);
|
||||
Menu.ParentMenu = MainMenu.Menu;
|
||||
MenuManager.MenuPool.Add(Menu);
|
||||
Menu.MaxItemsOnScreen = 11;
|
||||
|
||||
barrierMenu.OnItemSelect += BarrierMenu_OnItemSelected;
|
||||
barrierMenu.OnScrollerChange += BarrierMenu_OnScrollerChanged;
|
||||
barrierMenu.OnCheckboxChange += BarrierMenu_OnCheckboxChanged;
|
||||
barrierMenu.OnMenuOpen += BarrierMenu_OnMenuOpen;
|
||||
Menu.OnItemSelect += BarrierMenu_OnItemSelected;
|
||||
Menu.OnScrollerChange += BarrierMenu_OnScrollerChanged;
|
||||
Menu.OnCheckboxChange += BarrierMenu_OnCheckboxChanged;
|
||||
Menu.OnMenuOpen += BarrierMenu_OnMenuOpen;
|
||||
}
|
||||
|
||||
internal static void BuildBarrierMenu()
|
||||
internal static void Build()
|
||||
{
|
||||
barrierMenu.AddItem(barrierList);
|
||||
barrierList.ForeColor = Color.Gold;
|
||||
Menu.Clear();
|
||||
|
||||
barrierMenu.AddItem(rotateBarrier);
|
||||
Menu.AddItem(BarrierList);
|
||||
BarrierList.ForeColor = Color.Gold;
|
||||
|
||||
barrierMenu.AddItem(invincible);
|
||||
|
||||
barrierMenu.AddItem(immobile);
|
||||
Menu.AddItem(RotateBarrier);
|
||||
Menu.AddItem(Invincible);
|
||||
Menu.AddItem(Immobile);
|
||||
|
||||
if (Settings.EnableAdvancedBarricadeOptions)
|
||||
{
|
||||
barrierMenu.AddItem(barrierTexture);
|
||||
barrierTexture.Index = 0;
|
||||
Menu.AddItem(BarrierTexture);
|
||||
BarrierTexture.Index = 0;
|
||||
|
||||
barrierMenu.AddItem(setBarrierLights);
|
||||
Menu.AddItem(SetBarrierLights);
|
||||
|
||||
//barrierMenu.AddItem(setBarrierTrafficLight);
|
||||
//setBarrierTrafficLight.Index = 3;
|
||||
}
|
||||
Menu.AddItem(BelongsToPath);
|
||||
BelongsToPath.Enabled = PathManager.Paths.Count() > 0 ? true : false;
|
||||
BelongsToPath.Checked = false;
|
||||
|
||||
barrierMenu.AddItem(removeBarrierOptions);
|
||||
removeBarrierOptions.ForeColor = Color.Gold;
|
||||
removeBarrierOptions.Enabled = false;
|
||||
AddToPath = new UIMenuListScrollerItem<string>("Path", "The path the barrier will be saved with when the path is exported.", PathManager.Paths.Where(x => x != null).Select(x => x.Name));
|
||||
Menu.AddItem(AddToPath);
|
||||
AddToPath.Enabled = BelongsToPath.Checked;
|
||||
|
||||
barrierMenu.AddItem(resetBarriers);
|
||||
resetBarriers.ForeColor = Color.Gold;
|
||||
resetBarriers.Enabled = false;
|
||||
AddUnassignedToPath = new UIMenuListScrollerItem<string>("Add Unassigned Barriers to Path", "The path to add all unassigned barriers to.", PathManager.Paths.Where(x => x != null).Select(x => x.Name));
|
||||
Menu.AddItem(AddUnassignedToPath);
|
||||
AddUnassignedToPath.ForeColor = Color.Gold;
|
||||
AddUnassignedToPath.Enabled = BarrierManager.Barriers.Any(x => x.Path == null);
|
||||
|
||||
Menu.AddItem(RemoveBarrierOptions);
|
||||
RemoveBarrierOptions.ForeColor = Color.Gold;
|
||||
RemoveBarrierOptions.Enabled = BarrierManager.Barriers.Count() != 0;
|
||||
|
||||
Menu.AddItem(ResetBarriers);
|
||||
ResetBarriers.ForeColor = Color.Gold;
|
||||
ResetBarriers.Enabled = BarrierManager.Barriers.Count() != 0;
|
||||
}
|
||||
|
||||
internal static void CreateShadowBarrier()
|
||||
internal static void ScrollBarrierList()
|
||||
{
|
||||
if (shadowBarrier)
|
||||
if (BarrierManager.PlaceholderBarrier)
|
||||
{
|
||||
shadowBarrier.Delete();
|
||||
BarrierManager.PlaceholderBarrier.Delete();
|
||||
}
|
||||
BarrierTexture.Index = 0;
|
||||
|
||||
var barrierKey = Settings.barriers.Where(x => x.Key == barrierList.SelectedItem).FirstOrDefault().Key;
|
||||
var barrierValue = Settings.barriers[barrierKey].Name;
|
||||
shadowBarrier = new Object(barrierValue, MousePositionInWorld.GetPosition, rotateBarrier.Value);
|
||||
|
||||
// There arent enough available object handles in certain areas
|
||||
// The object gets spawned(sometimes) but doesn't get assigned a handle, so it returns a handle of 0 - Parks
|
||||
if (!shadowBarrier)
|
||||
if (BarrierList.SelectedItem == "Flare")
|
||||
{
|
||||
barrierMenu.Close();
|
||||
Game.DisplayNotification($"~o~Scene Manager ~r~[Error]\n~w~Something went wrong creating the shadow barrier. Please try again.");
|
||||
return;
|
||||
}
|
||||
//Rage.Native.NativeFunction.Natives.SET_ENTITY_TRAFFICLIGHT_OVERRIDE(shadowBarrier, setBarrierTrafficLight.Index);
|
||||
Rage.Native.NativeFunction.Natives.PLACE_OBJECT_ON_GROUND_PROPERLY(shadowBarrier);
|
||||
shadowBarrier.IsGravityDisabled = true;
|
||||
shadowBarrier.IsCollisionEnabled = false;
|
||||
shadowBarrier.Opacity = 0.7f;
|
||||
|
||||
if (Settings.EnableAdvancedBarricadeOptions)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.x971DA0055324D033(shadowBarrier, barrierTexture.Value);
|
||||
SetBarrierLights();
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoopToDisplayShadowBarrier()
|
||||
{
|
||||
while (barrierMenu.Visible)
|
||||
{
|
||||
if (barrierList.Selected || rotateBarrier.Selected || invincible.Selected || immobile.Selected || barrierTexture.Selected || setBarrierLights.Selected || setBarrierTrafficLight.Selected)
|
||||
{
|
||||
if (shadowBarrier)
|
||||
{
|
||||
UpdateShadowBarrierPosition();
|
||||
}
|
||||
else if(MousePositionInWorld.GetPositionForBarrier.DistanceTo2D(Game.LocalPlayer.Character.Position) <= Settings.BarrierPlacementDistance)
|
||||
{
|
||||
CreateShadowBarrier();
|
||||
}
|
||||
RotateBarrier.Enabled = false;
|
||||
Invincible.Enabled = false;
|
||||
Immobile.Enabled = false;
|
||||
BarrierTexture.Enabled = false;
|
||||
SetBarrierLights.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (shadowBarrier)
|
||||
{
|
||||
shadowBarrier.Delete();
|
||||
RotateBarrier.Enabled = true;
|
||||
Invincible.Enabled = true;
|
||||
Immobile.Enabled = true;
|
||||
BarrierTexture.Enabled = true;
|
||||
SetBarrierLights.Enabled = true;
|
||||
}
|
||||
}
|
||||
GameFiber.Yield();
|
||||
}
|
||||
|
||||
if (shadowBarrier)
|
||||
{
|
||||
shadowBarrier.Delete();
|
||||
}
|
||||
|
||||
void UpdateShadowBarrierPosition()
|
||||
{
|
||||
DisableBarrierMenuOptionsIfShadowConeTooFar();
|
||||
if (shadowBarrier)
|
||||
{
|
||||
// Delete and re-create for testing purposes.. Parks' stop light prop
|
||||
//shadowBarrier.Delete();
|
||||
//CreateShadowBarrier();
|
||||
shadowBarrier.Heading = rotateBarrier.Value;
|
||||
shadowBarrier.Position = MousePositionInWorld.GetPositionForBarrier;
|
||||
Rage.Native.NativeFunction.Natives.PLACE_OBJECT_ON_GROUND_PROPERLY(shadowBarrier);
|
||||
//Rage.Native.NativeFunction.Natives.SET_ENTITY_TRAFFICLIGHT_OVERRIDE(shadowBarrier, setBarrierTrafficLight.Index);
|
||||
}
|
||||
|
||||
void DisableBarrierMenuOptionsIfShadowConeTooFar()
|
||||
{
|
||||
if (!shadowBarrier && MousePositionInWorld.GetPositionForBarrier.DistanceTo2D(Game.LocalPlayer.Character.Position) <= Settings.BarrierPlacementDistance)
|
||||
{
|
||||
CreateShadowBarrier();
|
||||
|
||||
}
|
||||
else if (shadowBarrier && shadowBarrier.Position.DistanceTo2D(Game.LocalPlayer.Character.Position) > Settings.BarrierPlacementDistance)
|
||||
{
|
||||
barrierList.Enabled = false;
|
||||
rotateBarrier.Enabled = false;
|
||||
shadowBarrier.Delete();
|
||||
}
|
||||
else if (shadowBarrier && shadowBarrier.Position.DistanceTo2D(Game.LocalPlayer.Character.Position) <= Settings.BarrierPlacementDistance && barrierList.SelectedItem == "Flare")
|
||||
{
|
||||
barrierList.Enabled = true;
|
||||
rotateBarrier.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
barrierList.Enabled = true;
|
||||
rotateBarrier.Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void SpawnBarrier()
|
||||
{
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
if (barrierList.SelectedItem == "Flare")
|
||||
{
|
||||
SpawnFlare();
|
||||
}
|
||||
else
|
||||
{
|
||||
var barrier = new Object(shadowBarrier.Model, shadowBarrier.Position, rotateBarrier.Value);
|
||||
barrier.SetPositionWithSnap(shadowBarrier.Position);
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(barrier, true);
|
||||
if (invincible.Checked)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_DISABLE_FRAG_DAMAGE(barrier, true);
|
||||
if (barrier.Model.Name != "prop_barrier_wat_03a")
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_DISABLE_BREAKING(barrier, true);
|
||||
}
|
||||
}
|
||||
if (immobile.Checked)
|
||||
{
|
||||
barrier.IsPositionFrozen = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
barrier.IsPositionFrozen = false;
|
||||
}
|
||||
if (Settings.EnableAdvancedBarricadeOptions)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.x971DA0055324D033(barrier, barrierTexture.Value);
|
||||
if (setBarrierLights.Checked)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_LIGHTS(barrier, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_LIGHTS(barrier, true);
|
||||
}
|
||||
|
||||
//Rage.Native.NativeFunction.Natives.SET_ENTITY_TRAFFICLIGHT_OVERRIDE(barrier, setBarrierTrafficLight.Index);
|
||||
barrier.IsPositionFrozen = true;
|
||||
GameFiber.Sleep(50);
|
||||
if (barrier && !immobile.Checked)
|
||||
{
|
||||
barrier.IsPositionFrozen = false;
|
||||
}
|
||||
}
|
||||
barriers.Add(new Barrier(barrier, barrier.Position, barrier.Heading, invincible.Checked, immobile.Checked));
|
||||
//if (barriers.First().Object == barrier)
|
||||
//{
|
||||
// barriers.First().GoAround();
|
||||
//}
|
||||
removeBarrierOptions.Enabled = true;
|
||||
resetBarriers.Enabled = true;
|
||||
}
|
||||
}, "Scene Manager Spawn Barrier Fiber");
|
||||
|
||||
|
||||
void SpawnFlare()
|
||||
{
|
||||
var flare = new Weapon("weapon_flare", shadowBarrier.Position, 1);
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(flare, true);
|
||||
GameFiber.Sleep(1);
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
while (flare && flare.HeightAboveGround > 0.05f)
|
||||
{
|
||||
GameFiber.Yield();
|
||||
}
|
||||
GameFiber.Sleep(1000);
|
||||
if (flare)
|
||||
{
|
||||
flare.IsPositionFrozen = true;
|
||||
}
|
||||
});
|
||||
|
||||
barriers.Add(new Barrier(flare, flare.Position, flare.Heading, invincible.Checked, immobile.Checked));
|
||||
removeBarrierOptions.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void RotateBarrier()
|
||||
{
|
||||
shadowBarrier.Heading = rotateBarrier.Value;
|
||||
shadowBarrier.Position = MousePositionInWorld.GetPositionForBarrier;
|
||||
Rage.Native.NativeFunction.Natives.PLACE_OBJECT_ON_GROUND_PROPERLY(shadowBarrier);
|
||||
}
|
||||
|
||||
private static void RemoveBarrier()
|
||||
{
|
||||
switch (removeBarrierOptions.Index)
|
||||
{
|
||||
case 0:
|
||||
barriers[barriers.Count - 1].Object.Delete();
|
||||
barriers.RemoveAt(barriers.Count - 1);
|
||||
break;
|
||||
case 1:
|
||||
var nearestBarrier = barriers.OrderBy(b => b.Object.DistanceTo2D(Game.LocalPlayer.Character)).FirstOrDefault();
|
||||
if (nearestBarrier != null)
|
||||
{
|
||||
nearestBarrier.Object.Delete();
|
||||
barriers.Remove(nearestBarrier);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
foreach (Barrier b in barriers.Where(b => b.Object))
|
||||
{
|
||||
b.Object.Delete();
|
||||
}
|
||||
if (barriers.Count > 0)
|
||||
{
|
||||
barriers.Clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
removeBarrierOptions.Enabled = barriers.Count == 0 ? false : true;
|
||||
resetBarriers.Enabled = barriers.Count == 0 ? false : true;
|
||||
}
|
||||
|
||||
private static void ResetBarriers()
|
||||
{
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
var currentBarriers = barriers.Where(b => b.Model.Name != "0xa2c44e80").ToList(); // 0xa2c44e80 is the flare weapon hash
|
||||
foreach (Barrier barrier in currentBarriers)
|
||||
{
|
||||
var newBarrier = new Object(barrier.Model, barrier.Position, barrier.Rotation);
|
||||
newBarrier.SetPositionWithSnap(barrier.Position);
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(newBarrier, true);
|
||||
newBarrier.IsPositionFrozen = barrier.Immobile;
|
||||
if (barrier.Invincible)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_DISABLE_FRAG_DAMAGE(newBarrier, true);
|
||||
if (newBarrier.Model.Name != "prop_barrier_wat_03a")
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_DISABLE_BREAKING(newBarrier, true);
|
||||
}
|
||||
}
|
||||
//Rage.Native.NativeFunction.Natives.SET_ENTITY_TRAFFICLIGHT_OVERRIDE(newBarrier, setBarrierTrafficLight.Index);
|
||||
newBarrier.IsPositionFrozen = true;
|
||||
GameFiber.Sleep(50);
|
||||
if (newBarrier && !barrier.Immobile)
|
||||
{
|
||||
newBarrier.IsPositionFrozen = false;
|
||||
}
|
||||
barriers.Add(new Barrier(newBarrier, newBarrier.Position, newBarrier.Heading, barrier.Invincible, barrier.Immobile));
|
||||
|
||||
if (barrier.Object)
|
||||
{
|
||||
barrier.Object.Delete();
|
||||
}
|
||||
barriers.Remove(barrier);
|
||||
}
|
||||
currentBarriers.Clear();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private static void SetBarrierLights()
|
||||
{
|
||||
if (setBarrierLights.Checked)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_LIGHTS(shadowBarrier, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_LIGHTS(shadowBarrier, true);
|
||||
}
|
||||
|
||||
//Rage.Native.NativeFunction.Natives.SET_ENTITY_TRAFFICLIGHT_OVERRIDE(shadowBarrier, setBarrierTrafficLight.Index);
|
||||
}
|
||||
|
||||
private static void BarrierMenu_OnCheckboxChanged(UIMenu sender, UIMenuCheckboxItem checkbox, bool @checked)
|
||||
{
|
||||
if(checkbox == setBarrierLights)
|
||||
if(checkbox == SetBarrierLights)
|
||||
{
|
||||
SetBarrierLights();
|
||||
//SetBarrierLights();
|
||||
BarrierManager.SetBarrierLights();
|
||||
}
|
||||
|
||||
if(checkbox == BelongsToPath)
|
||||
{
|
||||
AddToPath.Enabled = BelongsToPath.Checked;
|
||||
}
|
||||
}
|
||||
|
||||
private static void BarrierMenu_OnScrollerChanged(UIMenu sender, UIMenuScrollerItem scrollerItem, int oldIndex, int newIndex)
|
||||
{
|
||||
if (scrollerItem == barrierList)
|
||||
if (scrollerItem == BarrierList)
|
||||
{
|
||||
if (shadowBarrier)
|
||||
{
|
||||
shadowBarrier.Delete();
|
||||
}
|
||||
barrierTexture.Index = 0;
|
||||
|
||||
if(barrierList.SelectedItem == "Flare")
|
||||
{
|
||||
rotateBarrier.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
rotateBarrier.Enabled = true;
|
||||
ScrollBarrierList();
|
||||
}
|
||||
|
||||
barrierMenu.Width = SetMenuWidth();
|
||||
if (scrollerItem == BarrierTexture)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.x971DA0055324D033(BarrierManager.PlaceholderBarrier, BarrierTexture.Value);
|
||||
}
|
||||
|
||||
if (scrollerItem == barrierTexture)
|
||||
if (scrollerItem == SetBarrierTrafficLight)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.x971DA0055324D033(shadowBarrier, barrierTexture.Value);
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_TRAFFICLIGHT_OVERRIDE(BarrierManager.PlaceholderBarrier, SetBarrierTrafficLight.Index);
|
||||
}
|
||||
|
||||
if (scrollerItem == setBarrierTrafficLight)
|
||||
if (scrollerItem == RotateBarrier)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.SET_ENTITY_TRAFFICLIGHT_OVERRIDE(shadowBarrier, setBarrierTrafficLight.Index);
|
||||
BarrierManager.RotateBarrier();
|
||||
}
|
||||
|
||||
if (scrollerItem == rotateBarrier)
|
||||
{
|
||||
RotateBarrier();
|
||||
}
|
||||
MenuManager.SetMenuWidth(Menu);
|
||||
}
|
||||
|
||||
private static void BarrierMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||
{
|
||||
if (selectedItem == barrierList)
|
||||
if (selectedItem == BarrierList)
|
||||
{
|
||||
SpawnBarrier();
|
||||
BarrierManager.SpawnBarrier();
|
||||
}
|
||||
|
||||
if (selectedItem == removeBarrierOptions)
|
||||
if (selectedItem == AddUnassignedToPath)
|
||||
{
|
||||
RemoveBarrier();
|
||||
BarrierManager.AddBarrierToPath();
|
||||
}
|
||||
|
||||
if (selectedItem == resetBarriers)
|
||||
if (selectedItem == RemoveBarrierOptions)
|
||||
{
|
||||
ResetBarriers();
|
||||
BarrierManager.RemoveBarrier(RemoveBarrierOptions.Index);
|
||||
}
|
||||
|
||||
if (selectedItem == ResetBarriers)
|
||||
{
|
||||
BarrierManager.ResetBarriers();
|
||||
}
|
||||
}
|
||||
|
||||
private static void BarrierMenu_OnMenuOpen(UIMenu menu)
|
||||
{
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { barrierList, barrierTexture, setBarrierTrafficLight, rotateBarrier, removeBarrierOptions };
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { BarrierList, BarrierTexture, SetBarrierTrafficLight, RotateBarrier, AddToPath, AddUnassignedToPath, RemoveBarrierOptions };
|
||||
|
||||
Hints.Display($"~o~Scene Manager ~y~[Hint]\n~w~The shadow barrier will disappear if you aim too far away.");
|
||||
CreateShadowBarrier();
|
||||
//CreatePlaceholderBarrier();
|
||||
BarrierManager.CreatePlaceholderBarrier();
|
||||
|
||||
GameFiber ShadowConeLoopFiber = new GameFiber(() => LoopToDisplayShadowBarrier());
|
||||
ShadowConeLoopFiber.Start();
|
||||
//GameFiber PlaceholderBarrierRenderFiber = new GameFiber(() => LoopToDisplayShadowBarrier());
|
||||
GameFiber PlaceholderBarrierRenderFiber = new GameFiber(() => BarrierManager.LoopToRenderPlaceholderBarrier(), "Render Placeholder Barrier Loop Fiber");
|
||||
PlaceholderBarrierRenderFiber.Start();
|
||||
|
||||
RNUIMouseInputHandler.Initialize(menu, scrollerItems);
|
||||
GameFiber.StartNew(() => UserInput.InitializeMenuMouseControl(menu, scrollerItems), "RNUI Mouse Input Fiber");
|
||||
}
|
||||
|
||||
internal static float SetMenuWidth()
|
||||
private static float SetMenuWidth()
|
||||
{
|
||||
float defaultWidth = UIMenu.DefaultWidth;
|
||||
|
||||
barrierList.TextStyle.Apply();
|
||||
BarrierList.TextStyle.Apply();
|
||||
Rage.Native.NativeFunction.Natives.x54CE8AC98E120CAB("STRING"); // _BEGIN_TEXT_COMMAND_GET_WIDTH
|
||||
Rage.Native.NativeFunction.Natives.ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(barrierList.SelectedItem);
|
||||
Rage.Native.NativeFunction.Natives.ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(BarrierList.SelectedItem);
|
||||
float textWidth = Rage.Native.NativeFunction.Natives.x85F061DA64ED2F67<float>(true); // _END_TEXT_COMMAND_GET_WIDTH
|
||||
float padding = 0.00390625f * 2; // typical padding used in RNUI
|
||||
|
||||
|
|
@ -444,5 +204,17 @@ namespace SceneManager
|
|||
return selectedItemWidth * 1.6f;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Cleanup()
|
||||
{
|
||||
foreach (Barrier barrier in BarrierManager.Barriers)
|
||||
{
|
||||
barrier.Delete();
|
||||
}
|
||||
if (BarrierManager.PlaceholderBarrier)
|
||||
{
|
||||
BarrierManager.PlaceholderBarrier.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
76
SceneManager/Menus/DriverMenu.cs
Normal file
76
SceneManager/Menus/DriverMenu.cs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
using Rage;
|
||||
using RAGENativeUI;
|
||||
using RAGENativeUI.Elements;
|
||||
using SceneManager.CollectedPeds;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Utils;
|
||||
using SceneManager.Waypoints;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace SceneManager.Menus
|
||||
{
|
||||
internal class DriverMenu
|
||||
{
|
||||
internal static UIMenu Menu = new UIMenu("Scene Manager", "~o~Driver Menu");
|
||||
private static string[] DismissOptions { get; } = new string[] { "From path", "From waypoint", "From world" };
|
||||
internal static UIMenuListScrollerItem<string> DirectOptions { get; } = new UIMenuListScrollerItem<string>("Direct driver to path's", "", new[] { "First waypoint", "Nearest waypoint" });
|
||||
internal static UIMenuListScrollerItem<string> DirectDriver { get; private set; }
|
||||
internal static UIMenuListScrollerItem<string> DismissDriver { get; } = new UIMenuListScrollerItem<string>("Dismiss nearest driver", $"~b~From path: ~w~Driver will be released from the path\n~b~From waypoint: ~w~Driver will skip their current waypoint task\n~b~From world: ~w~Driver will be removed from the world.", DismissOptions);
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
Menu.ParentMenu = PathMainMenu.Menu;
|
||||
MenuManager.MenuPool.Add(Menu);
|
||||
|
||||
Menu.OnItemSelect += DriverMenu_OnItemSelected;
|
||||
Menu.OnMenuOpen += DriverMenu_OnMenuOpen;
|
||||
}
|
||||
|
||||
internal static void Build()
|
||||
{
|
||||
Menu.Clear();
|
||||
|
||||
Menu.AddItem(DirectOptions);
|
||||
DirectOptions.Enabled = true;
|
||||
Menu.AddItem(DirectDriver = new UIMenuListScrollerItem<string>("Direct nearest driver to path", "", PathManager.Paths.Where(x => x != null).Select(x => x.Name))); // This must instantiate here because the Paths change
|
||||
DirectDriver.ForeColor = Color.Gold;
|
||||
DirectDriver.Enabled = true;
|
||||
Menu.AddItem(DismissDriver);
|
||||
DismissDriver.ForeColor = Color.Gold;
|
||||
DismissDriver.Enabled = true;
|
||||
|
||||
if (PathManager.Paths.All(x => x == null))
|
||||
{
|
||||
DirectOptions.Enabled = false;
|
||||
DirectDriver.Enabled = false;
|
||||
DismissDriver.Enabled = false;
|
||||
}
|
||||
|
||||
Menu.RefreshIndex();
|
||||
}
|
||||
|
||||
private static void DriverMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||
{
|
||||
if (selectedItem == DirectDriver)
|
||||
{
|
||||
if (Utils.DirectDriver.ValidateOptions(DirectOptions, PathManager.Paths[DirectDriver.Index], out Vehicle nearbyVehicle, out Waypoint targetWaypoint))
|
||||
{
|
||||
Utils.DirectDriver.Direct(nearbyVehicle, PathManager.Paths[DirectDriver.Index], targetWaypoint);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedItem == DismissDriver)
|
||||
{
|
||||
Utils.DismissDriver.Dismiss(DismissDriver.Index);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DriverMenu_OnMenuOpen(UIMenu menu)
|
||||
{
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { DirectOptions, DirectDriver, DismissDriver };
|
||||
GameFiber.StartNew(() => UserInput.InitializeMenuMouseControl(menu, scrollerItems), "RNUI Mouse Input Fiber");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,116 +1,116 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using Rage;
|
||||
using RAGENativeUI;
|
||||
using RAGENativeUI.Elements;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Menus;
|
||||
using SceneManager.Paths;
|
||||
using SceneManager.Utils;
|
||||
|
||||
namespace SceneManager
|
||||
{
|
||||
class EditPathMenu
|
||||
internal class EditPathMenu
|
||||
{
|
||||
internal static UIMenu editPathMenu = new UIMenu("Scene Manager", "~o~Edit Path");
|
||||
private static UIMenuItem editPathWaypoints, deletePath, exportPath;
|
||||
internal static UIMenuCheckboxItem disablePath;
|
||||
internal static UIMenu Menu { get; } = new UIMenu("Scene Manager", "~o~Edit Path");
|
||||
private static UIMenuCheckboxItem DisablePath { get; } = new UIMenuCheckboxItem("Disable Path Collection", false);
|
||||
private static UIMenuItem EditWaypoints { get; } = new UIMenuItem("Edit Waypoints");
|
||||
private static UIMenuItem DeletePath { get; } = new UIMenuItem("Delete Path");
|
||||
private static UIMenuItem ChangePathName { get; } = new UIMenuItem("Change Path Name");
|
||||
internal static Path CurrentPath { get; set; }
|
||||
|
||||
internal static void InstantiateMenu()
|
||||
internal static void Initialize()
|
||||
{
|
||||
editPathMenu.ParentMenu = PathMainMenu.pathMainMenu;
|
||||
MenuManager.menuPool.Add(editPathMenu);
|
||||
editPathMenu.OnItemSelect += EditPath_OnItemSelected;
|
||||
editPathMenu.OnCheckboxChange += EditPath_OnCheckboxChange;
|
||||
editPathMenu.OnMenuOpen += EditPath_OnMenuOpen;
|
||||
Menu.ParentMenu = PathMainMenu.Menu;
|
||||
MenuManager.MenuPool.Add(Menu);
|
||||
|
||||
Menu.OnItemSelect += EditPath_OnItemSelected;
|
||||
Menu.OnCheckboxChange += EditPath_OnCheckboxChange;
|
||||
Menu.OnMenuOpen += EditPath_OnMenuOpen;
|
||||
}
|
||||
|
||||
internal static void BuildEditPathMenu()
|
||||
internal static void Build()
|
||||
{
|
||||
editPathMenu.AddItem(disablePath = new UIMenuCheckboxItem("Disable Path", false));
|
||||
editPathMenu.AddItem(editPathWaypoints = new UIMenuItem("Edit Waypoints"));
|
||||
editPathWaypoints.ForeColor = Color.Gold;
|
||||
editPathMenu.AddItem(deletePath = new UIMenuItem("Delete Path"));
|
||||
deletePath.ForeColor = Color.Gold;
|
||||
//editPathMenu.AddItem(exportPath = new UIMenuItem("Export Path"));
|
||||
//exportPath.ForeColor = Color.Gold;
|
||||
editPathMenu.RefreshIndex();
|
||||
Menu.Clear();
|
||||
|
||||
Menu.AddItem(DisablePath);
|
||||
Menu.AddItem(EditWaypoints);
|
||||
EditWaypoints.ForeColor = Color.Gold;
|
||||
Menu.AddItem(ChangePathName);
|
||||
ChangePathName.ForeColor = Color.Gold;
|
||||
Menu.AddItem(DeletePath);
|
||||
DeletePath.ForeColor = Color.Gold;
|
||||
|
||||
Menu.RefreshIndex();
|
||||
}
|
||||
|
||||
private static void EditPathWaypoints()
|
||||
private static void EditPath_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||
{
|
||||
if (!SettingsMenu.threeDWaypoints.Checked)
|
||||
if (selectedItem == EditWaypoints)
|
||||
{
|
||||
if (!SettingsMenu.ThreeDWaypoints.Checked)
|
||||
{
|
||||
Hints.Display($"~o~Scene Manager ~y~[Hint]\n~w~You have 3D waypoints disabled in your settings. It's recommended to enable 3D waypoints while working with waypoints.");
|
||||
}
|
||||
EditWaypointMenu.BuildEditWaypointMenu();
|
||||
}
|
||||
|
||||
private static void DeletePath()
|
||||
if (selectedItem == DeletePath)
|
||||
{
|
||||
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
|
||||
PathMainMenu.DeletePath(currentPath, Delete.Single);
|
||||
var currentPath = PathManager.Paths[PathMainMenu.EditPath.Index];
|
||||
currentPath.Delete();
|
||||
PathMainMenu.Build();
|
||||
PathMainMenu.Menu.Visible = true;
|
||||
BarrierMenu.Build();
|
||||
}
|
||||
|
||||
private static void DisablePath()
|
||||
if(selectedItem == ChangePathName)
|
||||
{
|
||||
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
|
||||
if (disablePath.Checked)
|
||||
{
|
||||
currentPath.DisablePath();
|
||||
Game.LogTrivial($"Path {currentPath.Number} disabled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPath.EnablePath();
|
||||
Game.LogTrivial($"Path {currentPath.Number} enabled.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExportPath()
|
||||
{
|
||||
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
|
||||
// Reference PNWParks's UserInput class from LiveLights
|
||||
var filename = PNWUserInput.GetUserInput("Type the name you would like to save your file as", "Enter a filename", 100) + ".xml";
|
||||
|
||||
// If filename != null or empty, check if export directory exists (GTA V/Plugins/SceneManager/Saved Paths)
|
||||
if(string.IsNullOrWhiteSpace(filename))
|
||||
{
|
||||
Game.DisplayHelp($"Invalid filename given. Filename cannot be null, empty, or consist of just white spaces.");
|
||||
Game.LogTrivial($"Invalid filename given. Filename cannot be null, empty, or consist of just white spaces.");
|
||||
return;
|
||||
}
|
||||
Game.LogTrivial($"Filename: {filename}");
|
||||
currentPath.Save(filename);
|
||||
}
|
||||
|
||||
private static void EditPath_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||
{
|
||||
if (selectedItem == editPathWaypoints)
|
||||
{
|
||||
EditPathWaypoints();
|
||||
}
|
||||
|
||||
if (selectedItem == deletePath)
|
||||
{
|
||||
DeletePath();
|
||||
}
|
||||
|
||||
if(selectedItem == exportPath)
|
||||
{
|
||||
ExportPath();
|
||||
var currentPath = PathManager.Paths[PathMainMenu.EditPath.Index];
|
||||
currentPath.ChangeName();
|
||||
MenuManager.BuildMenus();
|
||||
Menu.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EditPath_OnCheckboxChange(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked)
|
||||
{
|
||||
if (checkboxItem == disablePath)
|
||||
if (checkboxItem == DisablePath)
|
||||
{
|
||||
DisablePath();
|
||||
//var currentPath = PathManager.Paths[PathMainMenu.EditPath.Index];
|
||||
var currentPath = PathManager.Paths.FirstOrDefault(x => x.Name == PathMainMenu.EditPath.OptionText);
|
||||
if(currentPath == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (DisablePath.Checked)
|
||||
{
|
||||
currentPath.Disable();
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPath.Enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void EditPath_OnMenuOpen(UIMenu menu)
|
||||
{
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { };
|
||||
RNUIMouseInputHandler.Initialize(menu, scrollerItems);
|
||||
GameFiber.StartNew(() => UserInput.InitializeMenuMouseControl(menu, scrollerItems), "RNUI Mouse Input Fiber");
|
||||
if (CurrentPath == null)
|
||||
{
|
||||
Menu.SubtitleText = $"~o~Currently editing: ~r~[ERROR GETTING CURRENT PATH]";
|
||||
ChangePathName.Description = $"Change the path name from ~r~[ERROR] ~w~to something else.";
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu.SubtitleText = $"~o~Currently editing: ~b~{CurrentPath.Name}";
|
||||
ChangePathName.Description = $"Change the path name from ~b~{CurrentPath.Name} ~w~to something else.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,311 +4,201 @@ using System.Linq;
|
|||
using Rage;
|
||||
using RAGENativeUI;
|
||||
using RAGENativeUI.Elements;
|
||||
using SceneManager.Objects;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Utils;
|
||||
using SceneManager.Waypoints;
|
||||
|
||||
namespace SceneManager
|
||||
namespace SceneManager.Menus
|
||||
{
|
||||
class EditWaypointMenu
|
||||
{
|
||||
internal static UIMenu editWaypointMenu = new UIMenu("Scene Manager", "~o~Edit Waypoint");
|
||||
internal static UIMenuItem updateWaypoint = new UIMenuItem("Update Waypoint");
|
||||
internal static UIMenuItem removeWaypoint = new UIMenuItem("Remove Waypoint");
|
||||
internal static UIMenuItem addAsNewWaypoint = new UIMenuItem("Add as New Waypoint", "Adds a new waypoint to the end of the path with these settings");
|
||||
internal static UIMenuNumericScrollerItem<int> editWaypoint;
|
||||
private static UIMenuNumericScrollerItem<int> changeWaypointSpeed;
|
||||
internal static UIMenuCheckboxItem stopWaypointType;
|
||||
internal static UIMenuCheckboxItem directWaypointBehavior = new UIMenuCheckboxItem("Drive directly to waypoint?", false, "If checked, vehicles will ignore traffic rules and drive directly to this waypoint.");
|
||||
internal static UIMenuCheckboxItem collectorWaypoint;
|
||||
internal static UIMenuNumericScrollerItem<int> changeCollectorRadius = new UIMenuNumericScrollerItem<int>("Collection Radius", "The distance from this waypoint (in meters) vehicles will be collected", 1, 50, 1);
|
||||
internal static UIMenuNumericScrollerItem<int> changeSpeedZoneRadius = new UIMenuNumericScrollerItem<int>("Speed Zone Radius", "The distance from this collector waypoint (in meters) non-collected vehicles will drive at this waypoint's speed", 5, 200, 5);
|
||||
internal static UIMenuCheckboxItem updateWaypointPosition = new UIMenuCheckboxItem("Update Waypoint Position", false, "Updates the waypoint's position to the player's chosen position. You should turn this on if you're planning on adding this waypoint as a new waypoint.");
|
||||
internal static UIMenu Menu = new UIMenu("Scene Manager", "~o~Edit Waypoint");
|
||||
internal static UIMenuItem UpdateWaypoint { get; } = new UIMenuItem("Update Waypoint");
|
||||
internal static UIMenuItem RemoveWaypoint { get; } = new UIMenuItem("Remove Waypoint");
|
||||
internal static UIMenuItem AddNewWaypoint { get; } = new UIMenuItem("Add as New Waypoint", "Adds a new waypoint to the end of the path with these settings");
|
||||
internal static UIMenuNumericScrollerItem<int> EditWaypoint { get; set; }
|
||||
internal static UIMenuNumericScrollerItem<int> ChangeWaypointSpeed { get; private set; }
|
||||
internal static UIMenuCheckboxItem StopWaypointType { get; private set; }
|
||||
internal static UIMenuCheckboxItem DirectWaypointBehavior { get; } = new UIMenuCheckboxItem("Drive directly to waypoint?", false, "If checked, vehicles will ignore traffic rules and drive directly to this waypoint.");
|
||||
internal static UIMenuCheckboxItem CollectorWaypoint { get; private set; }
|
||||
internal static UIMenuNumericScrollerItem<int> ChangeCollectorRadius { get; } = new UIMenuNumericScrollerItem<int>("Collection Radius", "The distance from this waypoint (in meters) vehicles will be collected", 1, 50, 1);
|
||||
internal static UIMenuNumericScrollerItem<int> ChangeSpeedZoneRadius { get; } = new UIMenuNumericScrollerItem<int>("Speed Zone Radius", "The distance from this collector waypoint (in meters) non-collected vehicles will drive at this waypoint's speed", 5, 200, 5);
|
||||
internal static UIMenuCheckboxItem UpdateWaypointPosition { get; } = new UIMenuCheckboxItem("Update Waypoint Position", false, "Updates the waypoint's position to the player's chosen position. You should turn this on if you're planning on adding this waypoint as a new waypoint.");
|
||||
|
||||
internal static void InstantiateMenu()
|
||||
internal static void Initialize()
|
||||
{
|
||||
editWaypointMenu.ParentMenu = EditPathMenu.editPathMenu;
|
||||
MenuManager.menuPool.Add(editWaypointMenu);
|
||||
Menu.ParentMenu = EditPathMenu.Menu;
|
||||
MenuManager.MenuPool.Add(Menu);
|
||||
Menu.MaxItemsOnScreen = 11;
|
||||
|
||||
editWaypointMenu.OnScrollerChange += EditWaypoint_OnScrollerChanged;
|
||||
editWaypointMenu.OnCheckboxChange += EditWaypoint_OnCheckboxChanged;
|
||||
editWaypointMenu.OnItemSelect += EditWaypoint_OnItemSelected;
|
||||
editWaypointMenu.OnMenuOpen += EditWaypoint_OnMenuOpen;
|
||||
Menu.OnScrollerChange += EditWaypoint_OnScrollerChanged;
|
||||
Menu.OnCheckboxChange += EditWaypoint_OnCheckboxChanged;
|
||||
Menu.OnItemSelect += EditWaypoint_OnItemSelected;
|
||||
Menu.OnMenuOpen += EditWaypoint_OnMenuOpen;
|
||||
}
|
||||
|
||||
internal static void BuildEditWaypointMenu()
|
||||
{
|
||||
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Value-1];
|
||||
Menu.MenuItems.Clear();
|
||||
var currentPath = PathManager.Paths.FirstOrDefault(x => x.Name == PathMainMenu.EditPath.OptionText);
|
||||
|
||||
editWaypoint = new UIMenuNumericScrollerItem<int>("Edit Waypoint", "", currentPath.Waypoints.First().Number, currentPath.Waypoints.Last().Number, 1);
|
||||
editWaypointMenu.Clear();
|
||||
editWaypointMenu.AddItem(editWaypoint);
|
||||
editWaypoint.Index = 0;
|
||||
Menu.AddItem(EditWaypoint = new UIMenuNumericScrollerItem<int>("Edit Waypoint", "", currentPath.Waypoints.First().Number, currentPath.Waypoints.Last().Number, 1));
|
||||
EditWaypoint.Index = 0;
|
||||
|
||||
var currentWaypoint = currentPath.Waypoints.Where(wp => wp.Number == editWaypoint.Value).FirstOrDefault();
|
||||
if(currentWaypoint != null)
|
||||
var currentWaypoint = currentPath.Waypoints.Where(wp => wp.Number == EditWaypoint.Value).FirstOrDefault();
|
||||
if(currentWaypoint == null)
|
||||
{
|
||||
editWaypointMenu.AddItem(collectorWaypoint = new UIMenuCheckboxItem("Collector", currentWaypoint.IsCollector, "If this waypoint will collect vehicles to follow the path"));
|
||||
Game.LogTrivial($"Current waypoint is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
editWaypointMenu.AddItem(changeCollectorRadius);
|
||||
changeCollectorRadius.Value = currentWaypoint.CollectorRadius != 0
|
||||
Menu.AddItem(CollectorWaypoint = new UIMenuCheckboxItem("Collector", currentWaypoint.IsCollector, "If this waypoint will collect vehicles to follow the path"));
|
||||
|
||||
Menu.AddItem(ChangeCollectorRadius);
|
||||
ChangeCollectorRadius.Value = currentWaypoint.CollectorRadius != 0
|
||||
? (int)currentWaypoint.CollectorRadius
|
||||
: changeCollectorRadius.Minimum;
|
||||
: ChangeCollectorRadius.Minimum;
|
||||
|
||||
editWaypointMenu.AddItem(changeSpeedZoneRadius);
|
||||
changeSpeedZoneRadius.Value = currentWaypoint.CollectorRadius != 0
|
||||
Menu.AddItem(ChangeSpeedZoneRadius);
|
||||
ChangeSpeedZoneRadius.Value = currentWaypoint.CollectorRadius != 0
|
||||
? (int)currentWaypoint.SpeedZoneRadius
|
||||
: changeSpeedZoneRadius.Minimum;
|
||||
: ChangeSpeedZoneRadius.Minimum;
|
||||
|
||||
changeCollectorRadius.Enabled = collectorWaypoint.Checked ? true : false;
|
||||
changeSpeedZoneRadius.Enabled = collectorWaypoint.Checked ? true : false;
|
||||
ChangeCollectorRadius.Enabled = CollectorWaypoint.Checked ? true : false;
|
||||
ChangeSpeedZoneRadius.Enabled = CollectorWaypoint.Checked ? true : false;
|
||||
|
||||
editWaypointMenu.AddItem(stopWaypointType = new UIMenuCheckboxItem("Is this a Stop waypoint?", currentWaypoint.IsStopWaypoint, "If checked, vehicles will drive to this waypoint, then stop."));
|
||||
editWaypointMenu.AddItem(directWaypointBehavior);
|
||||
Menu.AddItem(StopWaypointType = new UIMenuCheckboxItem("Is this a Stop waypoint?", currentWaypoint.IsStopWaypoint, "If checked, vehicles will drive to this waypoint, then stop."));
|
||||
Menu.AddItem(DirectWaypointBehavior);
|
||||
if(currentWaypoint.DrivingFlagType == DrivingFlagType.Direct)
|
||||
{
|
||||
directWaypointBehavior.Checked = true;
|
||||
DirectWaypointBehavior.Checked = true;
|
||||
}
|
||||
|
||||
editWaypointMenu.AddItem(changeWaypointSpeed = new UIMenuNumericScrollerItem<int>("Waypoint Speed", $"How fast the AI will drive to the waypoint in ~b~{SettingsMenu.speedUnits.SelectedItem}", 5, 100, 5));
|
||||
changeWaypointSpeed.Value = (int)MathHelper.ConvertMetersPerSecondToMilesPerHour(currentWaypoint.Speed);
|
||||
Menu.AddItem(ChangeWaypointSpeed = new UIMenuNumericScrollerItem<int>("Waypoint Speed", $"How fast the AI will drive to the waypoint in ~b~{SettingsMenu.SpeedUnits.SelectedItem}", 5, 100, 5));
|
||||
ChangeWaypointSpeed.Value = (int)MathHelper.ConvertMetersPerSecondToMilesPerHour(currentWaypoint.Speed);
|
||||
|
||||
editWaypointMenu.AddItem(updateWaypointPosition);
|
||||
editWaypointMenu.AddItem(updateWaypoint);
|
||||
updateWaypoint.ForeColor = Color.Gold;
|
||||
editWaypointMenu.AddItem(removeWaypoint);
|
||||
removeWaypoint.ForeColor = Color.Gold;
|
||||
editWaypointMenu.AddItem(addAsNewWaypoint);
|
||||
addAsNewWaypoint.ForeColor = Color.Gold;
|
||||
Menu.AddItem(UpdateWaypointPosition);
|
||||
Menu.AddItem(UpdateWaypoint);
|
||||
UpdateWaypoint.ForeColor = Color.Gold;
|
||||
Menu.AddItem(RemoveWaypoint);
|
||||
RemoveWaypoint.ForeColor = Color.Gold;
|
||||
Menu.AddItem(AddNewWaypoint);
|
||||
AddNewWaypoint.ForeColor = Color.Gold;
|
||||
|
||||
EditPathMenu.editPathMenu.Visible = false;
|
||||
editWaypointMenu.RefreshIndex();
|
||||
editWaypointMenu.Visible = true;
|
||||
}
|
||||
EditPathMenu.Menu.Visible = false;
|
||||
|
||||
Menu.RefreshIndex();
|
||||
Menu.Visible = true;
|
||||
}
|
||||
|
||||
private static void UpdateCollectorMenuOptionsStatus()
|
||||
private static void UpdateMenuSettings(Waypoint currentWaypoint)
|
||||
{
|
||||
if (collectorWaypoint.Checked)
|
||||
{
|
||||
changeCollectorRadius.Enabled = true;
|
||||
changeSpeedZoneRadius.Enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
changeCollectorRadius.Enabled = false;
|
||||
changeSpeedZoneRadius.Enabled = false;
|
||||
}
|
||||
ChangeWaypointSpeed.Value = (int)MathHelper.ConvertMetersPerSecondToMilesPerHour(currentWaypoint.Speed);
|
||||
StopWaypointType.Checked = currentWaypoint.IsStopWaypoint;
|
||||
DirectWaypointBehavior.Checked = currentWaypoint.DrivingFlagType == DrivingFlagType.Direct ? true : false;
|
||||
CollectorWaypoint.Checked = currentWaypoint.IsCollector;
|
||||
ChangeCollectorRadius.Enabled = CollectorWaypoint.Checked ? true : false;
|
||||
ChangeCollectorRadius.Value = (int)currentWaypoint.CollectorRadius;
|
||||
ChangeSpeedZoneRadius.Enabled = CollectorWaypoint.Checked ? true : false;
|
||||
ChangeSpeedZoneRadius.Value = (int)currentWaypoint.SpeedZoneRadius;
|
||||
UpdateWaypointPosition.Checked = false;
|
||||
}
|
||||
|
||||
private static void UpdateWaypoint()
|
||||
private static void ValidateCollectorRadiusSettings()
|
||||
{
|
||||
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
|
||||
var currentWaypoint = currentPath.Waypoints[editWaypoint.Index];
|
||||
DrivingFlagType drivingFlag = directWaypointBehavior.Checked ? DrivingFlagType.Direct : DrivingFlagType.Normal;
|
||||
|
||||
if (currentPath.Waypoints.Count == 1)
|
||||
if (ChangeCollectorRadius.Value > ChangeSpeedZoneRadius.Value)
|
||||
{
|
||||
currentWaypoint.UpdateWaypoint(currentWaypoint, MousePositionInWorld.GetPosition, drivingFlag, stopWaypointType.Checked, SetDriveSpeedForWaypoint(), true, changeCollectorRadius.Value, changeSpeedZoneRadius.Value, updateWaypointPosition.Checked);
|
||||
}
|
||||
else
|
||||
while (ChangeCollectorRadius.Value > ChangeSpeedZoneRadius.Value)
|
||||
{
|
||||
currentWaypoint.UpdateWaypoint(currentWaypoint, MousePositionInWorld.GetPosition, drivingFlag, stopWaypointType.Checked, SetDriveSpeedForWaypoint(), collectorWaypoint.Checked, changeCollectorRadius.Value, changeSpeedZoneRadius.Value, updateWaypointPosition.Checked);
|
||||
}
|
||||
|
||||
Game.LogTrivial($"Path {currentPath.Number} Waypoint {currentWaypoint.Number} updated [Driving style: {drivingFlag} | Stop waypoint: {stopWaypointType.Checked} | Speed: {changeWaypointSpeed.Value} | Collector: {currentWaypoint.IsCollector}]");
|
||||
|
||||
updateWaypointPosition.Checked = false;
|
||||
Game.DisplayNotification($"~o~Scene Manager ~g~[Success]~w~\nWaypoint {currentWaypoint.Number} updated.");
|
||||
}
|
||||
|
||||
private static void RemoveWaypoint()
|
||||
{
|
||||
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
|
||||
var currentWaypoint = currentPath.Waypoints[editWaypoint.Index];
|
||||
DrivingFlagType drivingFlag = directWaypointBehavior.Checked ? DrivingFlagType.Direct : DrivingFlagType.Normal;
|
||||
|
||||
if (currentPath.Waypoints.Count == 1)
|
||||
{
|
||||
Game.LogTrivial($"Deleting the last waypoint from the path.");
|
||||
PathMainMenu.DeletePath(currentPath, Delete.Single);
|
||||
|
||||
editWaypointMenu.Visible = false;
|
||||
PathMainMenu.pathMainMenu.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentWaypoint.Remove();
|
||||
currentPath.Waypoints.Remove(currentWaypoint);
|
||||
Game.LogTrivial($"[Path {currentPath.Number}] Waypoint {currentWaypoint.Number} ({currentWaypoint.DrivingFlagType}) removed");
|
||||
|
||||
foreach (Waypoint wp in currentPath.Waypoints)
|
||||
{
|
||||
wp.Number = currentPath.Waypoints.IndexOf(wp) + 1;
|
||||
}
|
||||
|
||||
editWaypointMenu.Clear();
|
||||
BuildEditWaypointMenu();
|
||||
|
||||
if (currentPath.Waypoints.Count == 1)
|
||||
{
|
||||
Hints.Display($"~o~Scene Manager ~y~[Hint]~w~\nYour path's first waypoint ~b~must~w~ be a collector. If it's not, it will automatically be made into one.");
|
||||
Game.LogTrivial($"The path only has 1 waypoint left, this waypoint must be a collector.");
|
||||
currentPath.Waypoints[0].UpdateWaypoint(currentWaypoint, MousePositionInWorld.GetPosition, drivingFlag, stopWaypointType.Checked, SetDriveSpeedForWaypoint(), true, changeCollectorRadius.Value, changeSpeedZoneRadius.Value, updateWaypointPosition.Checked);
|
||||
collectorWaypoint.Checked = true;
|
||||
changeCollectorRadius.Enabled = true;
|
||||
changeSpeedZoneRadius.Enabled = true;
|
||||
ChangeSpeedZoneRadius.ScrollToNextOption();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddAsNewWaypoint()
|
||||
private static void ValidateSpeedZoneRadiusSettings()
|
||||
{
|
||||
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
|
||||
DrivingFlagType drivingFlag = directWaypointBehavior.Checked ? DrivingFlagType.Direct : DrivingFlagType.Normal;
|
||||
|
||||
var pathIndex = PathMainMenu.paths.IndexOf(currentPath);
|
||||
var newWaypointBlip = CreateNewWaypointBlip();
|
||||
if (!currentPath.IsEnabled)
|
||||
if (ChangeSpeedZoneRadius.Value < ChangeCollectorRadius.Value)
|
||||
{
|
||||
newWaypointBlip.Alpha = 0.5f;
|
||||
}
|
||||
|
||||
if (collectorWaypoint.Checked)
|
||||
{
|
||||
currentPath.Waypoints.Add(new Waypoint(currentPath, currentPath.Waypoints.Last().Number + 1, MousePositionInWorld.GetPosition, SetDriveSpeedForWaypoint(), drivingFlag, stopWaypointType.Checked, newWaypointBlip, true, changeCollectorRadius.Value, changeSpeedZoneRadius.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPath.Waypoints.Add(new Waypoint(currentPath, currentPath.Waypoints.Last().Number + 1, MousePositionInWorld.GetPosition, SetDriveSpeedForWaypoint(), drivingFlag, stopWaypointType.Checked, newWaypointBlip));
|
||||
}
|
||||
|
||||
editWaypointMenu.RemoveItemAt(0);
|
||||
editWaypoint = new UIMenuNumericScrollerItem<int>("Edit Waypoint", "", currentPath.Waypoints.First().Number, currentPath.Waypoints.Last().Number, 1);
|
||||
editWaypointMenu.AddItem(editWaypoint, 0);
|
||||
editWaypoint.Index = editWaypoint.OptionCount - 1;
|
||||
editWaypointMenu.RefreshIndex();
|
||||
updateWaypointPosition.Checked = false;
|
||||
Game.LogTrivial($"New waypoint (#{currentPath.Waypoints.Last().Number}) added.");
|
||||
|
||||
Blip CreateNewWaypointBlip()
|
||||
{
|
||||
var spriteNumericalEnum = pathIndex + 17; // 17 because the numerical value of these sprites are always 17 more than the path index
|
||||
var blip = new Blip(MousePositionInWorld.GetPosition)
|
||||
{
|
||||
Scale = 0.5f,
|
||||
Sprite = (BlipSprite)spriteNumericalEnum
|
||||
};
|
||||
|
||||
if (collectorWaypoint.Checked)
|
||||
{
|
||||
blip.Color = Color.Blue;
|
||||
}
|
||||
else if (stopWaypointType.Checked)
|
||||
{
|
||||
blip.Color = Color.Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
blip.Color = Color.Green;
|
||||
}
|
||||
|
||||
if (!SettingsMenu.mapBlips.Checked)
|
||||
{
|
||||
blip.Alpha = 0f;
|
||||
}
|
||||
|
||||
return blip;
|
||||
ChangeCollectorRadius.Value = ChangeSpeedZoneRadius.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EditWaypoint_OnScrollerChanged(UIMenu sender, UIMenuScrollerItem scrollerItem, int first, int last)
|
||||
{
|
||||
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
|
||||
var currentWaypoint = currentPath.Waypoints[editWaypoint.Value - 1];
|
||||
var currentPath = PathManager.Paths[PathMainMenu.EditPath.Index];
|
||||
var currentWaypoint = currentPath.Waypoints[EditWaypoint.Value - 1];
|
||||
|
||||
if (scrollerItem == editWaypoint)
|
||||
if (scrollerItem == EditWaypoint)
|
||||
{
|
||||
changeWaypointSpeed.Value = (int)MathHelper.ConvertMetersPerSecondToMilesPerHour(currentWaypoint.Speed);
|
||||
stopWaypointType.Checked = currentWaypoint.IsStopWaypoint;
|
||||
directWaypointBehavior.Checked = currentWaypoint.DrivingFlagType == DrivingFlagType.Direct ? true : false;
|
||||
collectorWaypoint.Checked = currentWaypoint.IsCollector;
|
||||
changeCollectorRadius.Enabled = collectorWaypoint.Checked ? true : false;
|
||||
changeCollectorRadius.Value = (int)currentWaypoint.CollectorRadius;
|
||||
changeSpeedZoneRadius.Enabled = collectorWaypoint.Checked ? true : false;
|
||||
changeSpeedZoneRadius.Value = (int)currentWaypoint.SpeedZoneRadius;
|
||||
updateWaypointPosition.Checked = false;
|
||||
UpdateMenuSettings(currentWaypoint);
|
||||
}
|
||||
|
||||
if (scrollerItem == changeCollectorRadius)
|
||||
if (scrollerItem == ChangeCollectorRadius)
|
||||
{
|
||||
if (changeCollectorRadius.Value > changeSpeedZoneRadius.Value)
|
||||
{
|
||||
while(changeCollectorRadius.Value > changeSpeedZoneRadius.Value)
|
||||
{
|
||||
changeSpeedZoneRadius.ScrollToNextOption();
|
||||
}
|
||||
}
|
||||
ValidateCollectorRadiusSettings();
|
||||
}
|
||||
|
||||
if (scrollerItem == changeSpeedZoneRadius)
|
||||
if (scrollerItem == ChangeSpeedZoneRadius)
|
||||
{
|
||||
if (changeSpeedZoneRadius.Value < changeCollectorRadius.Value)
|
||||
{
|
||||
changeCollectorRadius.Value = changeSpeedZoneRadius.Value;
|
||||
}
|
||||
ValidateSpeedZoneRadiusSettings();
|
||||
}
|
||||
}
|
||||
|
||||
private static void EditWaypoint_OnCheckboxChanged(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked)
|
||||
{
|
||||
if (checkboxItem == collectorWaypoint)
|
||||
if (checkboxItem == CollectorWaypoint)
|
||||
{
|
||||
changeCollectorRadius.Enabled = collectorWaypoint.Checked ? true : false;
|
||||
changeSpeedZoneRadius.Enabled = collectorWaypoint.Checked ? true : false;
|
||||
ChangeCollectorRadius.Enabled = CollectorWaypoint.Checked ? true : false;
|
||||
ChangeSpeedZoneRadius.Enabled = CollectorWaypoint.Checked ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EditWaypoint_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||
{
|
||||
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
|
||||
var currentWaypoint = currentPath.Waypoints[editWaypoint.Index];
|
||||
DrivingFlagType drivingFlag = directWaypointBehavior.Checked ? DrivingFlagType.Direct : DrivingFlagType.Normal;
|
||||
//var currentPath = PathManager.Paths[PathMainMenu.EditPath.Index];
|
||||
var currentPath = PathManager.Paths.FirstOrDefault(x => x.Name == PathMainMenu.EditPath.OptionText);
|
||||
|
||||
if (selectedItem == updateWaypoint)
|
||||
if (selectedItem == UpdateWaypoint)
|
||||
{
|
||||
UpdateWaypoint();
|
||||
PathManager.UpdateWaypoint();
|
||||
}
|
||||
|
||||
if (selectedItem == addAsNewWaypoint)
|
||||
if (selectedItem == AddNewWaypoint)
|
||||
{
|
||||
AddAsNewWaypoint();
|
||||
PathManager.AddNewEditWaypoint(currentPath);
|
||||
|
||||
UpdateEditWaypointMenuItem();
|
||||
}
|
||||
|
||||
if (selectedItem == removeWaypoint)
|
||||
if (selectedItem == RemoveWaypoint)
|
||||
{
|
||||
RemoveWaypoint();
|
||||
PathManager.RemoveEditWaypoint(currentPath);
|
||||
if(PathManager.Paths.Length < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BuildEditWaypointMenu();
|
||||
}
|
||||
|
||||
void UpdateEditWaypointMenuItem()
|
||||
{
|
||||
// Need to close and re-open the menu so the mouse scroll works on the re-added menu item.
|
||||
MenuManager.MenuPool.CloseAllMenus();
|
||||
Menu.RemoveItemAt(0);
|
||||
EditWaypoint = new UIMenuNumericScrollerItem<int>("Edit Waypoint", "", currentPath.Waypoints.First().Number, currentPath.Waypoints.Last().Number, 1);
|
||||
Menu.AddItem(EditWaypoint, 0);
|
||||
EditWaypoint.Index = EditWaypoint.OptionCount - 1;
|
||||
Menu.RefreshIndex();
|
||||
UpdateWaypointPosition.Checked = false;
|
||||
Menu.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EditWaypoint_OnMenuOpen(UIMenu menu)
|
||||
{
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { editWaypoint, changeWaypointSpeed, changeCollectorRadius, changeSpeedZoneRadius };
|
||||
RNUIMouseInputHandler.Initialize(menu, scrollerItems);
|
||||
}
|
||||
|
||||
private static float SetDriveSpeedForWaypoint()
|
||||
{
|
||||
float convertedSpeed;
|
||||
if (SettingsMenu.speedUnits.SelectedItem == SpeedUnits.MPH)
|
||||
{
|
||||
convertedSpeed = MathHelper.ConvertMilesPerHourToMetersPerSecond(changeWaypointSpeed.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
convertedSpeed = MathHelper.ConvertKilometersPerHourToMetersPerSecond(changeWaypointSpeed.Value);
|
||||
}
|
||||
|
||||
return convertedSpeed;
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { EditWaypoint, ChangeWaypointSpeed, ChangeCollectorRadius, ChangeSpeedZoneRadius };
|
||||
GameFiber.StartNew(() => UserInput.InitializeMenuMouseControl(menu, scrollerItems), "RNUI Mouse Input Fiber");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
217
SceneManager/Menus/ExportPathMenu.cs
Normal file
217
SceneManager/Menus/ExportPathMenu.cs
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
using RAGENativeUI;
|
||||
using RAGENativeUI.Elements;
|
||||
using System.Drawing;
|
||||
using SceneManager.Utils;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Rage;
|
||||
using SceneManager.Managers;
|
||||
using System.IO;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace SceneManager.Menus
|
||||
{
|
||||
internal static class ExportPathMenu
|
||||
{
|
||||
public static List<Paths.Path> ExportPaths { get; } = new List<Paths.Path>();
|
||||
|
||||
internal static UIMenu Menu = new UIMenu("Scene Manager", "~o~Export Path Menu");
|
||||
internal static UIMenuListScrollerItem<string> ExportOptions = new UIMenuListScrollerItem<string>("Export As", "Choose whether you want the paths exported as individual files, or all within the same file.", new string[] { "Individual file(s)", "Combined file" });
|
||||
internal static UIMenuItem Export = new UIMenuItem("Export", "Export the selected path(s)");
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
Menu.ParentMenu = PathMainMenu.Menu;
|
||||
MenuManager.MenuPool.Add(Menu);
|
||||
|
||||
Menu.OnItemSelect += ExportPathMenu_OnItemSelect;
|
||||
Menu.OnCheckboxChange += ExportPathMenu_OnCheckboxChange;
|
||||
Menu.OnMenuOpen += ExportPathMenu_OnMenuOpen;
|
||||
}
|
||||
|
||||
internal static void Build()
|
||||
{
|
||||
Menu.Clear();
|
||||
foreach(Paths.Path path in PathManager.Paths.Where(x => x != null))
|
||||
{
|
||||
Menu.AddItem(new UIMenuCheckboxItem(path.Name, false));
|
||||
}
|
||||
|
||||
Menu.AddItem(ExportOptions);
|
||||
ExportOptions.Enabled = false;
|
||||
Menu.AddItem(Export);
|
||||
Export.ForeColor = Color.Gold;
|
||||
Export.Enabled = false;
|
||||
|
||||
Menu.RefreshIndex();
|
||||
}
|
||||
|
||||
private static void ExportPathMenu_OnMenuOpen(UIMenu menu)
|
||||
{
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { ExportOptions };
|
||||
GameFiber.StartNew(() => UserInput.InitializeMenuMouseControl(menu, scrollerItems), "RNUI Mouse Input Fiber");
|
||||
}
|
||||
|
||||
private static void ExportPathMenu_OnCheckboxChange(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool Checked)
|
||||
{
|
||||
var checkboxItems = Menu.MenuItems.Where(x => x.GetType() == typeof(UIMenuCheckboxItem));
|
||||
int checkedItems = 0;
|
||||
foreach (UIMenuCheckboxItem menuItem in checkboxItems)
|
||||
{
|
||||
if (menuItem.Checked)
|
||||
{
|
||||
checkedItems++;
|
||||
}
|
||||
}
|
||||
|
||||
Export.Enabled = checkedItems > 0;
|
||||
|
||||
if(checkedItems > 1)
|
||||
{
|
||||
ExportOptions.Enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!ExportOptions.OptionText.Contains("Individual"))
|
||||
{
|
||||
ExportOptions.ScrollToNextOption();
|
||||
}
|
||||
ExportOptions.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExportPathMenu_OnItemSelect(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||
{
|
||||
if(selectedItem == Export)
|
||||
{
|
||||
ExportPaths.Clear();
|
||||
var checkboxItems = Menu.MenuItems.Where(x => x.GetType() == typeof(UIMenuCheckboxItem)).Select(x => (UIMenuCheckboxItem)x);
|
||||
var checkedItems = checkboxItems.Where(x => x.Checked);
|
||||
foreach(UIMenuCheckboxItem checkedItem in checkedItems)
|
||||
{
|
||||
var pathToExport = PathManager.Paths.First(x => x.Name == checkedItem.Text);
|
||||
ExportPaths.Add(pathToExport);
|
||||
}
|
||||
|
||||
if (ExportOptions.OptionText.Contains("Individual"))
|
||||
{
|
||||
foreach (UIMenuCheckboxItem menuItem in checkedItems)
|
||||
{
|
||||
var pathToExport = PathManager.Paths.First(x => x.Name == menuItem.Text);
|
||||
ExportAsIndividualFile(pathToExport);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ExportAsCombinedFile(checkboxItems);
|
||||
}
|
||||
|
||||
MenuManager.BuildMenus();
|
||||
Menu.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExportAsIndividualFile(Paths.Path pathToExport)
|
||||
{
|
||||
if (CanQuickSavePath(pathToExport))
|
||||
{
|
||||
pathToExport.Save();
|
||||
return;
|
||||
}
|
||||
|
||||
var fileName = UserInput.PromptPlayerForFileName("Type the name you would like to save your file as", "Enter a filename", 100);
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
Game.DisplayHelp($"Invalid filename given. Filename cannot be null, empty, or consist of just white spaces. Defaulting to ~b~\"{pathToExport.Name}\"");
|
||||
Game.LogTrivial($"Invalid filename given. Filename cannot be null, empty, or consist of just white spaces. Defaulting to \"{pathToExport.Name}\"");
|
||||
fileName = pathToExport.Name;
|
||||
}
|
||||
|
||||
Game.LogTrivial($"Filename: {fileName}");
|
||||
pathToExport.Name = fileName;
|
||||
|
||||
var GAME_DIRECTORY = Directory.GetCurrentDirectory();
|
||||
var SAVED_PATHS_DIRECTORY = GAME_DIRECTORY + "/plugins/SceneManager/Saved Paths/";
|
||||
var overrides = Serializer.DefineOverrides();
|
||||
Serializer.SaveItemToXML(ExportPaths, SAVED_PATHS_DIRECTORY + fileName + ".xml", overrides);
|
||||
Game.DisplayNotification($"~o~Scene Manager ~g~[Success]\n~w~Path exported as ~b~{fileName}.xml~w~.");
|
||||
}
|
||||
|
||||
private static void ExportAsCombinedFile(IEnumerable<UIMenuCheckboxItem> checkedItems, bool autosave = false)
|
||||
{
|
||||
var GAME_DIRECTORY = Directory.GetCurrentDirectory();
|
||||
var SAVED_PATHS_DIRECTORY = GAME_DIRECTORY + "/plugins/SceneManager/Saved Paths/";
|
||||
var overrides = Serializer.DefineOverrides();
|
||||
|
||||
if (autosave)
|
||||
{
|
||||
Serializer.SaveItemToXML(ExportPaths, SAVED_PATHS_DIRECTORY + "autosave.xml", overrides);
|
||||
Game.DisplayNotification($"~o~Scene Manager ~g~[Success]\n~w~Paths exported as ~b~autosave.xml~w~.");
|
||||
return;
|
||||
}
|
||||
|
||||
// If any file contains all (and only) path names from checkedItems, it can be quicksaved
|
||||
string existingFile = GetNameForExistingCombinedPathsFile(checkedItems);
|
||||
string exportFilename = existingFile;
|
||||
|
||||
if (exportFilename == "")
|
||||
{
|
||||
exportFilename = UserInput.PromptPlayerForFileName("Type the name you would like to save your file as", "Enter a filename", 100);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(exportFilename))
|
||||
{
|
||||
Game.DisplayHelp($"Invalid filename given. Filename cannot be null, empty, or consist of just white spaces. Defaulting to ~b~\"{checkedItems.First().Text}\"");
|
||||
Game.LogTrivial($"Invalid filename given. Filename cannot be null, empty, or consist of just white spaces. Defaulting to \"{checkedItems.First().Text}\"");
|
||||
exportFilename = checkedItems.First().Text;
|
||||
}
|
||||
}
|
||||
Game.LogTrivial($"Filename: {exportFilename}");
|
||||
|
||||
Serializer.SaveItemToXML(ExportPaths, SAVED_PATHS_DIRECTORY + exportFilename + ".xml", overrides);
|
||||
Game.DisplayNotification($"~o~Scene Manager ~g~[Success]\n~w~Paths exported as ~b~{exportFilename}.xml~w~.");
|
||||
}
|
||||
|
||||
internal static void ExportOnUnload()
|
||||
{
|
||||
ExportPaths.Clear();
|
||||
var checkboxItems = Menu.MenuItems.Where(x => x.GetType() == typeof(UIMenuCheckboxItem)).Select(x => (UIMenuCheckboxItem)x);
|
||||
foreach (UIMenuCheckboxItem checkboxItem in checkboxItems)
|
||||
{
|
||||
var pathToExport = PathManager.Paths.First(x => x != null && x.Name == checkboxItem.Text);
|
||||
ExportPaths.Add(pathToExport);
|
||||
}
|
||||
|
||||
ExportAsCombinedFile(checkboxItems, true);
|
||||
}
|
||||
|
||||
private static bool CanQuickSavePath(Paths.Path pathToExport)
|
||||
{
|
||||
var GAME_DIRECTORY = Directory.GetCurrentDirectory();
|
||||
var SAVED_PATHS_DIRECTORY = GAME_DIRECTORY + "\\plugins\\SceneManager\\Saved Paths\\";
|
||||
if (!Directory.Exists(SAVED_PATHS_DIRECTORY))
|
||||
{
|
||||
Game.LogTrivial($"Directory '\\plugins\\SceneManager\\Saved Paths' does not exist.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var savedPathNames = Directory.GetFiles(SAVED_PATHS_DIRECTORY, "*.xml");
|
||||
return savedPathNames.Any(x => Path.GetFileNameWithoutExtension(x) == pathToExport.Name);
|
||||
}
|
||||
|
||||
private static string GetNameForExistingCombinedPathsFile(IEnumerable<UIMenuCheckboxItem> checkedItems)
|
||||
{
|
||||
var checkedItemsText = checkedItems.Select(x => x.Text);
|
||||
foreach (KeyValuePair<string, List<Paths.Path>> kvp in PathManager.ImportedPaths)
|
||||
{
|
||||
var pathNames = kvp.Value.Select(x => x.Name);
|
||||
if (checkedItemsText.Count() == pathNames.Count() && checkedItemsText.All(x => pathNames.Contains(x)))
|
||||
{
|
||||
Game.LogTrivial($"File \"{kvp.Key}\" contains all paths to be exported. Quicksave.");
|
||||
return kvp.Key;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
126
SceneManager/Menus/ImportPathMenu.cs
Normal file
126
SceneManager/Menus/ImportPathMenu.cs
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
using RAGENativeUI;
|
||||
using RAGENativeUI.Elements;
|
||||
using System.Drawing;
|
||||
using SceneManager.Utils;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Rage;
|
||||
using SceneManager.Managers;
|
||||
using System.IO;
|
||||
|
||||
namespace SceneManager.Menus
|
||||
{
|
||||
internal class ImportPathMenu
|
||||
{
|
||||
internal static UIMenu Menu = new UIMenu("Scene Manager", "~o~Import Path Menu");
|
||||
internal static UIMenuItem Import { get; } = new UIMenuItem("Import", "Import the selected paths.");
|
||||
internal static List<string> ImportedFileNames { get; } = new List<string>();
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
Menu.ParentMenu = PathMainMenu.Menu;
|
||||
MenuManager.MenuPool.Add(Menu);
|
||||
|
||||
Menu.OnItemSelect += ImportPathMenu_OnItemSelect;
|
||||
Menu.OnMenuOpen += ImportPathMenu_OnMenuOpen;
|
||||
Menu.OnCheckboxChange += ImportPathMenu_OnCheckboxChange;
|
||||
}
|
||||
|
||||
internal static void Build()
|
||||
{
|
||||
Menu.Clear();
|
||||
|
||||
GetFileNamesForPathsToImport();
|
||||
foreach(string fileName in ImportedFileNames)
|
||||
{
|
||||
var menuItem = new UIMenuCheckboxItem(fileName, false);
|
||||
if (!PathManager.LoadedFiles.Contains(fileName))
|
||||
{
|
||||
menuItem.LeftBadge = UIMenuItem.BadgeStyle.Star;
|
||||
}
|
||||
Menu.AddItem(menuItem);
|
||||
}
|
||||
|
||||
Menu.AddItem(Import);
|
||||
Import.ForeColor = Color.Gold;
|
||||
Import.Enabled = false;
|
||||
}
|
||||
|
||||
private static void ImportPathMenu_OnMenuOpen(UIMenu menu)
|
||||
{
|
||||
GameFiber.StartNew(() => UserInput.InitializeMenuMouseControl(menu, new List<UIMenuScrollerItem>()), "RNUI Mouse Input Fiber");
|
||||
}
|
||||
|
||||
private static void ImportPathMenu_OnItemSelect(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||
{
|
||||
if(selectedItem == Import)
|
||||
{
|
||||
var checkboxItems = Menu.MenuItems.Where(x => x.GetType() == typeof(UIMenuCheckboxItem)).Cast<UIMenuCheckboxItem>();
|
||||
var checkedItems = checkboxItems.Where(x => x.Checked);
|
||||
|
||||
foreach(var menuItem in checkedItems)
|
||||
{
|
||||
var importedPaths = PathManager.ImportPathsFromFile(menuItem.Text);
|
||||
if (importedPaths != null)
|
||||
{
|
||||
PathManager.LoadImportedPaths(importedPaths, menuItem.Text);
|
||||
}
|
||||
}
|
||||
Menu.RefreshIndex();
|
||||
|
||||
MenuManager.BuildMenus();
|
||||
Menu.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void GetFileNamesForPathsToImport()
|
||||
{
|
||||
ImportedFileNames.Clear();
|
||||
|
||||
// Check if Saved Paths directory exists
|
||||
var GAME_DIRECTORY = Directory.GetCurrentDirectory();
|
||||
var SAVED_PATHS_DIRECTORY = GAME_DIRECTORY + "\\plugins\\SceneManager\\Saved Paths\\";
|
||||
if (!Directory.Exists(SAVED_PATHS_DIRECTORY))
|
||||
{
|
||||
Game.LogTrivial($"Directory '\\plugins\\SceneManager\\Saved Paths' does not exist. No paths available to import.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if any XML files are available to import from Saved Paths
|
||||
var savedPathFiles = Directory.GetFiles(SAVED_PATHS_DIRECTORY, "*.xml");
|
||||
if (savedPathFiles.Length == 0)
|
||||
{
|
||||
Game.LogTrivial($"No saved paths found.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.LogTrivial($"{savedPathFiles.Length} path(s) available to import.");
|
||||
}
|
||||
|
||||
// Import file names
|
||||
foreach (string file in savedPathFiles)
|
||||
{
|
||||
string fileName = System.IO.Path.GetFileNameWithoutExtension(file);
|
||||
Game.LogTrivial($"File: {fileName}");
|
||||
ImportedFileNames.Add(fileName);
|
||||
}
|
||||
Game.LogTrivial($"Successfully populated menu with {ImportedFileNames.Count} file(s).");
|
||||
}
|
||||
|
||||
private static void ImportPathMenu_OnCheckboxChange(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool Checked)
|
||||
{
|
||||
var checkboxItems = Menu.MenuItems.Where(x => x.GetType() == typeof(UIMenuCheckboxItem));
|
||||
int checkedItems = 0;
|
||||
foreach (UIMenuCheckboxItem menuItem in checkboxItems)
|
||||
{
|
||||
if (menuItem.Checked)
|
||||
{
|
||||
checkedItems++;
|
||||
}
|
||||
}
|
||||
|
||||
Import.Enabled = checkedItems > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,42 +3,61 @@ using RAGENativeUI.Elements;
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using SceneManager.Utils;
|
||||
using Rage;
|
||||
using SceneManager.Managers;
|
||||
using System.Linq;
|
||||
|
||||
namespace SceneManager
|
||||
namespace SceneManager.Menus
|
||||
{
|
||||
// The only reason this class should change is to modify the main menu
|
||||
class MainMenu
|
||||
{
|
||||
internal static UIMenu mainMenu { get; private set; }
|
||||
private static UIMenuItem navigateToPathMenu, navigateToBarrierMenu, navigateToSettingsMenu;
|
||||
internal static UIMenu Menu { get; } = new UIMenu("Scene Manager", "~o~Main Menu");
|
||||
|
||||
internal static void InstantiateMenu()
|
||||
internal static void Initialize()
|
||||
{
|
||||
mainMenu = new UIMenu("Scene Manager", "~o~Main Menu");
|
||||
MenuManager.menuPool.Add(mainMenu);
|
||||
MenuManager.MenuPool.Add(Menu);
|
||||
|
||||
Menu.OnMenuOpen += MainMenu_OnMenuOpen;
|
||||
}
|
||||
|
||||
internal static void BuildMainMenu()
|
||||
internal static void Build()
|
||||
{
|
||||
mainMenu.AddItem(navigateToPathMenu = new UIMenuItem("Path Menu"));
|
||||
Menu.Clear();
|
||||
|
||||
var navigateToPathMenu = new UIMenuItem("Manage Paths");
|
||||
Menu.AddItem(navigateToPathMenu);
|
||||
navigateToPathMenu.ForeColor = Color.Gold;
|
||||
mainMenu.BindMenuToItem(PathMainMenu.pathMainMenu, navigateToPathMenu);
|
||||
Menu.BindMenuToItem(PathMainMenu.Menu, navigateToPathMenu);
|
||||
|
||||
mainMenu.AddItem(navigateToBarrierMenu = new UIMenuItem("Barrier Menu"));
|
||||
var navigateToDriverMenu = new UIMenuItem("Manage Drivers", "After you create a path, you will be able to direct drivers using this menu.");
|
||||
Menu.AddItem(navigateToDriverMenu);
|
||||
navigateToDriverMenu.ForeColor = Color.Gold;
|
||||
Menu.BindMenuToItem(DriverMenu.Menu, navigateToDriverMenu);
|
||||
navigateToDriverMenu.Enabled = PathManager.Paths.Count() > 0;
|
||||
|
||||
var navigateToBarrierMenu = new UIMenuItem("Manage Barriers");
|
||||
Menu.AddItem(navigateToBarrierMenu);
|
||||
navigateToBarrierMenu.ForeColor = Color.Gold;
|
||||
mainMenu.BindMenuToItem(BarrierMenu.barrierMenu, navigateToBarrierMenu);
|
||||
Menu.BindMenuToItem(BarrierMenu.Menu, navigateToBarrierMenu);
|
||||
|
||||
mainMenu.AddItem(navigateToSettingsMenu = new UIMenuItem("Settings"));
|
||||
var navigateToSettingsMenu = new UIMenuItem("Settings");
|
||||
Menu.AddItem(navigateToSettingsMenu);
|
||||
navigateToSettingsMenu.ForeColor = Color.Gold;
|
||||
mainMenu.BindMenuToItem(SettingsMenu.settingsMenu, navigateToSettingsMenu);
|
||||
Menu.BindMenuToItem(SettingsMenu.Menu, navigateToSettingsMenu);
|
||||
|
||||
mainMenu.RefreshIndex();
|
||||
mainMenu.OnMenuOpen += MainMenu_OnMenuOpen;
|
||||
Menu.RefreshIndex();
|
||||
}
|
||||
|
||||
private static void MainMenu_OnMenuOpen(UIMenu menu)
|
||||
{
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { };
|
||||
RNUIMouseInputHandler.Initialize(menu, scrollerItems);
|
||||
GameFiber.StartNew(() => UserInput.InitializeMenuMouseControl(menu, scrollerItems), "RNUI Mouse Input Fiber");
|
||||
}
|
||||
|
||||
internal static void DisplayMenu()
|
||||
{
|
||||
Menu.Visible = !Menu.Visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
using RAGENativeUI;
|
||||
using RAGENativeUI.Elements;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
namespace SceneManager
|
||||
{
|
||||
internal static class MenuManager
|
||||
{
|
||||
internal static MenuPool menuPool = new MenuPool();
|
||||
internal static Dictionary<UIMenu, List<UIMenuItem>> menus = new Dictionary<UIMenu, List<UIMenuItem>>();
|
||||
|
||||
internal static void InstantiateMenus()
|
||||
{
|
||||
MainMenu.InstantiateMenu();
|
||||
SettingsMenu.InstantiateMenu();
|
||||
PathMainMenu.InstantiateMenu();
|
||||
PathCreationMenu.InstantiateMenu();
|
||||
BarrierMenu.InstantiateMenu();
|
||||
EditPathMenu.InstantiateMenu();
|
||||
EditWaypointMenu.InstantiateMenu();
|
||||
|
||||
BuildMenus();
|
||||
DefineMenuMouseSettings();
|
||||
}
|
||||
|
||||
private static void DefineMenuMouseSettings()
|
||||
{
|
||||
foreach (UIMenu menu in menuPool)
|
||||
{
|
||||
menu.MouseControlsEnabled = false;
|
||||
menu.AllowCameraMovement = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void BuildMenus()
|
||||
{
|
||||
MainMenu.BuildMainMenu();
|
||||
SettingsMenu.BuildSettingsMenu();
|
||||
PathMainMenu.BuildPathMenu();
|
||||
EditPathMenu.BuildEditPathMenu();
|
||||
BarrierMenu.BuildBarrierMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,318 +1,163 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using Rage;
|
||||
using RAGENativeUI;
|
||||
using RAGENativeUI.Elements;
|
||||
using SceneManager.Utils;
|
||||
using SceneManager.Objects;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Paths;
|
||||
|
||||
namespace SceneManager
|
||||
namespace SceneManager.Menus
|
||||
{
|
||||
class PathCreationMenu
|
||||
{
|
||||
internal static UIMenu pathCreationMenu = new UIMenu("Scene Manager", "~o~Path Creation Menu");
|
||||
private static UIMenuItem trafficAddWaypoint = new UIMenuItem("Add waypoint"), trafficRemoveWaypoint = new UIMenuItem("Remove last waypoint"), trafficEndPath = new UIMenuItem("End path creation");
|
||||
internal static UIMenuNumericScrollerItem<int> waypointSpeed;
|
||||
internal static UIMenuCheckboxItem stopWaypointType = new UIMenuCheckboxItem("Is this a Stop waypoint?", false, "If checked, vehicles will drive to this waypoint, then stop.");
|
||||
internal static UIMenuCheckboxItem directWaypointBehavior = new UIMenuCheckboxItem("Drive directly to waypoint?", false, "If checked, vehicles will ignore traffic rules and drive directly to this waypoint.");
|
||||
internal static UIMenuCheckboxItem collectorWaypoint = new UIMenuCheckboxItem("Collector", true, "If checked, this waypoint will collect vehicles to follow the path. Your path's first waypoint ~b~must~w~ be a collector.");
|
||||
internal static UIMenuNumericScrollerItem<int> collectorRadius = new UIMenuNumericScrollerItem<int>("Collection Radius", "The distance from this waypoint (in meters) vehicles will be collected", 1, 50, 1);
|
||||
internal static UIMenuNumericScrollerItem<int> speedZoneRadius = new UIMenuNumericScrollerItem<int>("Speed Zone Radius", "The distance from this collector waypoint (in meters) non-collected vehicles will drive at this waypoint's speed", 5, 200, 5);
|
||||
private static List<UIMenuItem> menuItems = new List<UIMenuItem> {collectorWaypoint, collectorRadius, speedZoneRadius, stopWaypointType, directWaypointBehavior, waypointSpeed, trafficAddWaypoint, trafficRemoveWaypoint, trafficEndPath };
|
||||
internal static UIMenu Menu { get; } = new UIMenu("Scene Manager", "~o~Path Creation Menu");
|
||||
private static Path CurrentPath { get; set; }
|
||||
private static UIMenuItem AddWaypoint { get; } = new UIMenuItem("Add waypoint");
|
||||
internal static UIMenuItem RemoveLastWaypoint { get; } = new UIMenuItem("Remove last waypoint");
|
||||
internal static UIMenuItem EndPathCreation { get; } = new UIMenuItem("End path creation");
|
||||
internal static UIMenuNumericScrollerItem<int> WaypointSpeed { get; private set; }
|
||||
internal static UIMenuCheckboxItem StopWaypoint { get; } = new UIMenuCheckboxItem("Is this a Stop waypoint?", false, "If checked, vehicles will drive to this waypoint, then stop.");
|
||||
internal static UIMenuCheckboxItem DirectWaypoint { get; } = new UIMenuCheckboxItem("Drive directly to waypoint?", false, "If checked, vehicles will ignore traffic rules and drive directly to this waypoint.");
|
||||
internal static UIMenuCheckboxItem CollectorWaypoint { get; } = new UIMenuCheckboxItem("Collector", true, "If checked, this waypoint will collect vehicles to follow the path. Your path's first waypoint ~b~must~w~ be a collector.");
|
||||
internal static UIMenuNumericScrollerItem<int> CollectorRadius { get; } = new UIMenuNumericScrollerItem<int>("Collection Radius", "The distance from this waypoint (in meters) vehicles will be collected", 1, 50, 1);
|
||||
internal static UIMenuNumericScrollerItem<int> SpeedZoneRadius { get; } = new UIMenuNumericScrollerItem<int>("Speed Zone Radius", "The distance from this collector waypoint (in meters) non-collected vehicles will drive at this waypoint's speed", 5, 200, 5);
|
||||
internal static UIMenuItem PathName { get; private set; } = new UIMenuItem("Change Path Name", $"Add your first waypoint to enable this option.");
|
||||
internal static State PathCreationState { get; set; } = State.Uninitialized;
|
||||
|
||||
internal static void InstantiateMenu()
|
||||
internal static void Initialize()
|
||||
{
|
||||
pathCreationMenu.ParentMenu = PathMainMenu.pathMainMenu;
|
||||
MenuManager.menuPool.Add(pathCreationMenu);
|
||||
pathCreationMenu.OnItemSelect += PathCreation_OnItemSelected;
|
||||
pathCreationMenu.OnCheckboxChange += PathCreation_OnCheckboxChanged;
|
||||
pathCreationMenu.OnScrollerChange += PathCreation_OnScrollerChanged;
|
||||
pathCreationMenu.OnMenuOpen += PathCreation_OnMenuOpen;
|
||||
Menu.ParentMenu = PathMainMenu.Menu;
|
||||
MenuManager.MenuPool.Add(Menu);
|
||||
|
||||
Menu.OnItemSelect += PathCreation_OnItemSelected;
|
||||
Menu.OnCheckboxChange += PathCreation_OnCheckboxChanged;
|
||||
Menu.OnScrollerChange += PathCreation_OnScrollerChanged;
|
||||
Menu.OnMenuOpen += PathCreation_OnMenuOpen;
|
||||
}
|
||||
|
||||
internal static void BuildPathCreationMenu()
|
||||
internal static void Build()
|
||||
{
|
||||
pathCreationMenu.AddItem(collectorWaypoint);
|
||||
collectorWaypoint.Enabled = false;
|
||||
collectorWaypoint.Checked = true;
|
||||
Menu.Clear();
|
||||
|
||||
pathCreationMenu.AddItem(collectorRadius);
|
||||
collectorRadius.Index = Settings.CollectorRadius - 1;
|
||||
collectorRadius.Enabled = true;
|
||||
Menu.AddItem(CollectorWaypoint);
|
||||
CollectorWaypoint.Enabled = false;
|
||||
CollectorWaypoint.Checked = true;
|
||||
|
||||
pathCreationMenu.AddItem(speedZoneRadius);
|
||||
speedZoneRadius.Index = (Settings.SpeedZoneRadius / 5) - 1;
|
||||
speedZoneRadius.Enabled = true;
|
||||
Menu.AddItem(CollectorRadius);
|
||||
CollectorRadius.Index = Settings.CollectorRadius - 1;
|
||||
CollectorRadius.Enabled = true;
|
||||
|
||||
pathCreationMenu.AddItem(stopWaypointType);
|
||||
stopWaypointType.Checked = Settings.StopWaypoint;
|
||||
pathCreationMenu.AddItem(directWaypointBehavior);
|
||||
directWaypointBehavior.Checked = Settings.DirectDrivingBehavior;
|
||||
Menu.AddItem(SpeedZoneRadius);
|
||||
SpeedZoneRadius.Index = (Settings.SpeedZoneRadius / 5) - 1;
|
||||
SpeedZoneRadius.Enabled = true;
|
||||
|
||||
pathCreationMenu.AddItem(waypointSpeed = new UIMenuNumericScrollerItem<int>("Waypoint Speed", $"How fast the AI will drive to this waypoint in ~b~{SettingsMenu.speedUnits.SelectedItem}", 5, 100, 5));
|
||||
waypointSpeed.Index = (Settings.WaypointSpeed / 5) - 1;
|
||||
Menu.AddItem(StopWaypoint);
|
||||
StopWaypoint.Checked = Settings.StopWaypoint;
|
||||
Menu.AddItem(DirectWaypoint);
|
||||
DirectWaypoint.Checked = Settings.DirectDrivingBehavior;
|
||||
|
||||
pathCreationMenu.AddItem(trafficAddWaypoint);
|
||||
trafficAddWaypoint.ForeColor = Color.Gold;
|
||||
Menu.AddItem(WaypointSpeed = new UIMenuNumericScrollerItem<int>("Waypoint Speed", $"How fast the AI will drive to this waypoint in ~b~{SettingsMenu.SpeedUnits.SelectedItem}", 5, 100, 5));
|
||||
WaypointSpeed.Index = (Settings.WaypointSpeed / 5) - 1;
|
||||
|
||||
pathCreationMenu.AddItem(trafficRemoveWaypoint);
|
||||
trafficRemoveWaypoint.ForeColor = Color.Gold;
|
||||
trafficRemoveWaypoint.Enabled = false;
|
||||
Menu.AddItem(PathName);
|
||||
PathName.ForeColor = Color.Gold;
|
||||
PathName.Enabled = false;
|
||||
|
||||
pathCreationMenu.AddItem(trafficEndPath);
|
||||
trafficEndPath.ForeColor = Color.Gold;
|
||||
trafficEndPath.Enabled = false;
|
||||
Menu.AddItem(AddWaypoint);
|
||||
AddWaypoint.ForeColor = Color.Gold;
|
||||
|
||||
pathCreationMenu.RefreshIndex();
|
||||
Menu.AddItem(RemoveLastWaypoint);
|
||||
RemoveLastWaypoint.ForeColor = Color.Gold;
|
||||
RemoveLastWaypoint.Enabled = false;
|
||||
|
||||
Menu.AddItem(EndPathCreation);
|
||||
EndPathCreation.ForeColor = Color.Gold;
|
||||
EndPathCreation.Enabled = false;
|
||||
|
||||
Menu.RefreshIndex();
|
||||
}
|
||||
|
||||
private static void UpdateCollectorMenuOptionsStatus()
|
||||
private static void ValidateCollectorRadiusSettings()
|
||||
{
|
||||
if (collectorWaypoint.Checked)
|
||||
if (CollectorRadius.Value > SpeedZoneRadius.Value)
|
||||
{
|
||||
collectorRadius.Enabled = true;
|
||||
speedZoneRadius.Enabled = true;
|
||||
}
|
||||
else
|
||||
while (CollectorRadius.Value > SpeedZoneRadius.Value)
|
||||
{
|
||||
collectorRadius.Enabled = false;
|
||||
speedZoneRadius.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddNewWaypoint()
|
||||
{
|
||||
var anyPathsExist = PathMainMenu.paths.Count > 0;
|
||||
var waypointPosition = MousePositionInWorld.GetPosition;
|
||||
|
||||
if (!anyPathsExist)
|
||||
{
|
||||
AddNewPathToPathsCollection(PathMainMenu.paths, 0);
|
||||
}
|
||||
else if (anyPathsExist && !PathMainMenu.paths.Any(p => p != null && p.State == State.Creating))
|
||||
{
|
||||
AddNewPathToPathsCollection(PathMainMenu.paths, PathMainMenu.paths.IndexOf(PathMainMenu.paths.Where(p => p.State == State.Finished).Last()) + 1);
|
||||
}
|
||||
|
||||
var firstNonNullPath = PathMainMenu.paths.Where(p => p != null && p.State == State.Creating).First();
|
||||
var pathIndex = PathMainMenu.paths.IndexOf(firstNonNullPath);
|
||||
var pathNumber = firstNonNullPath.Number;
|
||||
var waypointNumber = PathMainMenu.paths[pathIndex].Waypoints.Count + 1;
|
||||
DrivingFlagType drivingFlag = directWaypointBehavior.Checked ? DrivingFlagType.Direct : DrivingFlagType.Normal;
|
||||
|
||||
if (collectorWaypoint.Checked)
|
||||
{
|
||||
PathMainMenu.paths[pathIndex].Waypoints.Add(new Waypoint(firstNonNullPath, waypointNumber, waypointPosition, SetDriveSpeedForWaypoint(), drivingFlag, stopWaypointType.Checked, CreateWaypointBlip(), true, collectorRadius.Value, speedZoneRadius.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
PathMainMenu.paths[pathIndex].Waypoints.Add(new Waypoint(firstNonNullPath, waypointNumber, waypointPosition, SetDriveSpeedForWaypoint(), drivingFlag, stopWaypointType.Checked, CreateWaypointBlip()));
|
||||
}
|
||||
Game.LogTrivial($"Path {pathNumber} Waypoint {waypointNumber} added [Driving style: {drivingFlag} | Stop waypoint: {stopWaypointType.Checked} | Speed: {waypointSpeed.Value} | Collector: {collectorWaypoint.Checked}]");
|
||||
|
||||
ToggleTrafficEndPathMenuItem(pathIndex);
|
||||
collectorWaypoint.Enabled = true;
|
||||
collectorWaypoint.Checked = false;
|
||||
if (collectorWaypoint.Checked)
|
||||
{
|
||||
collectorRadius.Enabled = true;
|
||||
speedZoneRadius.Enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
collectorRadius.Enabled = false;
|
||||
speedZoneRadius.Enabled = false;
|
||||
}
|
||||
trafficRemoveWaypoint.Enabled = true;
|
||||
PathMainMenu.createNewPath.Text = $"Continue Creating Path {pathNumber}";
|
||||
|
||||
float SetDriveSpeedForWaypoint()
|
||||
{
|
||||
float convertedSpeed;
|
||||
if (SettingsMenu.speedUnits.SelectedItem == SpeedUnits.MPH)
|
||||
{
|
||||
//Logger.Log($"Original speed: {waypointSpeeds[waypointSpeed.Index]}{SettingsMenu.speedUnits.SelectedItem}");
|
||||
convertedSpeed = MathHelper.ConvertMilesPerHourToMetersPerSecond(waypointSpeed.Value);
|
||||
//Logger.Log($"Converted speed: {convertedSpeed}m/s");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Logger.Log($"Original speed: {waypointSpeeds[waypointSpeed.Index]}{SettingsMenu.speedUnits.SelectedItem}");
|
||||
convertedSpeed = MathHelper.ConvertKilometersPerHourToMetersPerSecond(waypointSpeed.Value);
|
||||
//Logger.Log($"Converted speed: {convertedSpeed}m/s");
|
||||
}
|
||||
|
||||
return convertedSpeed;
|
||||
}
|
||||
|
||||
Blip CreateWaypointBlip()
|
||||
{
|
||||
var spriteNumericalEnum = pathIndex + 17; // 17 because the numerical value of these sprites are always 17 more than the path index
|
||||
var blip = new Blip(waypointPosition)
|
||||
{
|
||||
Scale = 0.5f,
|
||||
Sprite = (BlipSprite)spriteNumericalEnum
|
||||
};
|
||||
|
||||
if (collectorWaypoint.Checked)
|
||||
{
|
||||
blip.Color = Color.Blue;
|
||||
}
|
||||
else if (stopWaypointType.Checked)
|
||||
{
|
||||
blip.Color = Color.Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
blip.Color = Color.Green;
|
||||
}
|
||||
|
||||
if (!SettingsMenu.mapBlips.Checked)
|
||||
{
|
||||
blip.Alpha = 0f;
|
||||
}
|
||||
|
||||
return blip;
|
||||
}
|
||||
}
|
||||
|
||||
private static void RemoveWaypoint()
|
||||
{
|
||||
for (int i = 0; i < PathMainMenu.paths.Count; i++)
|
||||
{
|
||||
if (PathMainMenu.paths.ElementAtOrDefault(i) != null && PathMainMenu.paths[i].State == State.Creating)
|
||||
{
|
||||
Game.LogTrivial($"[Path {i + 1}] {PathMainMenu.paths[i].Waypoints.Last().DrivingFlagType} waypoint removed");
|
||||
PathMainMenu.paths[i].Waypoints.Last().Blip.Delete();
|
||||
PathMainMenu.paths[i].Waypoints.Last().RemoveSpeedZone();
|
||||
|
||||
if (PathMainMenu.paths[i].Waypoints.Last().CollectorRadiusBlip)
|
||||
{
|
||||
PathMainMenu.paths[i].Waypoints.Last().CollectorRadiusBlip.Delete();
|
||||
}
|
||||
PathMainMenu.paths[i].Waypoints.RemoveAt(PathMainMenu.paths[i].Waypoints.IndexOf(PathMainMenu.paths[i].Waypoints.Last()));
|
||||
|
||||
ToggleTrafficEndPathMenuItem(i);
|
||||
|
||||
// If the path has no waypoints, disable the menu option to remove a waypoint
|
||||
if (PathMainMenu.paths[i].Waypoints.Count == 0)
|
||||
{
|
||||
collectorWaypoint.Checked = true;
|
||||
collectorWaypoint.Enabled = false;
|
||||
speedZoneRadius.Enabled = true;
|
||||
collectorRadius.Enabled = true;
|
||||
trafficRemoveWaypoint.Enabled = false;
|
||||
trafficEndPath.Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void EndPath()
|
||||
{
|
||||
for (int i = 0; i < PathMainMenu.paths.Count; i++)
|
||||
{
|
||||
var currentPath = PathMainMenu.paths[i];
|
||||
if (PathMainMenu.paths.ElementAtOrDefault(i) != null && currentPath.State == State.Creating)
|
||||
{
|
||||
Game.LogTrivial($"[Path Creation] Path {currentPath.Number} finished with {currentPath.Waypoints.Count} waypoints.");
|
||||
Game.DisplayNotification($"~o~Scene Manager ~g~[Success]\n~w~Path {i + 1} complete.");
|
||||
currentPath.State = State.Finished;
|
||||
currentPath.IsEnabled = true;
|
||||
currentPath.Number = i + 1;
|
||||
currentPath.LoopForVehiclesToBeDismissed();
|
||||
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
currentPath.LoopWaypointCollection();
|
||||
});
|
||||
|
||||
PathMainMenu.createNewPath.Text = "Create New Path";
|
||||
PathMainMenu.BuildPathMenu();
|
||||
PathMainMenu.pathMainMenu.RefreshIndex();
|
||||
pathCreationMenu.Clear();
|
||||
PathMainMenu.pathMainMenu.Visible = true;
|
||||
break;
|
||||
SpeedZoneRadius.ScrollToNextOption();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ToggleTrafficEndPathMenuItem(int pathIndex)
|
||||
private static void ValidateSpeedZoneRadiusSettings()
|
||||
{
|
||||
if (PathMainMenu.paths[pathIndex].Waypoints.Count > 0)
|
||||
if (SpeedZoneRadius.Value < CollectorRadius.Value)
|
||||
{
|
||||
trafficEndPath.Enabled = true;
|
||||
CollectorRadius.Value = SpeedZoneRadius.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
trafficEndPath.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddNewPathToPathsCollection(List<Path> paths, int pathIndex)
|
||||
{
|
||||
var pathNum = pathIndex + 1;
|
||||
Game.LogTrivial($"Creating path {pathNum}");
|
||||
Game.DisplayNotification($"~o~Scene Manager\n~y~[Creating]~w~ Path {pathNum} started.");
|
||||
paths.Insert(pathIndex, new Path(pathNum, State.Creating));
|
||||
trafficRemoveWaypoint.Enabled = false;
|
||||
trafficEndPath.Enabled = false;
|
||||
}
|
||||
|
||||
private static void PathCreation_OnCheckboxChanged(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked)
|
||||
{
|
||||
if(checkboxItem == collectorWaypoint)
|
||||
if(checkboxItem == CollectorWaypoint)
|
||||
{
|
||||
collectorRadius.Enabled = collectorWaypoint.Checked ? true : false;
|
||||
speedZoneRadius.Enabled = collectorWaypoint.Checked ? true : false;
|
||||
CollectorRadius.Enabled = CollectorWaypoint.Checked ? true : false;
|
||||
SpeedZoneRadius.Enabled = CollectorWaypoint.Checked ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void PathCreation_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||
{
|
||||
if (selectedItem == trafficAddWaypoint)
|
||||
if (selectedItem == AddWaypoint)
|
||||
{
|
||||
AddNewWaypoint();
|
||||
if (PathCreationState != State.Creating)
|
||||
{
|
||||
CurrentPath = PathManager.InitializeNewPath();
|
||||
PathName.Description = $"Current path name is ~b~{CurrentPath.Name}";
|
||||
PathName.Enabled = true;
|
||||
}
|
||||
|
||||
if (selectedItem == trafficRemoveWaypoint)
|
||||
{
|
||||
RemoveWaypoint();
|
||||
CurrentPath.AddWaypoint();
|
||||
PathManager.TogglePathCreationMenuItems(CurrentPath);
|
||||
}
|
||||
|
||||
if (selectedItem == trafficEndPath)
|
||||
if (selectedItem == RemoveLastWaypoint)
|
||||
{
|
||||
EndPath();
|
||||
CurrentPath.RemoveWaypoint();
|
||||
PathManager.TogglePathCreationMenuItems(CurrentPath);
|
||||
}
|
||||
|
||||
if (selectedItem == EndPathCreation)
|
||||
{
|
||||
CurrentPath.Finish();
|
||||
PathCreationState = State.Uninitialized;
|
||||
PathName.Description = $"Add your first waypoint to enable this option.";
|
||||
}
|
||||
|
||||
if(selectedItem == PathName)
|
||||
{
|
||||
CurrentPath.ChangeName();
|
||||
PathName.Description = $"Current path name is ~b~{CurrentPath.Name}";
|
||||
}
|
||||
}
|
||||
|
||||
private static void PathCreation_OnScrollerChanged(UIMenu sender, UIMenuScrollerItem scrollerItem, int first, int last)
|
||||
{
|
||||
if (scrollerItem == collectorRadius)
|
||||
if (scrollerItem == CollectorRadius)
|
||||
{
|
||||
if (collectorRadius.Value > speedZoneRadius.Value)
|
||||
{
|
||||
while (collectorRadius.Value > speedZoneRadius.Value)
|
||||
{
|
||||
speedZoneRadius.ScrollToNextOption();
|
||||
}
|
||||
}
|
||||
ValidateCollectorRadiusSettings();
|
||||
}
|
||||
|
||||
if (scrollerItem == speedZoneRadius)
|
||||
if (scrollerItem == SpeedZoneRadius)
|
||||
{
|
||||
if (speedZoneRadius.Value < collectorRadius.Value)
|
||||
{
|
||||
collectorRadius.Value = speedZoneRadius.Value;
|
||||
}
|
||||
ValidateSpeedZoneRadiusSettings();
|
||||
}
|
||||
}
|
||||
|
||||
private static void PathCreation_OnMenuOpen(UIMenu menu)
|
||||
{
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { collectorRadius, speedZoneRadius, waypointSpeed };
|
||||
RNUIMouseInputHandler.Initialize(menu, scrollerItems);
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { CollectorRadius, SpeedZoneRadius, WaypointSpeed };
|
||||
GameFiber.StartNew(() => UserInput.InitializeMenuMouseControl(menu, scrollerItems), "RNUI Mouse Input Fiber");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,417 +4,150 @@ using System.Linq;
|
|||
using Rage;
|
||||
using RAGENativeUI;
|
||||
using RAGENativeUI.Elements;
|
||||
using SceneManager.Objects;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Paths;
|
||||
using SceneManager.Utils;
|
||||
|
||||
namespace SceneManager
|
||||
namespace SceneManager.Menus
|
||||
{
|
||||
internal static class PathMainMenu
|
||||
{
|
||||
internal static List<Path> paths = new List<Path>();
|
||||
internal static List<string> importedPaths = new List<string>();
|
||||
private static string[] dismissOptions = new string[] { "From path", "From waypoint", "From world" };
|
||||
internal static UIMenu pathMainMenu = new UIMenu("Scene Manager", "~o~Path Manager Main Menu");
|
||||
internal static UIMenuItem createNewPath;
|
||||
internal static UIMenuListScrollerItem<string> importPath;
|
||||
internal static UIMenuItem deleteAllPaths = new UIMenuItem("Delete All Paths");
|
||||
internal static UIMenuNumericScrollerItem<int> editPath;
|
||||
internal static UIMenuListScrollerItem<string> directOptions = new UIMenuListScrollerItem<string>("Direct driver to path's", "", new[] { "First waypoint", "Nearest waypoint" });
|
||||
internal static UIMenuNumericScrollerItem<int> directDriver;
|
||||
internal static UIMenuListScrollerItem<string> dismissDriver = new UIMenuListScrollerItem<string>("Dismiss nearest driver", $"~b~From path: ~w~AI will be released from the path\n~b~From waypoint: ~w~AI will skip their current waypoint task\n~b~From world: ~w~AI will be removed from the world.", dismissOptions);
|
||||
internal static UIMenuCheckboxItem disableAllPaths = new UIMenuCheckboxItem("Disable All Paths", false);
|
||||
internal static UIMenu Menu { get; } = new UIMenu("Scene Manager", "~o~Path Manager");
|
||||
internal static UIMenuItem CreateNewPath { get; } = new UIMenuItem("Create New Path");
|
||||
internal static UIMenuItem ImportPath { get; } = new UIMenuItem("Import Paths", "Import saved paths from ~b~plugins/SceneManager/Saved Paths");
|
||||
internal static UIMenuItem ExportPath { get; } = new UIMenuItem("Export Paths", "Export selected paths to ~b~plugins/SceneManager/Saved Paths");
|
||||
internal static UIMenuItem DeleteAllPaths { get; } = new UIMenuItem("Delete All Paths");
|
||||
internal static UIMenuListScrollerItem<string> EditPath { get; private set; }
|
||||
internal static UIMenuCheckboxItem DisableAllPaths { get; } = new UIMenuCheckboxItem("Disable All Path Collection", false);
|
||||
|
||||
internal static void InstantiateMenu()
|
||||
internal static void Initialize()
|
||||
{
|
||||
pathMainMenu.ParentMenu = MainMenu.mainMenu;
|
||||
MenuManager.menuPool.Add(pathMainMenu);
|
||||
pathMainMenu.OnItemSelect += PathMenu_OnItemSelected;
|
||||
pathMainMenu.OnCheckboxChange += PathMenu_OnCheckboxChange;
|
||||
pathMainMenu.OnMenuOpen += PathMenu_OnMenuOpen;
|
||||
Menu.ParentMenu = MainMenu.Menu;
|
||||
MenuManager.MenuPool.Add(Menu);
|
||||
|
||||
Menu.OnItemSelect += PathMenu_OnItemSelected;
|
||||
Menu.OnCheckboxChange += PathMenu_OnCheckboxChange;
|
||||
Menu.OnMenuOpen += PathMenu_OnMenuOpen;
|
||||
}
|
||||
|
||||
internal static void BuildPathMenu()
|
||||
internal static void Build()
|
||||
{
|
||||
MenuManager.menuPool.CloseAllMenus();
|
||||
pathMainMenu.Clear();
|
||||
MenuManager.MenuPool.CloseAllMenus();
|
||||
Menu.Clear();
|
||||
|
||||
pathMainMenu.AddItem(createNewPath = new UIMenuItem("Create New Path"));
|
||||
createNewPath.ForeColor = Color.Gold;
|
||||
//pathMainMenu.AddItem(importPath = new UIMenuListScrollerItem<string>("Import Path", "Import a saved path", importedPaths));
|
||||
//importPath.ForeColor = Color.Gold;
|
||||
pathMainMenu.AddItem(editPath = new UIMenuNumericScrollerItem<int>("Edit Path", "", 1, paths.Count, 1));
|
||||
editPath.ForeColor = Color.Gold;
|
||||
pathMainMenu.AddItem(disableAllPaths);
|
||||
disableAllPaths.Enabled = true;
|
||||
pathMainMenu.AddItem(deleteAllPaths);
|
||||
deleteAllPaths.Enabled = true;
|
||||
deleteAllPaths.ForeColor = Color.Gold;
|
||||
pathMainMenu.AddItem(directOptions);
|
||||
pathMainMenu.AddItem(directDriver = new UIMenuNumericScrollerItem<int>("Direct nearest driver to path", "", 1, paths.Count, 1));
|
||||
directDriver.ForeColor = Color.Gold;
|
||||
directDriver.Enabled = true;
|
||||
pathMainMenu.AddItem(dismissDriver);
|
||||
dismissDriver.ForeColor = Color.Gold;
|
||||
Menu.AddItem(CreateNewPath);
|
||||
CreateNewPath.ForeColor = Color.Gold;
|
||||
Menu.AddItem(ImportPath);
|
||||
ImportPath.ForeColor = Color.Gold;
|
||||
ImportPath.Enabled = ImportPathMenu.ImportedFileNames.Count > 0;
|
||||
Menu.AddItem(ExportPath);
|
||||
ExportPath.ForeColor = Color.Gold;
|
||||
ExportPath.Enabled = PathManager.Paths.Any(x => x != null);
|
||||
Menu.AddItem(EditPath = new UIMenuListScrollerItem<string>("Edit Path", "Options to ~b~edit path waypoints~w~, ~b~disable the path~w~, ~b~change path name~w~, or ~b~delete the path~w~.", PathManager.Paths.Where(x => x != null).Select(x => x.Name)));
|
||||
EditPath.ForeColor = Color.Gold;
|
||||
Menu.AddItem(DisableAllPaths);
|
||||
DisableAllPaths.Enabled = true;
|
||||
Menu.AddItem(DeleteAllPaths);
|
||||
DeleteAllPaths.Enabled = true;
|
||||
DeleteAllPaths.ForeColor = Color.Gold;
|
||||
|
||||
if (paths.Count == 8)
|
||||
if (PathManager.Paths.All(x => x != null))
|
||||
{
|
||||
createNewPath.Enabled = false;
|
||||
CreateNewPath.Enabled = false;
|
||||
ImportPath.Enabled = false;
|
||||
}
|
||||
if (paths.Count == 0)
|
||||
if (PathManager.Paths.All(x => x == null))
|
||||
{
|
||||
editPath.Enabled = false;
|
||||
deleteAllPaths.Enabled = false;
|
||||
disableAllPaths.Enabled = false;
|
||||
directDriver.Enabled = false;
|
||||
EditPath.Enabled = false;
|
||||
DeleteAllPaths.Enabled = false;
|
||||
DisableAllPaths.Enabled = false;
|
||||
}
|
||||
if(ImportPathMenu.ImportedFileNames.Count == 0)
|
||||
{
|
||||
ImportPath.Enabled = false;
|
||||
}
|
||||
|
||||
MenuManager.menuPool.RefreshIndex();
|
||||
}
|
||||
|
||||
private static bool VehicleAndDriverValid(this Vehicle v)
|
||||
{
|
||||
if (v && v.HasDriver && v.Driver && v.Driver.IsAlive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void GoToEditPathMenu()
|
||||
{
|
||||
pathMainMenu.Visible = false;
|
||||
EditPathMenu.editPathMenu.Visible = true;
|
||||
}
|
||||
|
||||
private static void GoToPathCreationMenu()
|
||||
{
|
||||
if (createNewPath.Text.Contains("Continue"))
|
||||
{
|
||||
pathMainMenu.Visible = false;
|
||||
PathCreationMenu.pathCreationMenu.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
PathCreationMenu.pathCreationMenu.Clear();
|
||||
PathCreationMenu.BuildPathCreationMenu();
|
||||
pathMainMenu.Visible = false;
|
||||
PathCreationMenu.pathCreationMenu.Visible = true;
|
||||
|
||||
// For each element in paths, determine if the element exists but is not finished yet, or if it doesn't exist, create it.
|
||||
for (int i = 0; i <= paths.Count; i++)
|
||||
{
|
||||
if (paths.ElementAtOrDefault(i) != null && paths[i].State == State.Creating)
|
||||
{
|
||||
Game.DisplayNotification($"~o~Scene Manager~y~[Creating]\n~w~Resuming path {paths[i].Number}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DisableAllPaths()
|
||||
{
|
||||
if (disableAllPaths.Checked)
|
||||
{
|
||||
foreach (Path path in paths)
|
||||
{
|
||||
path.DisablePath();
|
||||
}
|
||||
Game.LogTrivial($"All paths disabled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Path path in paths)
|
||||
{
|
||||
path.EnablePath();
|
||||
}
|
||||
Game.LogTrivial($"All paths enabled.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeleteAllPaths()
|
||||
{
|
||||
for (int i = 0; i < paths.Count; i++)
|
||||
{
|
||||
DeletePath(paths[i], Delete.All);
|
||||
}
|
||||
disableAllPaths.Checked = false;
|
||||
paths.Clear();
|
||||
BuildPathMenu();
|
||||
pathMainMenu.Visible = true;
|
||||
Game.LogTrivial($"All paths deleted");
|
||||
Game.DisplayNotification($"~o~Scene Manager\n~w~All paths deleted.");
|
||||
}
|
||||
|
||||
internal static void DeletePath(Path path, Delete pathsToDelete)
|
||||
{
|
||||
//Game.LogTrivial($"Preparing to delete path {path.Number}");
|
||||
|
||||
RemoveVehiclesFromPath();
|
||||
RemoveBlipsAndYieldZones();
|
||||
|
||||
//Game.LogTrivial($"Clearing path waypoints");
|
||||
path.Waypoints.Clear();
|
||||
|
||||
// Manipulating the menu to reflect specific paths being deleted
|
||||
if (pathsToDelete == Delete.Single)
|
||||
{
|
||||
paths.Remove(path);
|
||||
UpdatePathNumbers();
|
||||
UpdatePathBlips();
|
||||
BuildPathMenu();
|
||||
pathMainMenu.Visible = true;
|
||||
Game.LogTrivial($"Path {path.Number} deleted successfully.");
|
||||
Game.DisplayNotification($"~o~Scene Manager\n~w~Path {path.Number} deleted.");
|
||||
}
|
||||
|
||||
EditPathMenu.editPathMenu.Reset(true, true);
|
||||
EditPathMenu.disablePath.Enabled = true;
|
||||
|
||||
void RemoveVehiclesFromPath()
|
||||
{
|
||||
//Game.LogTrivial($"Removing all vehicles on the path");
|
||||
var pathVehicles = path.CollectedVehicles.Where(cv => cv.Path.Number == path.Number).ToList();
|
||||
foreach (CollectedVehicle cv in pathVehicles.Where(cv => cv != null && cv.Vehicle && cv.Driver))
|
||||
{
|
||||
if (cv.StoppedAtWaypoint)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(cv.Vehicle, 1f, 1, true);
|
||||
}
|
||||
//cv.StoppedAtWaypoint = false;
|
||||
if (cv.Driver.GetAttachedBlip())
|
||||
{
|
||||
cv.Driver.GetAttachedBlip().Delete();
|
||||
}
|
||||
cv.Driver.Dismiss();
|
||||
cv.Vehicle.IsSirenOn = false;
|
||||
cv.Vehicle.IsSirenSilent = true;
|
||||
cv.Vehicle.Dismiss();
|
||||
|
||||
//Game.LogTrivial($"{cv.vehicle.Model.Name} cleared from path {cv.path}");
|
||||
path.CollectedVehicles.Remove(cv);
|
||||
}
|
||||
path.CollectedVehicles.Clear();
|
||||
}
|
||||
|
||||
void RemoveBlipsAndYieldZones()
|
||||
{
|
||||
//Game.LogTrivial($"Removing waypoint blips and yield zones.");
|
||||
foreach (Waypoint waypoint in path.Waypoints)
|
||||
{
|
||||
if (waypoint.SpeedZone != 0)
|
||||
{
|
||||
waypoint.RemoveSpeedZone();
|
||||
}
|
||||
if (waypoint.Blip)
|
||||
{
|
||||
waypoint.Blip.Delete();
|
||||
}
|
||||
if (waypoint.CollectorRadiusBlip)
|
||||
{
|
||||
waypoint.CollectorRadiusBlip.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePathBlips()
|
||||
{
|
||||
foreach (Path p in paths)
|
||||
{
|
||||
foreach (Waypoint waypoint in p.Waypoints)
|
||||
{
|
||||
var blipColor = waypoint.Blip.Color;
|
||||
waypoint.Blip.Sprite = (BlipSprite)paths.IndexOf(p) + 17;
|
||||
waypoint.Blip.Color = blipColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePathNumbers()
|
||||
{
|
||||
for (int i = 0; i < paths.Count; i++)
|
||||
{
|
||||
paths[i].Number = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DirectDriver()
|
||||
{
|
||||
var nearbyVehicle = Game.LocalPlayer.Character.GetNearbyVehicles(16).Where(v => v != Game.LocalPlayer.Character.CurrentVehicle && v.VehicleAndDriverValid()).FirstOrDefault();
|
||||
var path = paths[directDriver.Index];
|
||||
var collectedVehicle = path.CollectedVehicles.Where(cv => cv.Vehicle == nearbyVehicle).FirstOrDefault();
|
||||
var waypoints = path.Waypoints;
|
||||
var firstWaypoint = waypoints.First();
|
||||
var nearestWaypoint = waypoints.Where(wp => wp.Position.DistanceTo2D(nearbyVehicle.FrontPosition) < wp.Position.DistanceTo2D(nearbyVehicle.RearPosition)).OrderBy(wp => wp.Position.DistanceTo2D(nearbyVehicle)).FirstOrDefault();
|
||||
|
||||
if (nearbyVehicle)
|
||||
{
|
||||
var nearbyVehiclePath = paths.Where(p => p.CollectedVehicles.Any(v => v.Vehicle == nearbyVehicle)).FirstOrDefault();
|
||||
if (nearbyVehiclePath != null)
|
||||
{
|
||||
var nearbyCollectedVehicle = nearbyVehiclePath.CollectedVehicles.Where(v => v.Vehicle == nearbyVehicle).FirstOrDefault();
|
||||
if (nearbyCollectedVehicle != null)
|
||||
{
|
||||
nearbyCollectedVehicle.Dismiss(DismissOption.FromDirected, path);
|
||||
if (directOptions.SelectedItem == "First waypoint")
|
||||
{
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
nearbyCollectedVehicle.AssignWaypointTasks(path, firstWaypoint);
|
||||
//AITasking.AssignWaypointTasks(nearbyCollectedVehicle, path, firstWaypoint);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nearestWaypoint != null)
|
||||
{
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
nearbyCollectedVehicle.AssignWaypointTasks(path, nearestWaypoint);
|
||||
//AITasking.AssignWaypointTasks(nearbyCollectedVehicle, path, nearestWaypoint);
|
||||
});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The vehicle should only be added to the collection when it's not null AND if the selected item is First Waypoint OR if the selected item is nearestWaypoint AND nearestWaypoint is not null
|
||||
if (collectedVehicle == null && directOptions.SelectedItem == "First waypoint" || (directOptions.SelectedItem == "Nearest waypoint" && nearestWaypoint != null))
|
||||
{
|
||||
Game.LogTrivial($"[Direct Driver] Adding {nearbyVehicle.Model.Name} to collection.");
|
||||
path.CollectedVehicles.Add(new CollectedVehicle(nearbyVehicle, path));
|
||||
collectedVehicle = path.CollectedVehicles.Where(cv => cv.Vehicle == nearbyVehicle).FirstOrDefault();
|
||||
//Logger.Log($"Collected vehicle is {collectedVehicle.Vehicle.Model.Name}");
|
||||
}
|
||||
|
||||
if (collectedVehicle == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
collectedVehicle.Directed = true;
|
||||
collectedVehicle.Driver.Tasks.Clear();
|
||||
|
||||
//Logger.Log($"Collected vehicle properties: Dismissed [{collectedVehicle.Dismissed}], Directed [{collectedVehicle.Directed}], StopppedAtWaypoint [{collectedVehicle.StoppedAtWaypoint}]");
|
||||
if (directOptions.SelectedItem == "First waypoint")
|
||||
{
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
collectedVehicle.AssignWaypointTasks(path, firstWaypoint);
|
||||
//AITasking.AssignWaypointTasks(collectedVehicle, path, firstWaypoint);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nearestWaypoint != null)
|
||||
{
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
collectedVehicle.AssignWaypointTasks(path, nearestWaypoint);
|
||||
//AITasking.AssignWaypointTasks(collectedVehicle, path, nearestWaypoint);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DismissDriver()
|
||||
{
|
||||
var nearbyVehicle = Game.LocalPlayer.Character.GetNearbyVehicles(16).Where(v => v != Game.LocalPlayer.Character.CurrentVehicle && v.VehicleAndDriverValid()).FirstOrDefault();
|
||||
if (nearbyVehicle)
|
||||
{
|
||||
if (!paths.Any() && dismissDriver.Index == (int)DismissOption.FromWorld)
|
||||
{
|
||||
Game.LogTrivial($"Dismissed {nearbyVehicle.Model.Name} from the world");
|
||||
while (nearbyVehicle && nearbyVehicle.HasOccupants)
|
||||
{
|
||||
foreach (Ped occupant in nearbyVehicle.Occupants)
|
||||
{
|
||||
occupant.Delete();
|
||||
}
|
||||
GameFiber.Yield();
|
||||
}
|
||||
if (nearbyVehicle)
|
||||
{
|
||||
nearbyVehicle.Delete();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (Path path in paths)
|
||||
{
|
||||
var collectedVehicle = path.CollectedVehicles.Where(cv => cv.Vehicle == nearbyVehicle).FirstOrDefault();
|
||||
if (collectedVehicle != null)
|
||||
{
|
||||
collectedVehicle.Dismiss((DismissOption)dismissDriver.Index);
|
||||
break;
|
||||
}
|
||||
else if (dismissDriver.Index == (int)DismissOption.FromWorld)
|
||||
{
|
||||
Game.LogTrivial($"Dismissed {nearbyVehicle.Model.Name} from the world");
|
||||
while (nearbyVehicle && nearbyVehicle.HasOccupants)
|
||||
{
|
||||
foreach (Ped occupant in nearbyVehicle.Occupants)
|
||||
{
|
||||
occupant.Delete();
|
||||
}
|
||||
GameFiber.Yield();
|
||||
}
|
||||
if (nearbyVehicle)
|
||||
{
|
||||
nearbyVehicle.Delete();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
MenuManager.MenuPool.RefreshIndex();
|
||||
}
|
||||
|
||||
private static void PathMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||
{
|
||||
if (selectedItem == createNewPath)
|
||||
if (selectedItem == CreateNewPath)
|
||||
{
|
||||
GoToPathCreationMenu();
|
||||
}
|
||||
|
||||
if (selectedItem == editPath)
|
||||
if(selectedItem == ImportPath)
|
||||
{
|
||||
pathMainMenu.Visible = false;
|
||||
EditPathMenu.editPathMenu.Visible = true;
|
||||
GoToImportMenu();
|
||||
}
|
||||
|
||||
if (selectedItem == deleteAllPaths)
|
||||
if(selectedItem == ExportPath)
|
||||
{
|
||||
DeleteAllPaths();
|
||||
GoToExportMenu();
|
||||
}
|
||||
|
||||
if (selectedItem == directDriver)
|
||||
if (selectedItem == EditPath)
|
||||
{
|
||||
DirectDriver();
|
||||
GoToEditPathMenu();
|
||||
}
|
||||
|
||||
if (selectedItem == dismissDriver)
|
||||
if (selectedItem == DeleteAllPaths)
|
||||
{
|
||||
DismissDriver();
|
||||
PathManager.DeleteAllPaths();
|
||||
PathManager.LoadedFiles.Clear();
|
||||
MenuManager.BuildMenus();
|
||||
Menu.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void PathMenu_OnCheckboxChange(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked)
|
||||
{
|
||||
if (checkboxItem == disableAllPaths)
|
||||
if (checkboxItem == DisableAllPaths)
|
||||
{
|
||||
DisableAllPaths();
|
||||
PathManager.ToggleAllPaths(DisableAllPaths.Checked);
|
||||
}
|
||||
}
|
||||
|
||||
private static void PathMenu_OnMenuOpen(UIMenu menu)
|
||||
{
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { directOptions, directDriver, dismissDriver, editPath };
|
||||
RNUIMouseInputHandler.Initialize(menu, scrollerItems);
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { EditPath };
|
||||
GameFiber.StartNew(() => UserInput.InitializeMenuMouseControl(menu, scrollerItems), "RNUI Mouse Input Fiber");
|
||||
}
|
||||
|
||||
private static void GoToPathCreationMenu()
|
||||
{
|
||||
if (PathCreationMenu.PathCreationState == State.Creating)
|
||||
{
|
||||
Menu.Visible = false;
|
||||
PathCreationMenu.Menu.Visible = true;
|
||||
Path currentPath = PathManager.Paths.FirstOrDefault(x => x != null && x.State == State.Creating);
|
||||
Game.DisplayNotification($"~o~Scene Manager~y~[Creating]\n~w~Resuming path ~b~{currentPath.Name}~w~.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu.Visible = false;
|
||||
PathCreationMenu.Menu.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void GoToImportMenu()
|
||||
{
|
||||
Menu.Visible = false;
|
||||
ImportPathMenu.Menu.Visible = true;
|
||||
}
|
||||
|
||||
private static void GoToExportMenu()
|
||||
{
|
||||
Menu.Visible = false;
|
||||
ExportPathMenu.Menu.Visible = true;
|
||||
}
|
||||
|
||||
private static void GoToEditPathMenu()
|
||||
{
|
||||
Menu.Visible = false;
|
||||
EditPathMenu.CurrentPath = PathManager.Paths[EditPath.Index];
|
||||
EditPathMenu.Menu.Visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,113 +3,70 @@ using RAGENativeUI;
|
|||
using RAGENativeUI.Elements;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SceneManager.Objects;
|
||||
using SceneManager.Utils;
|
||||
using SceneManager.Managers;
|
||||
|
||||
namespace SceneManager
|
||||
namespace SceneManager.Menus
|
||||
{
|
||||
class SettingsMenu
|
||||
{
|
||||
internal static UIMenu settingsMenu = new UIMenu("Scene Manager", "~o~Plugin Settings");
|
||||
internal static UIMenuCheckboxItem threeDWaypoints = new UIMenuCheckboxItem("Enable 3D Waypoints", Settings.Enable3DWaypoints),
|
||||
mapBlips = new UIMenuCheckboxItem("Enable Map Blips", Settings.EnableMapBlips),
|
||||
hints = new UIMenuCheckboxItem("Enable Hints", Settings.EnableHints);
|
||||
private static SpeedUnits[] speedArray = {SpeedUnits.MPH, SpeedUnits.KPH };
|
||||
internal static UIMenuListScrollerItem<SpeedUnits> speedUnits = new UIMenuListScrollerItem<SpeedUnits>("Speed Unit of Measure", "", new[] { SpeedUnits.MPH, SpeedUnits.KPH });
|
||||
internal static UIMenuItem saveSettings = new UIMenuItem("Save settings to .ini", "Updates the plugin's .ini file with the current settings so the next time the plugin is loaded, it will use these settings.");
|
||||
internal static UIMenu Menu { get; set; } = new UIMenu("Scene Manager", "~o~Plugin Settings");
|
||||
internal static UIMenuCheckboxItem ThreeDWaypoints { get; } = new UIMenuCheckboxItem("Enable 3D Waypoints", Settings.Enable3DWaypoints);
|
||||
internal static UIMenuCheckboxItem MapBlips { get; } = new UIMenuCheckboxItem("Enable Map Blips", Settings.EnableMapBlips);
|
||||
internal static UIMenuCheckboxItem Hints { get; } = new UIMenuCheckboxItem("Enable Hints", Settings.EnableHints);
|
||||
private static SpeedUnits[] SpeedUnitsArray { get; } = { Utils.SpeedUnits.MPH, Utils.SpeedUnits.KPH };
|
||||
internal static UIMenuListScrollerItem<SpeedUnits> SpeedUnits { get; } = new UIMenuListScrollerItem<SpeedUnits>("Speed Unit of Measure", "", new[] { Utils.SpeedUnits.MPH, Utils.SpeedUnits.KPH });
|
||||
internal static UIMenuItem SaveSettings { get; } = new UIMenuItem("Save settings to .ini", "Updates the plugin's .ini file with the current settings. The next time the plugin is loaded, it will use these settings.");
|
||||
|
||||
internal static void InstantiateMenu()
|
||||
internal static void Initialize()
|
||||
{
|
||||
settingsMenu.ParentMenu = MainMenu.mainMenu;
|
||||
MenuManager.menuPool.Add(settingsMenu);
|
||||
settingsMenu.OnCheckboxChange += SettingsMenu_OnCheckboxChange;
|
||||
settingsMenu.OnScrollerChange += SettingsMenu_OnScrollerChange;
|
||||
settingsMenu.OnItemSelect += SettingsMenu_OnItemSelected;
|
||||
settingsMenu.OnMenuOpen += SettingsMenu_OnMenuOpen;
|
||||
Menu.ParentMenu = MainMenu.Menu;
|
||||
MenuManager.MenuPool.Add(Menu);
|
||||
|
||||
Menu.OnCheckboxChange += SettingsMenu_OnCheckboxChange;
|
||||
Menu.OnItemSelect += SettingsMenu_OnItemSelected;
|
||||
Menu.OnMenuOpen += SettingsMenu_OnMenuOpen;
|
||||
}
|
||||
|
||||
internal static void BuildSettingsMenu()
|
||||
internal static void Build()
|
||||
{
|
||||
settingsMenu.AddItem(threeDWaypoints);
|
||||
settingsMenu.AddItem(mapBlips);
|
||||
settingsMenu.AddItem(hints);
|
||||
settingsMenu.AddItem(speedUnits);
|
||||
speedUnits.Index = Array.IndexOf(speedArray, Settings.SpeedUnit);
|
||||
settingsMenu.AddItem(saveSettings);
|
||||
saveSettings.ForeColor = System.Drawing.Color.Gold;
|
||||
}
|
||||
Menu.Clear();
|
||||
|
||||
private static void ToggleMapBlips()
|
||||
{
|
||||
if (mapBlips.Checked)
|
||||
{
|
||||
foreach (Path path in PathMainMenu.paths)
|
||||
{
|
||||
foreach (Waypoint wp in path.Waypoints)
|
||||
{
|
||||
wp.EnableBlip();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Path path in PathMainMenu.paths)
|
||||
{
|
||||
foreach (Waypoint wp in path.Waypoints)
|
||||
{
|
||||
wp.DisableBlip();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ToggleHints()
|
||||
{
|
||||
Hints.Enabled = hints.Checked ? true : false;
|
||||
}
|
||||
|
||||
private static void ToggleSettings()
|
||||
{
|
||||
Settings.UpdateSettings(threeDWaypoints.Checked, mapBlips.Checked, hints.Checked, speedUnits.SelectedItem);
|
||||
Game.DisplayHelp($"Scene Manager settings saved");
|
||||
Menu.AddItem(ThreeDWaypoints);
|
||||
Menu.AddItem(MapBlips);
|
||||
Menu.AddItem(Hints);
|
||||
Menu.AddItem(SpeedUnits);
|
||||
SpeedUnits.Index = Array.IndexOf(SpeedUnitsArray, Settings.SpeedUnit);
|
||||
Menu.AddItem(SaveSettings);
|
||||
SaveSettings.ForeColor = System.Drawing.Color.Gold;
|
||||
}
|
||||
|
||||
private static void SettingsMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||
{
|
||||
if(selectedItem == saveSettings)
|
||||
if(selectedItem == SaveSettings)
|
||||
{
|
||||
Settings.UpdateSettings(threeDWaypoints.Checked, mapBlips.Checked, hints.Checked, speedUnits.SelectedItem);
|
||||
Settings.UpdateSettings(ThreeDWaypoints.Checked, MapBlips.Checked, Hints.Checked, SpeedUnits.SelectedItem);
|
||||
Game.DisplayHelp($"Scene Manager settings saved");
|
||||
}
|
||||
}
|
||||
|
||||
private static void SettingsMenu_OnCheckboxChange(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked)
|
||||
{
|
||||
if (checkboxItem == mapBlips)
|
||||
if (checkboxItem == MapBlips)
|
||||
{
|
||||
ToggleMapBlips();
|
||||
PathManager.ToggleBlips(MapBlips.Checked);
|
||||
}
|
||||
|
||||
if (checkboxItem == hints)
|
||||
if (checkboxItem == Hints)
|
||||
{
|
||||
Hints.Enabled = hints.Checked ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SettingsMenu_OnScrollerChange(UIMenu sender, UIMenuScrollerItem scrollerItem, int oldIndex, int newIndex)
|
||||
{
|
||||
if (scrollerItem == speedUnits)
|
||||
{
|
||||
// Clear the menu and rebuild it to reflect the menu item text change
|
||||
PathCreationMenu.pathCreationMenu.Clear();
|
||||
PathCreationMenu.BuildPathCreationMenu();
|
||||
SceneManager.Hints.Enabled = Hints.Checked ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SettingsMenu_OnMenuOpen(UIMenu menu)
|
||||
{
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { speedUnits };
|
||||
RNUIMouseInputHandler.Initialize(menu, scrollerItems);
|
||||
var scrollerItems = new List<UIMenuScrollerItem> { SpeedUnits };
|
||||
GameFiber.StartNew(() => UserInput.InitializeMenuMouseControl(menu, scrollerItems), "RNUI Mouse Input Fiber");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Rage;
|
||||
using SceneManager.Utils;
|
||||
|
||||
namespace SceneManager.Objects
|
||||
{
|
||||
class Barrier
|
||||
{
|
||||
internal Rage.Object Object { get; }
|
||||
internal Model @Model{ get; }
|
||||
internal Vector3 Position { get; }
|
||||
internal float Rotation { get; }
|
||||
internal bool Invincible { get; }
|
||||
|
||||
internal bool Immobile { get; }
|
||||
|
||||
internal Barrier(Rage.Object barrier, Vector3 barrierPosition, float barrierRotation, bool invincible, bool immobile)
|
||||
{
|
||||
Object = barrier;
|
||||
@Model = barrier.Model;
|
||||
Position = barrierPosition;
|
||||
Rotation = barrierRotation;
|
||||
Invincible = invincible;
|
||||
Immobile = immobile;
|
||||
//AddBlocker();
|
||||
}
|
||||
|
||||
private void AddBlocker()
|
||||
{
|
||||
var blocker = new Rage.Object("prop_barier_conc_01a", Position, Rotation);
|
||||
blocker.AttachTo(Object, 0, new Vector3(0, 0, 0), new Rotator());
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
while (Object)
|
||||
{
|
||||
GameFiber.Yield();
|
||||
}
|
||||
blocker.Delete();
|
||||
});
|
||||
}
|
||||
|
||||
internal void GoAround()
|
||||
{
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
var collected = new List<Vehicle>();
|
||||
while (Object)
|
||||
{
|
||||
foreach (Vehicle v in World.GetAllVehicles())
|
||||
{
|
||||
if(v && v.IsEngineOn)
|
||||
{
|
||||
if(v.HasDriver && v.Driver && v.Driver.IsAlive)
|
||||
{
|
||||
if (!collected.Contains(v))
|
||||
{
|
||||
v.Driver.Tasks.Clear();
|
||||
v.Driver.Tasks.CruiseWithVehicle(5f, (VehicleDrivingFlags)17039872);
|
||||
v.Driver.KeepTasks = true;
|
||||
collected.Add(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameFiber.Sleep(1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,454 +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 Waypoint NextWaypoint { 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, Waypoint currentWaypoint)
|
||||
{
|
||||
Vehicle = vehicle;
|
||||
Driver = Vehicle.Driver;
|
||||
Path = path;
|
||||
CurrentWaypoint = currentWaypoint;
|
||||
SetPersistence();
|
||||
}
|
||||
|
||||
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(DismissOption dismissOption = DismissOption.FromPath, Path newPath = null)
|
||||
{
|
||||
if (!Vehicle)
|
||||
{
|
||||
Game.LogTrivial($"Vehicle is null.");
|
||||
return;
|
||||
}
|
||||
if (!Driver)
|
||||
{
|
||||
Game.LogTrivial($"Driver is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dismissOption == DismissOption.FromWorld)
|
||||
{
|
||||
DismissFromWorld();
|
||||
return;
|
||||
}
|
||||
|
||||
if (dismissOption == DismissOption.FromPlayer)
|
||||
{
|
||||
Dismissed = true;
|
||||
//if (Driver)
|
||||
//{
|
||||
Driver.Dismiss();
|
||||
//}
|
||||
//if (Vehicle)
|
||||
//{
|
||||
Vehicle.Dismiss();
|
||||
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(Vehicle, 0f, 1, true);
|
||||
//}
|
||||
Path.CollectedVehicles.Remove(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if(Driver.CurrentVehicle && StoppedAtWaypoint)
|
||||
{
|
||||
StoppedAtWaypoint = false;
|
||||
Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(Driver.LastVehicle, 0f, 1, true);
|
||||
//if (Driver)
|
||||
//{
|
||||
Driver.Tasks.CruiseWithVehicle(5f);
|
||||
//}
|
||||
}
|
||||
Driver.Tasks.Clear();
|
||||
|
||||
if (dismissOption == DismissOption.FromWaypoint)
|
||||
{
|
||||
DismissFromWaypoint();
|
||||
}
|
||||
|
||||
if (dismissOption == DismissOption.FromPath)
|
||||
{
|
||||
DismissFromPath();
|
||||
}
|
||||
|
||||
if(dismissOption == DismissOption.FromDirected)
|
||||
{
|
||||
DismissFromDirect();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,261 +0,0 @@
|
|||
using Rage;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
using SceneManager.Utils;
|
||||
using System.IO;
|
||||
|
||||
namespace SceneManager.Objects
|
||||
{
|
||||
internal class Path // Change this to Public for import/export
|
||||
{
|
||||
internal int Number { get; set; }
|
||||
internal bool IsEnabled { get; set; }
|
||||
internal State State { get; set; }
|
||||
|
||||
[XmlArray("Waypoints")]
|
||||
[XmlArrayItem("Waypoint")]
|
||||
public List<Waypoint> Waypoints { get; set; } = new List<Waypoint>();
|
||||
|
||||
internal List<CollectedVehicle> CollectedVehicles = new List<CollectedVehicle>();
|
||||
private List<Vehicle> _blacklistedVehicles = new List<Vehicle>();
|
||||
|
||||
private Path() { }
|
||||
|
||||
internal Path(int pathNum, State pathState)
|
||||
{
|
||||
Number = pathNum;
|
||||
State = pathState;
|
||||
DrawLinesBetweenWaypoints();
|
||||
}
|
||||
|
||||
internal void Save(string filename)
|
||||
{
|
||||
var GAME_DIRECTORY = Directory.GetCurrentDirectory();
|
||||
var SAVED_PATHS_DIRECTORY = GAME_DIRECTORY + "/plugins/SceneManager/Saved Paths/";
|
||||
if (!Directory.Exists(SAVED_PATHS_DIRECTORY))
|
||||
{
|
||||
Directory.CreateDirectory(SAVED_PATHS_DIRECTORY);
|
||||
Game.LogTrivial($"New directory created at '/plugins/SceneManager/Saved Paths'");
|
||||
}
|
||||
PathXMLManager.SaveItemToXML(this, SAVED_PATHS_DIRECTORY + filename);
|
||||
}
|
||||
|
||||
private void LowerWaypointBlipsOpacity()
|
||||
{
|
||||
foreach (Waypoint wp in Waypoints)
|
||||
{
|
||||
wp.Blip.Alpha = 0.5f;
|
||||
if (wp.CollectorRadiusBlip)
|
||||
{
|
||||
wp.CollectorRadiusBlip.Alpha = 0.25f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RestoreWaypointBlipsOpacity()
|
||||
{
|
||||
foreach (Waypoint wp in Waypoints)
|
||||
{
|
||||
if (wp.Blip)
|
||||
{
|
||||
wp.Blip.Alpha = 1.0f;
|
||||
if (wp.CollectorRadiusBlip)
|
||||
{
|
||||
wp.CollectorRadiusBlip.Alpha = 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void DisablePath()
|
||||
{
|
||||
IsEnabled = false;
|
||||
foreach(Waypoint wp in Waypoints)
|
||||
{
|
||||
wp.RemoveSpeedZone();
|
||||
}
|
||||
if (SettingsMenu.mapBlips.Checked)
|
||||
{
|
||||
LowerWaypointBlipsOpacity();
|
||||
}
|
||||
}
|
||||
|
||||
internal void EnablePath()
|
||||
{
|
||||
IsEnabled = true;
|
||||
foreach (Waypoint wp in Waypoints)
|
||||
{
|
||||
if (wp.IsCollector)
|
||||
{
|
||||
wp.AddSpeedZone();
|
||||
}
|
||||
}
|
||||
if (SettingsMenu.mapBlips.Checked)
|
||||
{
|
||||
RestoreWaypointBlipsOpacity();
|
||||
}
|
||||
}
|
||||
|
||||
internal void DrawLinesBetweenWaypoints()
|
||||
{
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
if (SettingsMenu.threeDWaypoints.Checked && (State == State.Finished && MenuManager.menuPool.IsAnyMenuOpen()) || (State == State.Creating && PathCreationMenu.pathCreationMenu.Visible))
|
||||
{
|
||||
for (int i = 0; i < Waypoints.Count; i++)
|
||||
{
|
||||
if (i != Waypoints.Count - 1)
|
||||
{
|
||||
if (Waypoints[i + 1].IsStopWaypoint)
|
||||
{
|
||||
Debug.DrawLine(Waypoints[i].Position, Waypoints[i + 1].Position, Color.Orange);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.DrawLine(Waypoints[i].Position, Waypoints[i + 1].Position, Color.Green);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameFiber.Yield();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
internal void LoopForVehiclesToBeDismissed()
|
||||
{
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
while (PathMainMenu.paths.Contains(this))
|
||||
{
|
||||
//Logger.Log($"Dismissing unused vehicles for cleanup");
|
||||
foreach (CollectedVehicle cv in CollectedVehicles.Where(cv => cv.Vehicle))
|
||||
{
|
||||
if (!cv.Vehicle.IsDriveable || cv.Vehicle.IsUpsideDown || !cv.Vehicle.HasDriver)
|
||||
{
|
||||
if (cv.Vehicle.HasDriver)
|
||||
{
|
||||
cv.Vehicle.Driver.Dismiss();
|
||||
}
|
||||
cv.Vehicle.Dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
CollectedVehicles.RemoveAll(cv => !cv.Vehicle);
|
||||
_blacklistedVehicles.RemoveAll(v => !v);
|
||||
GameFiber.Sleep(60000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
internal void LoopWaypointCollection()
|
||||
{
|
||||
uint lastProcessTime = Game.GameTime; // Store the last time the full loop finished; this is a value in ms
|
||||
int yieldAfterChecks = 50; // How many calculations to do before yielding
|
||||
while (PathMainMenu.paths.Contains(this))
|
||||
{
|
||||
if (IsEnabled)
|
||||
{
|
||||
int checksDone = 0;
|
||||
try
|
||||
{
|
||||
foreach (Waypoint waypoint in Waypoints)
|
||||
{
|
||||
if (waypoint != null & waypoint.IsCollector)
|
||||
{
|
||||
foreach (Vehicle v in World.GetAllVehicles())
|
||||
{
|
||||
if (VehicleIsNearWaypoint(v, waypoint) && VehicleIsValidForCollection(v))
|
||||
{
|
||||
CollectedVehicle newCollectedVehicle = AddVehicleToCollection(v);
|
||||
GameFiber AssignTasksFiber = new GameFiber(() => newCollectedVehicle.AssignWaypointTasks(this, waypoint));
|
||||
//GameFiber AssignTasksFiber = new GameFiber(() => AITasking.AssignWaypointTasks(newCollectedVehicle, this, waypoint));
|
||||
AssignTasksFiber.Start();
|
||||
}
|
||||
|
||||
checksDone++; // Increment the counter inside the vehicle loop
|
||||
if (checksDone % yieldAfterChecks == 0)
|
||||
{
|
||||
GameFiber.Yield(); // Yield the game fiber after the specified number of vehicles have been checked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//return;
|
||||
}
|
||||
}
|
||||
GameFiber.Sleep((int)Math.Max(1, Game.GameTime - lastProcessTime)); // If the prior lines took more than a second to run, then you'll run again almost immediately, but if they ran fairly quickly, you can sleep the loop until the remainder of the time between checks has passed
|
||||
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)
|
||||
{
|
||||
return v.FrontPosition.DistanceTo2D(wp.Position) <= wp.CollectorRadius && Math.Abs(wp.Position.Z - v.Position.Z) < 3;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
var vehicleCollectedOnAnotherPath = PathMainMenu.paths.Any(p => p.Number != Number && p.CollectedVehicles.Any(cv => cv.Vehicle == v));
|
||||
if (vehicleCollectedOnAnotherPath)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (v.HasDriver && v.Driver)
|
||||
{
|
||||
if(!v.Driver.IsAlive)
|
||||
{
|
||||
Game.LogTrivial($"Vehicle's driver is dead.");
|
||||
_blacklistedVehicles.Add(v);
|
||||
return false;
|
||||
}
|
||||
if (v.IsPoliceVehicle && !v.Driver.IsAmbient())
|
||||
{
|
||||
_blacklistedVehicles.Add(v);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!v.HasDriver)
|
||||
{
|
||||
v.CreateRandomDriver();
|
||||
while (!v.HasDriver)
|
||||
{
|
||||
GameFiber.Yield();
|
||||
}
|
||||
if (v && v.Driver)
|
||||
{
|
||||
v.Driver.IsPersistent = true;
|
||||
v.Driver.BlockPermanentEvents = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
370
SceneManager/Paths/Path.cs
Normal file
370
SceneManager/Paths/Path.cs
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
using Rage;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
using SceneManager.Utils;
|
||||
using SceneManager.Menus;
|
||||
using System.IO;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Barriers;
|
||||
using SceneManager.Waypoints;
|
||||
using SceneManager.CollectedPeds;
|
||||
using RAGENativeUI;
|
||||
|
||||
namespace SceneManager.Paths
|
||||
{
|
||||
public class Path // Change this to Public for import/export
|
||||
{
|
||||
public string Name { get; set; }
|
||||
internal int Number { get => Array.IndexOf(PathManager.Paths, this) + 1; set { } }
|
||||
internal bool IsEnabled { get; set; }
|
||||
internal State State { get; set; }
|
||||
|
||||
[XmlArray("Waypoints")]
|
||||
[XmlArrayItem("Waypoint")]
|
||||
public List<Waypoint> Waypoints { get; set; } = new List<Waypoint>();
|
||||
[XmlArray("Barriers")]
|
||||
[XmlArrayItem("Barrier")]
|
||||
public List<Barrier> Barriers { get; set; } = new List<Barrier>();
|
||||
internal List<CollectedPed> CollectedPeds { get; } = new List<CollectedPed>();
|
||||
internal List<Vehicle> BlacklistedVehicles { get; } = new List<Vehicle>();
|
||||
|
||||
internal Path()
|
||||
{
|
||||
State = State.Creating;
|
||||
DrawLinesBetweenWaypoints();
|
||||
}
|
||||
|
||||
internal void Save()
|
||||
{
|
||||
var GAME_DIRECTORY = Directory.GetCurrentDirectory();
|
||||
var SAVED_PATHS_DIRECTORY = GAME_DIRECTORY + "/plugins/SceneManager/Saved Paths/";
|
||||
if (!Directory.Exists(SAVED_PATHS_DIRECTORY))
|
||||
{
|
||||
Directory.CreateDirectory(SAVED_PATHS_DIRECTORY);
|
||||
Game.LogTrivial($"New directory created at '/plugins/SceneManager/Saved Paths'");
|
||||
}
|
||||
|
||||
var overrides = Serializer.DefineOverrides();
|
||||
Serializer.SaveItemToXML(new List<Path> { this }, SAVED_PATHS_DIRECTORY + Name + ".xml", overrides);
|
||||
Game.LogTrivial($"Saved {Name}.xml");
|
||||
|
||||
Game.DisplayNotification($"~o~Scene Manager ~w~[~g~Success~w~]\n~w~Path ~b~{Name} ~w~exported.");
|
||||
}
|
||||
|
||||
internal void Load()
|
||||
{
|
||||
Game.DisplayHelp($"~{InstructionalKey.SymbolBusySpinner.GetId()}~ Loading ~b~{Name}~w~...");
|
||||
foreach (Waypoint waypoint in Waypoints)
|
||||
{
|
||||
waypoint.LoadFromImport(this);
|
||||
}
|
||||
|
||||
Game.LogTrivial($"This path has {Barriers.Count} barriers");
|
||||
for(int i = 0; i < Barriers.Count(); i++)
|
||||
{
|
||||
var barrier = new Barrier(Barriers[i], Barriers[i].Invincible, Barriers[i].Immobile, Barriers[i].TextureVariation, Barriers[i].LightsEnabled);
|
||||
barrier.Path = this;
|
||||
Barriers[i] = barrier;
|
||||
BarrierManager.Barriers.Add(barrier);
|
||||
}
|
||||
Rage.Native.NativeFunction.Natives.CLEAR_ALL_HELP_MESSAGES();
|
||||
DrawLinesBetweenWaypoints();
|
||||
Finish();
|
||||
}
|
||||
|
||||
internal void AddWaypoint()
|
||||
{
|
||||
DrivingFlagType drivingFlag = PathCreationMenu.DirectWaypoint.Checked ? DrivingFlagType.Direct : DrivingFlagType.Normal;
|
||||
float speed = HelperMethods.ConvertDriveSpeedForWaypoint(PathCreationMenu.WaypointSpeed.Value);
|
||||
|
||||
if (PathCreationMenu.CollectorWaypoint.Checked)
|
||||
{
|
||||
new Waypoint(this, UserInput.PlayerMousePosition, speed, drivingFlag, PathCreationMenu.StopWaypoint.Checked, true, PathCreationMenu.CollectorRadius.Value, PathCreationMenu.SpeedZoneRadius.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
new Waypoint(this, UserInput.PlayerMousePosition, speed, drivingFlag, PathCreationMenu.StopWaypoint.Checked);
|
||||
}
|
||||
}
|
||||
|
||||
internal void RemoveWaypoint()
|
||||
{
|
||||
Waypoint lastWaypoint = Waypoints.Last();
|
||||
lastWaypoint.Delete();
|
||||
Waypoints.Remove(lastWaypoint);
|
||||
}
|
||||
|
||||
internal void Finish()
|
||||
{
|
||||
Game.LogTrivial($"[Path Creation] Path \"{Name}\" finished with {Waypoints.Count} waypoints.");
|
||||
Game.DisplayNotification($"~o~Scene Manager ~w~[~g~Success~w~]\n~w~Path ~b~{Name} ~w~complete.");
|
||||
State = State.Finished;
|
||||
IsEnabled = true;
|
||||
Waypoints.ForEach(x => x.EnableBlip());
|
||||
//GameFiber.StartNew(() => LoopForVehiclesToBeDismissed(), "Vehicle Cleanup Loop Fiber");
|
||||
GameFiber.StartNew(() => LoopWaypointCollection(), "Waypoint Collection Loop Fiber");
|
||||
|
||||
PathMainMenu.CreateNewPath.Text = "Create New Path";
|
||||
PathMainMenu.Build();
|
||||
PathMainMenu.Menu.Visible = true;
|
||||
|
||||
MainMenu.Build();
|
||||
DriverMenu.Build();
|
||||
PathCreationMenu.Build();
|
||||
ExportPathMenu.Build();
|
||||
BarrierMenu.Build();
|
||||
}
|
||||
|
||||
internal void LowerWaypointBlipsOpacity()
|
||||
{
|
||||
foreach (Waypoint wp in Waypoints)
|
||||
{
|
||||
wp.Blip.Alpha = 0.5f;
|
||||
if (wp.CollectorRadiusBlip)
|
||||
{
|
||||
wp.CollectorRadiusBlip.Alpha = 0.25f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RestoreWaypointBlipsOpacity()
|
||||
{
|
||||
foreach (Waypoint wp in Waypoints)
|
||||
{
|
||||
if (wp.Blip)
|
||||
{
|
||||
wp.Blip.Alpha = 1.0f;
|
||||
if (wp.CollectorRadiusBlip)
|
||||
{
|
||||
wp.CollectorRadiusBlip.Alpha = 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void Disable()
|
||||
{
|
||||
IsEnabled = false;
|
||||
foreach(Waypoint wp in Waypoints)
|
||||
{
|
||||
wp.RemoveSpeedZone();
|
||||
}
|
||||
if (SettingsMenu.MapBlips.Checked)
|
||||
{
|
||||
LowerWaypointBlipsOpacity();
|
||||
}
|
||||
Game.LogTrivial($"Path \"{Name}\" disabled.");
|
||||
}
|
||||
|
||||
internal void Enable()
|
||||
{
|
||||
IsEnabled = true;
|
||||
foreach (Waypoint wp in Waypoints)
|
||||
{
|
||||
if (wp.IsCollector)
|
||||
{
|
||||
wp.AddSpeedZone();
|
||||
}
|
||||
}
|
||||
if (SettingsMenu.MapBlips.Checked)
|
||||
{
|
||||
RestoreWaypointBlipsOpacity();
|
||||
}
|
||||
Game.LogTrivial($"Path \"{Name}\" enabled.");
|
||||
}
|
||||
|
||||
internal void DrawLinesBetweenWaypoints()
|
||||
{
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
if (SettingsMenu.ThreeDWaypoints.Checked && (State == State.Finished && MenuManager.MenuPool.IsAnyMenuOpen()) || (State == State.Creating && PathCreationMenu.Menu.Visible))
|
||||
{
|
||||
for (int i = 0; i < Waypoints.Count; i++)
|
||||
{
|
||||
if (i != Waypoints.Count - 1)
|
||||
{
|
||||
if (Waypoints[i + 1].IsStopWaypoint)
|
||||
{
|
||||
Debug.DrawLine(Waypoints[i].Position, Waypoints[i + 1].Position, Color.Orange);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.DrawLine(Waypoints[i].Position, Waypoints[i + 1].Position, Color.Green);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameFiber.Yield();
|
||||
}
|
||||
}, "3D Waypoint Line Drawing Fiber");
|
||||
}
|
||||
|
||||
//internal void LoopForVehiclesToBeDismissed()
|
||||
//{
|
||||
// while (PathManager.Paths.Contains(this))
|
||||
// {
|
||||
// foreach (CollectedPed cp in CollectedPeds.Where(x => x && x.CurrentVehicle && (!x.CurrentVehicle.IsDriveable || x.CurrentVehicle.IsUpsideDown || !x.CurrentVehicle.HasDriver)))
|
||||
// {
|
||||
// if (cp.CurrentVehicle.HasDriver)
|
||||
// {
|
||||
// cp.CurrentVehicle.Driver.Dismiss();
|
||||
// }
|
||||
// cp.CurrentVehicle.Dismiss();
|
||||
// }
|
||||
|
||||
// CollectedPeds.RemoveAll(cp => !cp || !cp.CurrentVehicle);
|
||||
// BlacklistedVehicles.RemoveAll(v => !v);
|
||||
// GameFiber.Sleep(60000);
|
||||
// }
|
||||
//}
|
||||
|
||||
internal void CleanupInvalidPedsAndVehicles()
|
||||
{
|
||||
var pedsToDismiss = CollectedPeds.Where(x => x && x.CurrentVehicle && (!x.CurrentVehicle.IsDriveable || x.CurrentVehicle.IsUpsideDown || !x.CurrentVehicle.HasDriver)).ToList();
|
||||
foreach (CollectedPed cp in pedsToDismiss)
|
||||
{
|
||||
//if (cp.CurrentVehicle.HasDriver)
|
||||
//{
|
||||
// cp.CurrentVehicle.Driver.Dismiss();
|
||||
//}
|
||||
//cp.CurrentVehicle.Dismiss();
|
||||
cp.Dismiss();
|
||||
}
|
||||
|
||||
CollectedPeds.RemoveAll(cp => !cp || !cp.CurrentVehicle);
|
||||
BlacklistedVehicles.RemoveAll(v => !v);
|
||||
}
|
||||
|
||||
internal void LoopWaypointCollection()
|
||||
{
|
||||
uint lastProcessTime = Game.GameTime; // Store the last time the full loop finished; this is a value in ms
|
||||
int yieldAfterChecks = 50; // How many calculations to do before yielding
|
||||
while (PathManager.Paths.Contains(this))
|
||||
{
|
||||
//Game.DisplaySubtitle($"CollectedPeds: ~b~{CollectedPeds.Count} ~w~| Persistent Peds: ~b~{World.GetAllPeds().Count(p => p.IsPersistent)}");
|
||||
|
||||
//Game.LogTrivial($"Looping for waypoint collection");
|
||||
//GameFiber.SleepUntil(() => IsEnabled, 0);
|
||||
if(!IsEnabled)
|
||||
{
|
||||
lastProcessTime = Game.GameTime;
|
||||
GameFiber.Yield();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (State == State.Deleting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int checksDone = 0;
|
||||
var collectorWaypoints = Waypoints.Where(x => x.IsCollector);
|
||||
|
||||
foreach (Waypoint waypoint in collectorWaypoints.ToList())
|
||||
{
|
||||
foreach (Vehicle vehicle in World.GetAllVehicles())
|
||||
{
|
||||
if(!vehicle)
|
||||
{
|
||||
lastProcessTime = Game.GameTime;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vehicle.IsNearCollectorWaypoint(waypoint) && vehicle.IsValidForPathCollection(this))
|
||||
{
|
||||
while (!vehicle.Driver)
|
||||
{
|
||||
GameFiber.Yield();
|
||||
if (!vehicle)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!vehicle)
|
||||
{
|
||||
lastProcessTime = Game.GameTime;
|
||||
continue;
|
||||
}
|
||||
CollectedPeds.Add(new CollectedPed(vehicle.Driver, this, waypoint));
|
||||
}
|
||||
|
||||
checksDone++; // Increment the counter inside the vehicle loop
|
||||
if (checksDone % yieldAfterChecks == 0)
|
||||
{
|
||||
GameFiber.Yield(); // Yield the game fiber after the specified number of vehicles have been checked
|
||||
if(State == State.Deleting)
|
||||
{
|
||||
Game.LogTrivial($"Path deleted, ending waypoint collection.");
|
||||
return;
|
||||
}
|
||||
CleanupInvalidPedsAndVehicles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameFiber.Sleep((int)Math.Max(1, Game.GameTime - lastProcessTime)); // If the prior lines took more than a second to run, then you'll run again almost immediately, but if they ran fairly quickly, you can sleep the loop until the remainder of the time between checks has passed
|
||||
lastProcessTime = Game.GameTime;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Delete()
|
||||
{
|
||||
var pathIndex = Array.IndexOf(PathManager.Paths, this);
|
||||
State = State.Deleting;
|
||||
RemoveAllBarriers();
|
||||
DismissCollectedDrivers();
|
||||
RemoveAllWaypoints();
|
||||
PathManager.Paths[pathIndex] = null;
|
||||
Game.LogTrivial($"Path \"{Name}\" deleted.");
|
||||
}
|
||||
|
||||
private void DismissCollectedDrivers()
|
||||
{
|
||||
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 (CollectedPed collectedPed in collectedPedsCopy.Where(x => x != null && x && x.CurrentVehicle))
|
||||
{
|
||||
collectedPed.Dismiss();
|
||||
CollectedPeds.Remove(collectedPed);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveAllWaypoints()
|
||||
{
|
||||
Waypoints.ForEach(x => x.Delete());
|
||||
Waypoints.Clear();
|
||||
}
|
||||
|
||||
private void RemoveAllBarriers()
|
||||
{
|
||||
Game.LogTrivial($"Deleting barriers.");
|
||||
foreach(Barrier barrier in Barriers)
|
||||
{
|
||||
barrier.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
internal void ChangeName()
|
||||
{
|
||||
var pathName = UserInput.PromptPlayerForFileName("Type the name you would like for your path", $"{Name}", 100);
|
||||
if (string.IsNullOrWhiteSpace(pathName))
|
||||
{
|
||||
Game.DisplayHelp($"Invalid path name given. Name cannot be null, empty, or consist of just white spaces. Defaulting to ~b~\"{Name}\"");
|
||||
Game.LogTrivial($"Invalid path name given. Name cannot be null, empty, or consist of just white spaces. Defaulting to \"{Name}\"");
|
||||
return;
|
||||
}
|
||||
if (PathManager.Paths.Any(x => x != null && x.Name == pathName))
|
||||
{
|
||||
Game.DisplayHelp($"Invalid path name given. A path with that name already exists. Defaulting to ~b~\"{Name}\"");
|
||||
Game.LogTrivial($"Invalid path name given. A path with that name already exists. Defaulting to \"{Name}\"");
|
||||
return;
|
||||
}
|
||||
|
||||
Name = pathName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("2.2.2.0")]
|
||||
[assembly: AssemblyFileVersion("2.2.2.0")]
|
||||
[assembly: AssemblyVersion("2.3.0.0")]
|
||||
[assembly: AssemblyFileVersion("2.3.0.0")]
|
||||
|
|
|
|||
|
|
@ -36,13 +36,11 @@
|
|||
<Reference Include="InputManager, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\InputManager.1.0.0\lib\InputManager.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="RAGENativeUI">
|
||||
<HintPath>D:\Program Files\Rockstar Games\Grand Theft Auto V\RAGENativeUI.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
<Reference Include="RAGENativeUI, Version=1.8.0.0, Culture=neutral, processorArchitecture=AMD64">
|
||||
<HintPath>..\packages\RAGENativeUI.1.8.0\lib\net472\RAGENativeUI.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="RagePluginHook">
|
||||
<HintPath>..\..\Modding Resources\References\RagePluginHook.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
<Reference Include="RagePluginHook, Version=0.0.0.0, Culture=neutral, processorArchitecture=AMD64">
|
||||
<HintPath>..\packages\RagePluginHook.1.86.1\lib\net472\RagePluginHook.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
|
|
@ -64,35 +62,43 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Menus\DriverMenu.cs" />
|
||||
<Compile Include="Menus\ExportPathMenu.cs" />
|
||||
<Compile Include="Menus\ImportPathMenu.cs" />
|
||||
<Compile Include="SettingsValidator.cs" />
|
||||
<Compile Include="Managers\BarrierManager.cs" />
|
||||
<Compile Include="Utils\ConsoleCommands.cs" />
|
||||
<Compile Include="Utils\DependencyChecker.cs" />
|
||||
<Compile Include="Utils\DismissDriver.cs" />
|
||||
<Compile Include="Utils\Enums.cs" />
|
||||
<Compile Include="Utils\Extensions.cs" />
|
||||
<Compile Include="Utils\MousePositionInWorld.cs" />
|
||||
<Compile Include="Objects\CollectedVehicle.cs" />
|
||||
<Compile Include="Objects\Barrier.cs" />
|
||||
<Compile Include="Hints.cs" />
|
||||
<Compile Include="CollectedPeds\CollectedPed.cs" />
|
||||
<Compile Include="Barriers\Barrier.cs" />
|
||||
<Compile Include="Utils\HelperMethods.cs" />
|
||||
<Compile Include="Utils\Hints.cs" />
|
||||
<Compile Include="Menus\BarrierMenu.cs" />
|
||||
<Compile Include="Menus\EditPathMenu.cs" />
|
||||
<Compile Include="Menus\EditWaypointMenu.cs" />
|
||||
<Compile Include="EntryPoint.cs" />
|
||||
<Compile Include="Utils\GetUserInput.cs" />
|
||||
<Compile Include="Managers\PathManager.cs" />
|
||||
<Compile Include="Utils\DirectDriver.cs" />
|
||||
<Compile Include="Utils\UserInput.cs" />
|
||||
<Compile Include="Menus\MainMenu.cs" />
|
||||
<Compile Include="Menus\MenuManager.cs" />
|
||||
<Compile Include="Objects\Path.cs" />
|
||||
<Compile Include="Managers\MenuManager.cs" />
|
||||
<Compile Include="Paths\Path.cs" />
|
||||
<Compile Include="Menus\PathCreationMenu.cs" />
|
||||
<Compile Include="Utils\PathXMLManager.cs" />
|
||||
<Compile Include="Utils\PNWUserInput.cs" />
|
||||
<Compile Include="Utils\Serializer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Menus\PathMainMenu.cs" />
|
||||
<Compile Include="Menus\SettingsMenu.cs" />
|
||||
<Compile Include="Utils\RNUIMouseInputHandler.cs" />
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="Objects\Waypoint.cs" />
|
||||
<Compile Include="Waypoints\Waypoint.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="AfterCompile">
|
||||
<Exec Command="if "$(ConfigurationName)" == "Release" ("$(ProjectDir)_ConfuserEx\Confuser.CLI.exe" "$(ProjectDir)_ConfuserEx\c.crproj")
" />
|
||||
|
|
|
|||
|
|
@ -3,39 +3,42 @@ using System.Collections.Generic;
|
|||
using System.Windows.Forms;
|
||||
using SceneManager.Utils;
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
using System.Linq;
|
||||
using System.Xml.Serialization;
|
||||
using SceneManager.Managers;
|
||||
|
||||
namespace SceneManager
|
||||
{
|
||||
// The only reason this class should change is to modify any plugin settings
|
||||
internal static class Settings
|
||||
{
|
||||
internal static readonly InitializationFile ini = new InitializationFile("Plugins/SceneManager.ini");
|
||||
|
||||
// Keybindings
|
||||
internal static Keys ToggleKey = Keys.T;
|
||||
internal static Keys ModifierKey = Keys.LShiftKey;
|
||||
internal static ControllerButtons ToggleButton = ControllerButtons.Y;
|
||||
internal static ControllerButtons ModifierButton = ControllerButtons.A;
|
||||
internal static Keys ToggleKey { get; private set; } = Keys.T;
|
||||
internal static Keys ModifierKey { get; private set; } = Keys.LShiftKey;
|
||||
internal static ControllerButtons ToggleButton { get; private set; } = ControllerButtons.Y;
|
||||
internal static ControllerButtons ModifierButton { get; private set; } = ControllerButtons.A;
|
||||
|
||||
// Plugin Settings
|
||||
internal static bool Enable3DWaypoints = true;
|
||||
internal static bool EnableMapBlips = true;
|
||||
internal static bool EnableHints = true;
|
||||
internal static SpeedUnits SpeedUnit = SpeedUnits.MPH;
|
||||
internal static float BarrierPlacementDistance = 30f;
|
||||
internal static bool EnableAdvancedBarricadeOptions = false;
|
||||
internal static bool EnableBarrierLightsDefaultOn = false;
|
||||
internal static bool Enable3DWaypoints { get; private set; } = true;
|
||||
internal static bool EnableMapBlips { get; private set; } = true;
|
||||
internal static bool EnableHints { get; private set; } = true;
|
||||
internal static SpeedUnits SpeedUnit { get; private set; } = SpeedUnits.MPH;
|
||||
internal static float BarrierPlacementDistance { get; private set; } = 30f;
|
||||
internal static bool EnableAdvancedBarricadeOptions { get; private set; } = false;
|
||||
internal static bool EnableBarrierLightsDefaultOn { get; private set; } = false;
|
||||
|
||||
// Default Waypoint Settings
|
||||
internal static int CollectorRadius = 1;
|
||||
internal static int SpeedZoneRadius = 5;
|
||||
internal static bool StopWaypoint = false;
|
||||
internal static bool DirectDrivingBehavior = false;
|
||||
internal static int WaypointSpeed = 5;
|
||||
internal static int CollectorRadius { get; set; } = 1;
|
||||
internal static int SpeedZoneRadius { get; set; } = 5;
|
||||
internal static bool StopWaypoint { get; set; } = false;
|
||||
internal static bool DirectDrivingBehavior { get; set; } = false;
|
||||
internal static int WaypointSpeed { get; set; } = 5;
|
||||
|
||||
// Barriers
|
||||
internal static Dictionary<string, Model> barriers = new Dictionary<string, Model>();
|
||||
//internal static List<string> barrierKeys = new List<string>();
|
||||
//internal static List<Model> barrierValues = new List<Model>();
|
||||
internal static Dictionary<string, Model> BarrierModels { get; private set; } = new Dictionary<string, Model>();
|
||||
|
||||
internal static void LoadSettings()
|
||||
{
|
||||
|
|
@ -63,77 +66,9 @@ namespace SceneManager
|
|||
StopWaypoint = ini.ReadBoolean("Default Waypoint Settings", "StopWaypoint", false);
|
||||
DirectDrivingBehavior = ini.ReadBoolean("Default Waypoint Settings", "DirectDrivingBehavior", false);
|
||||
WaypointSpeed = ini.ReadInt32("Default Waypoint Settings", "WaypointSpeed", 5);
|
||||
CheckForValidWaypointSettings();
|
||||
|
||||
// Barriers
|
||||
foreach(string displayName in ini.GetKeyNames("Barriers"))
|
||||
{
|
||||
var model = new Model(ini.ReadString("Barriers", displayName.Trim()));
|
||||
if (model.IsValid)
|
||||
{
|
||||
barriers.Add(displayName, model);
|
||||
//barrierKeys.Add(key.Trim());
|
||||
//barrierValues.Add(model);
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.LogTrivial($"{model.Name} is not valid.");
|
||||
}
|
||||
}
|
||||
|
||||
//ImportPaths();
|
||||
|
||||
void CheckForValidWaypointSettings()
|
||||
{
|
||||
if(CollectorRadius > 50 || CollectorRadius < 1)
|
||||
{
|
||||
CollectorRadius = 1;
|
||||
Game.LogTrivial($"Invalid value for CollectorRadius in user settings, resetting to default.");
|
||||
}
|
||||
if(SpeedZoneRadius > 200 || SpeedZoneRadius < 5)
|
||||
{
|
||||
SpeedZoneRadius = 5;
|
||||
Game.LogTrivial($"Invalid value for SpeedZoneRadius in user settings, resetting to default.");
|
||||
}
|
||||
if (CollectorRadius > SpeedZoneRadius)
|
||||
{
|
||||
CollectorRadius = 1;
|
||||
SpeedZoneRadius = 5;
|
||||
Game.LogTrivial($"CollectorRadius is greater than SpeedZoneRadius in user settings, resetting to defaults.");
|
||||
}
|
||||
if (WaypointSpeed > 100 || WaypointSpeed < 5)
|
||||
{
|
||||
WaypointSpeed = 5;
|
||||
Game.LogTrivial($"Invalid value for WaypointSpeed in user settings, resetting to default.");
|
||||
}
|
||||
}
|
||||
|
||||
void ImportPaths()
|
||||
{
|
||||
//read each file name in Saved Paths
|
||||
var GAME_DIRECTORY = Directory.GetCurrentDirectory();
|
||||
var SAVED_PATHS_DIRECTORY = GAME_DIRECTORY + "/plugins/SceneManager/Saved Paths/";
|
||||
if (!Directory.Exists(SAVED_PATHS_DIRECTORY))
|
||||
{
|
||||
Game.LogTrivial($"Directory '/plugins/SceneManager/Saved Paths' does not exist. No paths available to import.");
|
||||
return;
|
||||
}
|
||||
|
||||
//add file name to PathMainMenu.importedPaths
|
||||
var paths = Directory.GetFiles(SAVED_PATHS_DIRECTORY);
|
||||
if (paths.Length == 0)
|
||||
{
|
||||
Game.LogTrivial($"No saved paths found.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string path in paths)
|
||||
{
|
||||
Game.LogTrivial($"Path to import: {Path.GetFileName(path)}");
|
||||
|
||||
// Check if XML is valid before actually importing
|
||||
}
|
||||
}
|
||||
SettingsValidator.ValidateWaypointSettings();
|
||||
SettingsValidator.ValidateBarrierSettings(ini);
|
||||
}
|
||||
|
||||
internal static void UpdateSettings(bool threeDWaypointsEnabled, bool mapBlipsEnabled, bool hintsEnabled, SpeedUnits unit)
|
||||
|
|
|
|||
54
SceneManager/SettingsValidator.cs
Normal file
54
SceneManager/SettingsValidator.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
using Rage;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SceneManager
|
||||
{
|
||||
// The only reason this class should change is to modify how settings are validated
|
||||
internal class SettingsValidator
|
||||
{
|
||||
internal static void ValidateWaypointSettings()
|
||||
{
|
||||
if (Settings.CollectorRadius > 50 || Settings.CollectorRadius < 1)
|
||||
{
|
||||
Settings.CollectorRadius = 1;
|
||||
Game.LogTrivial($"Invalid value for CollectorRadius in user settings, resetting to default.");
|
||||
}
|
||||
if (Settings.SpeedZoneRadius > 200 || Settings.SpeedZoneRadius < 5)
|
||||
{
|
||||
Settings.SpeedZoneRadius = 5;
|
||||
Game.LogTrivial($"Invalid value for SpeedZoneRadius in user settings, resetting to default.");
|
||||
}
|
||||
if (Settings.CollectorRadius > Settings.SpeedZoneRadius)
|
||||
{
|
||||
Settings.CollectorRadius = 1;
|
||||
Settings.SpeedZoneRadius = 5;
|
||||
Game.LogTrivial($"CollectorRadius is greater than SpeedZoneRadius in user settings, resetting to defaults.");
|
||||
}
|
||||
if (Settings.WaypointSpeed > 100 || Settings.WaypointSpeed < 5)
|
||||
{
|
||||
Settings.WaypointSpeed = 5;
|
||||
Game.LogTrivial($"Invalid value for WaypointSpeed in user settings, resetting to default.");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ValidateBarrierSettings(InitializationFile ini)
|
||||
{
|
||||
foreach (string displayName in ini.GetKeyNames("Barriers"))
|
||||
{
|
||||
var model = new Model(ini.ReadString("Barriers", displayName.Trim()));
|
||||
if (model.IsValid)
|
||||
{
|
||||
Settings.BarrierModels.Add(displayName, model);
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.LogTrivial($"{model.Name} is not valid.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,26 +2,26 @@
|
|||
using Rage.Attributes;
|
||||
using Rage.ConsoleCommands.AutoCompleters;
|
||||
using System.Linq;
|
||||
using SceneManager.Objects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Paths;
|
||||
|
||||
namespace SceneManager.Utils
|
||||
{
|
||||
public static class ConsoleCommands
|
||||
internal static class ConsoleCommands
|
||||
{
|
||||
[ConsoleCommand]
|
||||
public static void Command_ShowCollectedVehicleInfo([ConsoleCommandParameter(AutoCompleterType = typeof(ConsoleCommandAutoCompleterVehicle))] Vehicle vehicle)
|
||||
[ConsoleCommand("ShowCollectedVehicleInfo")]
|
||||
internal static void Command_ShowCollectedVehicleInfo([ConsoleCommandParameter(AutoCompleterType = typeof(ConsoleCommandAutoCompleterVehicle), Name = "ShowCollectedVehicleInfo")] Vehicle vehicle)
|
||||
{
|
||||
foreach(Path path in PathMainMenu.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)
|
||||
{
|
||||
Game.LogTrivial($"Vehicle: {collectedVehicle.Vehicle.Model.Name} [{collectedVehicle.Vehicle.Handle}]");
|
||||
Rage.Native.NativeFunction.Natives.xA6E9C38DB51D7748(collectedVehicle.Vehicle, out uint script);
|
||||
Game.LogTrivial($"Vehicle: {collectedVehicle.CurrentVehicle.Model.Name} [{collectedVehicle.CurrentVehicle.Handle}]");
|
||||
Rage.Native.NativeFunction.Natives.xA6E9C38DB51D7748(collectedVehicle.CurrentVehicle, out uint 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($"Current waypoint: {collectedVehicle.CurrentWaypoint.Number}");
|
||||
Game.LogTrivial($"StoppedAtWaypoint: {collectedVehicle.StoppedAtWaypoint}");
|
||||
|
|
@ -29,18 +29,18 @@ namespace SceneManager.Utils
|
|||
Game.LogTrivial($"ReadyForDirectTasks: {collectedVehicle.ReadyForDirectTasks}");
|
||||
Game.LogTrivial($"Directed: {collectedVehicle.Directed}");
|
||||
Game.LogTrivial($"Dismissed: {collectedVehicle.Dismissed}");
|
||||
Game.LogTrivial($"Task status: {collectedVehicle.Driver.Tasks.CurrentTaskStatus}");
|
||||
Game.LogTrivial($"Task status: {collectedVehicle.Tasks.CurrentTaskStatus}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
Game.LogTrivial($"{vehicle.Model.Name} [{vehicle.Handle}] was not found collected by any path.");
|
||||
}
|
||||
|
||||
[ConsoleCommand]
|
||||
public static void Command_GetPedsActiveTasks([ConsoleCommandParameter(AutoCompleterType = typeof(ConsoleCommandAutoCompleterPedAliveOnly))] Ped ped)
|
||||
[ConsoleCommand("GetPedsActiveTasks")]
|
||||
internal static void Command_GetPedsActiveTasks([ConsoleCommandParameter(AutoCompleterType = typeof(ConsoleCommandAutoCompleterPedAliveOnly), Name = "GetPedsActiveTasks")] Ped ped)
|
||||
{
|
||||
var tasks = new List<PedTask>();
|
||||
foreach (PedTask task in (PedTask[])Enum.GetValues(typeof(PedTask)))
|
||||
var tasks = (PedTask[])Enum.GetValues(typeof(PedTask));
|
||||
foreach (PedTask task in tasks)
|
||||
{
|
||||
if(Rage.Native.NativeFunction.Natives.GET_IS_TASK_ACTIVE<bool>(ped, (int)task))
|
||||
{
|
||||
|
|
@ -48,5 +48,32 @@ namespace SceneManager.Utils
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("DeleteVehicle")]
|
||||
internal static void Command_DeleteVehicleSM([ConsoleCommandParameter(AutoCompleterType = typeof(ConsoleCommandAutoCompleterVehicle), Name = "Vehicle")] Vehicle vehicle)
|
||||
{
|
||||
if (vehicle)
|
||||
{
|
||||
vehicle.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("DeletePed")]
|
||||
internal static void Command_DeletePedSM([ConsoleCommandParameter(AutoCompleterType = typeof(ConsoleCommandAutoCompleterPed), Name = "Ped")] Ped ped)
|
||||
{
|
||||
if (ped && ped != Game.LocalPlayer.Character)
|
||||
{
|
||||
ped.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand("GetNumberOfVehiclesOnPath")]
|
||||
internal static void Command_GetNumberOfVehiclesOnPath()
|
||||
{
|
||||
foreach(Path path in PathManager.Paths.Where(x => x != null))
|
||||
{
|
||||
Game.LogTrivial($"Path \"{path.Name}\" has {path.CollectedPeds.Count} collected peds.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
63
SceneManager/Utils/DependencyChecker.cs
Normal file
63
SceneManager/Utils/DependencyChecker.cs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
using Rage;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SceneManager.Utils
|
||||
{
|
||||
internal class DependencyChecker
|
||||
{
|
||||
internal static bool DependenciesInstalled()
|
||||
{
|
||||
if (!InputManagerChecker() || !CheckRNUIVersion())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CheckRNUIVersion()
|
||||
{
|
||||
var directory = Directory.GetCurrentDirectory();
|
||||
var exists = File.Exists(directory + @"\RAGENativeUI.dll");
|
||||
if (!exists)
|
||||
{
|
||||
Game.LogTrivial($"RNUI was not found in the user's GTA V directory.");
|
||||
Game.DisplayNotification($"~o~Scene Manager ~r~[Error]\n~w~RAGENativeUI.dll was not found in your GTA V directory. Please install RAGENativeUI and try again.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var userVersion = Assembly.LoadFrom(directory + @"\RAGENativeUI.dll").GetName().Version;
|
||||
Version requiredMinimumVersion = new Version("1.7.0.0");
|
||||
if (userVersion >= requiredMinimumVersion)
|
||||
{
|
||||
Game.LogTrivial($"User's RNUI version: {userVersion}");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.DisplayNotification($"~o~Scene Manager~r~[Error]\n~w~Your RAGENativeUI.dll version is below 1.7. Please update RAGENativeUI and try again.");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static bool InputManagerChecker()
|
||||
{
|
||||
var directory = Directory.GetCurrentDirectory();
|
||||
var exists = File.Exists(directory + @"\InputManager.dll");
|
||||
if (!exists)
|
||||
{
|
||||
Game.LogTrivial($"InputManager was not found in the user's GTA V directory.");
|
||||
Game.DisplayNotification($"~o~Scene Manager ~r~[Error]\n~w~InputManager.dll was not found in your GTA V directory. Please install InputManager.dll and try again.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
78
SceneManager/Utils/DirectDriver.cs
Normal file
78
SceneManager/Utils/DirectDriver.cs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
using Rage;
|
||||
using RAGENativeUI.Elements;
|
||||
using SceneManager.CollectedPeds;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Paths;
|
||||
using SceneManager.Waypoints;
|
||||
using System.Linq;
|
||||
|
||||
namespace SceneManager.Utils
|
||||
{
|
||||
// The only reason this class should change is to modify how vehicles are directed to paths.
|
||||
internal static class DirectDriver
|
||||
{
|
||||
internal static bool ValidateOptions(UIMenuListScrollerItem<string> menuItem, Path path, out Vehicle vehicle, out Waypoint waypoint)
|
||||
{
|
||||
var nearbyVehicle = Game.LocalPlayer.Character.GetNearbyVehicles(16).FirstOrDefault(v => v != Game.LocalPlayer.Character.CurrentVehicle && v.VehicleAndDriverValid());
|
||||
vehicle = nearbyVehicle;
|
||||
waypoint = null;
|
||||
if (!nearbyVehicle)
|
||||
{
|
||||
Game.LogTrivial($"Nearby vehicle is null.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var firstWaypoint = path.Waypoints.First();
|
||||
if (menuItem.SelectedItem == "First waypoint" && firstWaypoint == null)
|
||||
{
|
||||
Game.LogTrivial($"First waypoint is null.");
|
||||
return false;
|
||||
}
|
||||
else if(menuItem.SelectedItem == "First waypoint" && firstWaypoint != null)
|
||||
{
|
||||
waypoint = firstWaypoint;
|
||||
return true;
|
||||
}
|
||||
|
||||
var nearestWaypoint = path.Waypoints.Where(wp => wp.Position.DistanceTo2D(nearbyVehicle.FrontPosition) < wp.Position.DistanceTo2D(nearbyVehicle.RearPosition)).OrderBy(wp => wp.Position.DistanceTo2D(nearbyVehicle)).FirstOrDefault();
|
||||
if (menuItem.SelectedItem == "Nearest waypoint" && nearestWaypoint == null)
|
||||
{
|
||||
Game.LogTrivial($"Nearest waypoint is null.");
|
||||
return false;
|
||||
}
|
||||
else if (menuItem.SelectedItem == "Nearest waypoint" && nearestWaypoint != null)
|
||||
{
|
||||
waypoint = nearestWaypoint;
|
||||
return true;
|
||||
}
|
||||
|
||||
Game.LogTrivial($"What are we doing here?");
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static void Direct(Vehicle nearbyVehicle, Path path, Waypoint targetWaypoint)
|
||||
{
|
||||
var nearbyVehiclesPath = PathManager.Paths.FirstOrDefault(p => p.CollectedPeds.Any(v => v.CurrentVehicle == nearbyVehicle));
|
||||
if(nearbyVehiclesPath == null)
|
||||
{
|
||||
Game.LogTrivial($"Nearby vehicle does not belong to any path.");
|
||||
}
|
||||
|
||||
var collectedVehicleOnThisPath = path.CollectedPeds.FirstOrDefault(v => v.CurrentVehicle == nearbyVehicle);
|
||||
var nearbyCollectedVehicleOtherPath = nearbyVehiclesPath?.CollectedPeds.FirstOrDefault(p => p.CurrentVehicle == nearbyVehicle);
|
||||
if (collectedVehicleOnThisPath == null)
|
||||
{
|
||||
Game.LogTrivial($"Nearby vehicle does not belong to this path.");
|
||||
if (nearbyCollectedVehicleOtherPath != null)
|
||||
{
|
||||
Game.LogTrivial($"Dismissing nearby vehicle from other path.");
|
||||
nearbyCollectedVehicleOtherPath.Dismiss(Dismiss.FromDirected, path);
|
||||
}
|
||||
Game.LogTrivial($"[Direct Driver] Adding {nearbyVehicle.Model.Name} to directed path.");
|
||||
var newCollectedPed = new CollectedPed(nearbyVehicle.Driver, path, targetWaypoint) { Directed = true };
|
||||
path.CollectedPeds.Add(newCollectedPed);
|
||||
//collectedVehicleOnThisPath.Tasks.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
SceneManager/Utils/DismissDriver.cs
Normal file
44
SceneManager/Utils/DismissDriver.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
using Rage;
|
||||
using SceneManager.CollectedPeds;
|
||||
using SceneManager.Managers;
|
||||
using System.Linq;
|
||||
|
||||
namespace SceneManager.Utils
|
||||
{
|
||||
internal static class DismissDriver
|
||||
{
|
||||
internal static void Dismiss(int dismissIndex)
|
||||
{
|
||||
var nearbyVehicle = Game.LocalPlayer.Character.GetNearbyVehicles(16).FirstOrDefault(v => v.VehicleAndDriverValid() && v != Game.LocalPlayer.Character.CurrentVehicle);
|
||||
if (!nearbyVehicle)
|
||||
{
|
||||
Game.LogTrivial($"Nearby vehicle is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(dismissIndex == (int)Utils.Dismiss.FromWorld)
|
||||
{
|
||||
// Have to loop because sometimes police peds don't get deleted properly
|
||||
// The path should handle removing the deleted driver/vehicle from its list of collected vehicles
|
||||
while (nearbyVehicle && nearbyVehicle.HasOccupants)
|
||||
{
|
||||
nearbyVehicle.Occupants.ToList().ForEach(x => x.Delete());
|
||||
GameFiber.Yield();
|
||||
}
|
||||
if (nearbyVehicle)
|
||||
{
|
||||
nearbyVehicle.Delete();
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
CollectedPed collectedPed = PathManager.Paths.Where(x => x != null).SelectMany(x => x.CollectedPeds).FirstOrDefault(x => x != null && x.CurrentVehicle == nearbyVehicle);
|
||||
if(collectedPed != null)
|
||||
{
|
||||
collectedPed.Dismiss((Dismiss)dismissIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,5 @@
|
|||
namespace SceneManager.Utils
|
||||
{
|
||||
internal enum Delete
|
||||
{
|
||||
Single,
|
||||
All
|
||||
}
|
||||
|
||||
internal enum PedTask
|
||||
{
|
||||
CTaskHandsUp = 0,
|
||||
|
|
@ -446,7 +440,8 @@
|
|||
{
|
||||
Uninitialized,
|
||||
Creating,
|
||||
Finished
|
||||
Finished,
|
||||
Deleting
|
||||
}
|
||||
|
||||
internal enum SpeedUnits
|
||||
|
|
@ -455,18 +450,18 @@
|
|||
KPH
|
||||
}
|
||||
|
||||
internal enum DrivingFlagType
|
||||
public enum DrivingFlagType
|
||||
{
|
||||
Normal = 263075,
|
||||
Direct = 17040259
|
||||
} // Change this to Public for import/export?
|
||||
} // Change this to Public for import/export
|
||||
|
||||
internal enum DismissOption
|
||||
internal enum Dismiss
|
||||
{
|
||||
FromPath = 0,
|
||||
FromWaypoint = 1,
|
||||
FromWorld = 2,
|
||||
FromPlayer = 3,
|
||||
ByPlayer = 3,
|
||||
FromDirected = 4
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
using Rage;
|
||||
using RAGENativeUI.Elements;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Paths;
|
||||
using SceneManager.Waypoints;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace SceneManager.Utils
|
||||
{
|
||||
|
|
@ -49,15 +55,15 @@ namespace SceneManager.Utils
|
|||
}
|
||||
|
||||
// Ped is in a vehicle
|
||||
if (taskInVehicleBasic)
|
||||
if (ped.CurrentVehicle)
|
||||
{
|
||||
//Game.LogTrivial($"Ped is in a vehicle.");
|
||||
// Ped has a controlled driving task
|
||||
if (taskControlVehicle)
|
||||
{
|
||||
//Game.LogTrivial($"Ped has a controlled driving task. (non-ambient)");
|
||||
return false;
|
||||
}
|
||||
//if (taskControlVehicle)
|
||||
//{
|
||||
// //Game.LogTrivial($"Ped has a controlled driving task. (non-ambient)");
|
||||
// return false;
|
||||
//}
|
||||
|
||||
// Ped has a wander driving task
|
||||
if (taskCarDriveWander)
|
||||
|
|
@ -67,12 +73,12 @@ namespace SceneManager.Utils
|
|||
}
|
||||
|
||||
// If the ped is in a vehicle but doesn't have a driving task, then it's a passenger. Check if the vehicle's driver has a driving wander task
|
||||
if (ped.CurrentVehicle && ped.CurrentVehicle.Driver)
|
||||
if (ped.CurrentVehicle.Driver && ped.CurrentVehicle.Driver != ped)
|
||||
{
|
||||
var driverHasWanderTask = Rage.Native.NativeFunction.Natives.GET_IS_TASK_ACTIVE<bool>(ped.CurrentVehicle.Driver, 151);
|
||||
if (driverHasWanderTask)
|
||||
{
|
||||
//Game.LogTrivial($"[Ambient Ped Check]: Ped is a passenger. Vehicle's driver has a wander driving task. (ambient)");
|
||||
//Game.LogTrivial($"Ped is a passenger. Vehicle's driver has a wander driving task. (ambient)");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -80,13 +86,6 @@ namespace SceneManager.Utils
|
|||
|
||||
if (ped.IsOnFoot)
|
||||
{
|
||||
// UB unit on-foot, waiting for interaction
|
||||
if (ped.RelationshipGroup.Name == "UBCOP")
|
||||
{
|
||||
//Game.LogTrivial($"Cop is UB unit. (non-ambient)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cop ped walking around or standing still
|
||||
if ((taskComplexControlMovement && taskWanderingScenario) || (taskAmbientClips && taskUseScenario))
|
||||
{
|
||||
|
|
@ -99,5 +98,121 @@ namespace SceneManager.Utils
|
|||
//Game.LogTrivial($"Nothing else has returned true by this point. (non-ambient)");
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>Determines if a vehicle and driver are valid.
|
||||
/// </summary>
|
||||
internal static bool VehicleAndDriverValid(this Vehicle vehicle)
|
||||
{
|
||||
if (vehicle && vehicle.HasDriver && vehicle.Driver && vehicle.Driver.IsAlive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Determines if this vehicle is within the waypoint's collection range.
|
||||
/// </summary>
|
||||
internal static bool IsNearCollectorWaypoint(this Vehicle vehicle, Waypoint waypoint)
|
||||
{
|
||||
return vehicle.FrontPosition.DistanceTo2D(waypoint.Position) <= waypoint.CollectorRadius && Math.Abs(waypoint.Position.Z - vehicle.Position.Z) < 3;
|
||||
}
|
||||
|
||||
internal static bool IsValidForPathCollection(this Vehicle vehicle, Path path)
|
||||
{
|
||||
if (!vehicle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var vehicleCollectedOnAnotherPath = PathManager.Paths.Any(p => p != null && p.Number != path.Number && p.CollectedPeds.Any(cp => cp && cp.CurrentVehicle == vehicle));
|
||||
if (vehicleCollectedOnAnotherPath)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(path.BlacklistedVehicles.Contains(vehicle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(vehicle == Game.LocalPlayer.Character.LastVehicle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vehicle.Driver)
|
||||
{
|
||||
if (!vehicle.Driver.IsAlive)
|
||||
{
|
||||
Game.LogTrivial($"Vehicle's driver is dead.");
|
||||
path.BlacklistedVehicles.Add(vehicle);
|
||||
return false;
|
||||
}
|
||||
if (vehicle.IsPoliceVehicle && !vehicle.Driver.IsAmbient())
|
||||
{
|
||||
Game.LogTrivial($"Vehicle is a non-ambient police vehicle.");
|
||||
path.BlacklistedVehicles.Add(vehicle);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((vehicle.IsCar || vehicle.IsBike || vehicle.IsBicycle || vehicle.IsQuadBike) && !vehicle.IsSirenOn && vehicle.IsEngineOn && vehicle.IsOnAllWheels && vehicle.Speed > 1 && !path.CollectedPeds.Any(cp => cp && cp.CurrentVehicle == vehicle))
|
||||
{
|
||||
if (!vehicle.HasDriver)
|
||||
{
|
||||
vehicle.CreateRandomDriver();
|
||||
GameFiber.Yield();
|
||||
//while (vehicle && !vehicle.HasDriver)
|
||||
//{
|
||||
// Game.LogTrivial($"Trying to create new driver");
|
||||
// GameFiber.Yield();
|
||||
//}
|
||||
if(!vehicle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!vehicle.Driver)
|
||||
{
|
||||
Game.LogTrivial($"Unable to create a new driver");
|
||||
vehicle.Delete();
|
||||
return false;
|
||||
}
|
||||
Game.LogTrivial($"Vehicle has a new driver");
|
||||
//vehicle.Driver.IsPersistent = true;
|
||||
vehicle.Driver.BlockPermanentEvents = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static float GetTextWidth(this UIMenuItem menuItem)
|
||||
{
|
||||
menuItem.TextStyle.Apply();
|
||||
Rage.Native.NativeFunction.Natives.x54CE8AC98E120CAB("STRING"); // _BEGIN_TEXT_COMMAND_GET_WIDTH
|
||||
Rage.Native.NativeFunction.Natives.ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(menuItem.Text);
|
||||
return Rage.Native.NativeFunction.Natives.x85F061DA64ED2F67<float>(true); // _END_TEXT_COMMAND_GET_WIDTH
|
||||
}
|
||||
|
||||
internal static float GetSelectedItemTextWidth(this UIMenuListScrollerItem<string> scrollerItem)
|
||||
{
|
||||
if (scrollerItem.OptionCount == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
scrollerItem.GetTextWidth();
|
||||
scrollerItem.TextStyle.Apply();
|
||||
|
||||
Rage.Native.NativeFunction.Natives.x54CE8AC98E120CAB("STRING"); // _BEGIN_TEXT_COMMAND_GET_WIDTH
|
||||
Rage.Native.NativeFunction.Natives.ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(scrollerItem.SelectedItem);
|
||||
|
||||
return Rage.Native.NativeFunction.Natives.x85F061DA64ED2F67<float>(true); // _END_TEXT_COMMAND_GET_WIDTH
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
using Rage;
|
||||
|
||||
namespace SceneManager.Utils
|
||||
{
|
||||
class GetUserInput
|
||||
{
|
||||
internal static void LoopForUserInput()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
bool isTextEntryOpen = (Rage.Native.NativeFunction.Natives.UPDATE_ONSCREEN_KEYBOARD<int>() == 0);
|
||||
if (!isTextEntryOpen)
|
||||
{
|
||||
GetKeyboardInput();
|
||||
GetControllerInput();
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.LogTrivial($"A text menu is open.");
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (MenuManager.menuPool.IsAnyMenuOpen())
|
||||
{
|
||||
Game.DisplaySubtitle($"You are using a test build of Scene Manager. Please report any bugs/crashes in the Discord server.");
|
||||
}
|
||||
#endif
|
||||
MenuManager.menuPool.ProcessMenus();
|
||||
GameFiber.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
private static void GetControllerInput()
|
||||
{
|
||||
if (Settings.ModifierButton == ControllerButtons.None)
|
||||
{
|
||||
if (Game.IsControllerButtonDown(Settings.ToggleButton) && AreMenusClosed())
|
||||
{
|
||||
MainMenu.mainMenu.Visible = !MainMenu.mainMenu.Visible;
|
||||
}
|
||||
}
|
||||
else if (Game.IsControllerButtonDownRightNow(Settings.ModifierButton) && Game.IsControllerButtonDown(Settings.ToggleButton) && AreMenusClosed())
|
||||
{
|
||||
MainMenu.mainMenu.Visible = !MainMenu.mainMenu.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
private static void GetKeyboardInput()
|
||||
{
|
||||
if (Settings.ModifierKey == System.Windows.Forms.Keys.None)
|
||||
{
|
||||
if (Game.IsKeyDown(Settings.ToggleKey) && AreMenusClosed())
|
||||
{
|
||||
MainMenu.mainMenu.Visible = !MainMenu.mainMenu.Visible;
|
||||
}
|
||||
}
|
||||
else if (Game.IsKeyDownRightNow(Settings.ModifierKey) && Game.IsKeyDown(Settings.ToggleKey) && AreMenusClosed())
|
||||
{
|
||||
MainMenu.mainMenu.Visible = !MainMenu.mainMenu.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool AreMenusClosed()
|
||||
{
|
||||
if(!BarrierMenu.barrierMenu.Visible && !PathMainMenu.pathMainMenu.Visible && !PathCreationMenu.pathCreationMenu.Visible && !EditPathMenu.editPathMenu.Visible && !EditWaypointMenu.editWaypointMenu.Visible && !SettingsMenu.settingsMenu.Visible)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
SceneManager/Utils/HelperMethods.cs
Normal file
16
SceneManager/Utils/HelperMethods.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using Rage;
|
||||
using SceneManager.Menus;
|
||||
|
||||
namespace SceneManager.Utils
|
||||
{
|
||||
internal class HelperMethods
|
||||
{
|
||||
internal static float ConvertDriveSpeedForWaypoint(float speed)
|
||||
{
|
||||
float convertedSpeed = SettingsMenu.SpeedUnits.SelectedItem == SpeedUnits.MPH
|
||||
? MathHelper.ConvertMilesPerHourToMetersPerSecond(speed)
|
||||
: MathHelper.ConvertKilometersPerHourToMetersPerSecond(speed);
|
||||
return convertedSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
SceneManager/Utils/Hints.cs
Normal file
39
SceneManager/Utils/Hints.cs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
using Rage;
|
||||
using System.Windows.Forms;
|
||||
using SceneManager.Menus;
|
||||
|
||||
namespace SceneManager
|
||||
{
|
||||
class Hints
|
||||
{
|
||||
internal static bool Enabled { get; set; } = SettingsMenu.Hints.Checked;
|
||||
|
||||
internal static void Display(string message)
|
||||
{
|
||||
if (Enabled)
|
||||
{
|
||||
Game.DisplayNotification($"{message}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DisplayHintsToOpenMenu()
|
||||
{
|
||||
if (Settings.ModifierKey == Keys.None && Settings.ModifierButton == ControllerButtons.None)
|
||||
{
|
||||
Display($"~o~Scene Manager ~y~[Hint]\n~w~To open the menu, press the ~b~{Settings.ToggleKey} key ~w~or ~b~{Settings.ToggleButton} button");
|
||||
}
|
||||
else if (Settings.ModifierKey == Keys.None)
|
||||
{
|
||||
Display($"~o~Scene Manager ~y~[Hint]\n~w~To open the menu, press the ~b~{Settings.ToggleKey} key ~w~or ~b~{Settings.ModifierButton} ~w~+ ~b~{Settings.ToggleButton} buttons");
|
||||
}
|
||||
else if (Settings.ModifierButton == ControllerButtons.None)
|
||||
{
|
||||
Display($"~o~Scene Manager ~y~[Hint]\n~w~To open the menu, press ~b~{Settings.ModifierKey} ~w~+ ~b~{Settings.ToggleKey} ~w~or the ~b~{Settings.ToggleButton} button");
|
||||
}
|
||||
else
|
||||
{
|
||||
Display($"~o~Scene Manager ~y~[Hint]\n~w~To open the menu, press the ~b~{Settings.ModifierKey} ~w~+ ~b~{Settings.ToggleKey} keys ~w~or ~b~{Settings.ModifierButton} ~w~+ ~b~{Settings.ToggleButton} buttons");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
using Rage;
|
||||
|
||||
namespace SceneManager.Utils
|
||||
{
|
||||
internal static class MousePositionInWorld
|
||||
{
|
||||
internal static Vector3 GetPosition { get { return GetMousePositionInWorld(); } }
|
||||
|
||||
internal static Vector3 GetPositionForBarrier { get { return GetMousePositionInWorld(Settings.BarrierPlacementDistance); } }
|
||||
|
||||
private static Vector3 GetMousePositionInWorld(float maxDistance = 100f)
|
||||
{
|
||||
HitResult TracePlayerView(float maxTraceDistance = 100f, TraceFlags flags = TraceFlags.IntersectWorld) => TracePlayerView2(out Vector3 v1, out Vector3 v2, maxTraceDistance, flags);
|
||||
|
||||
HitResult TracePlayerView2(out Vector3 start, out Vector3 end, float maxTraceDistance, TraceFlags flags)
|
||||
{
|
||||
Vector3 direction = GetPlayerLookingDirection(out start);
|
||||
end = start + (maxTraceDistance * direction);
|
||||
return World.TraceLine(start, end, flags);
|
||||
}
|
||||
|
||||
Vector3 GetPlayerLookingDirection(out Vector3 camPosition)
|
||||
{
|
||||
if (Camera.RenderingCamera)
|
||||
{
|
||||
camPosition = Camera.RenderingCamera.Position;
|
||||
return Camera.RenderingCamera.Direction;
|
||||
}
|
||||
else
|
||||
{
|
||||
float pitch = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_RELATIVE_PITCH<float>();
|
||||
float heading = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_RELATIVE_HEADING<float>();
|
||||
|
||||
camPosition = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_COORD<Vector3>();
|
||||
return (Game.LocalPlayer.Character.Rotation + new Rotator(pitch, 0, heading)).ToVector().ToNormalized();
|
||||
}
|
||||
}
|
||||
|
||||
return TracePlayerView(maxDistance, TraceFlags.IntersectWorld).HitPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
using Rage;
|
||||
using Rage.Native;
|
||||
|
||||
namespace SceneManager.Utils
|
||||
{
|
||||
internal static class PNWUserInput
|
||||
{
|
||||
public static string GetUserInput(string windowTitle, string defaultText, int maxLength)
|
||||
{
|
||||
NativeFunction.Natives.DISABLE_ALL_CONTROL_ACTIONS(2);
|
||||
|
||||
NativeFunction.Natives.DISPLAY_ONSCREEN_KEYBOARD(true, windowTitle, 0, defaultText, 0, 0, 0, maxLength);
|
||||
Game.DisplayHelp("Enter the filename you would like to save your path as\n~INPUT_FRONTEND_ACCEPT~ Export path\n~INPUT_FRONTEND_CANCEL~ Cancel", true);
|
||||
Game.DisplaySubtitle(windowTitle, 100000);
|
||||
|
||||
while (NativeFunction.Natives.UPDATE_ONSCREEN_KEYBOARD<int>() == 0)
|
||||
{
|
||||
GameFiber.Yield();
|
||||
}
|
||||
|
||||
NativeFunction.Natives.ENABLE_ALL_CONTROL_ACTIONS(2);
|
||||
Game.DisplaySubtitle("", 5);
|
||||
Game.HideHelp();
|
||||
|
||||
return NativeFunction.Natives.GET_ONSCREEN_KEYBOARD_RESULT<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
using InputManager;
|
||||
using Rage;
|
||||
using RAGENativeUI;
|
||||
using RAGENativeUI.Elements;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
||||
namespace SceneManager.Utils
|
||||
{
|
||||
internal class RNUIMouseInputHandler
|
||||
{
|
||||
internal delegate void Function();
|
||||
|
||||
internal static void Initialize(UIMenu menu, List<UIMenuScrollerItem> scrollerItems)
|
||||
{
|
||||
GameFiber.StartNew(() =>
|
||||
{
|
||||
while (menu.Visible)
|
||||
{
|
||||
var selectedScroller = menu.MenuItems.Where(x => scrollerItems.Contains(x) && x.Selected && x.Enabled).FirstOrDefault();
|
||||
if (selectedScroller != null)
|
||||
{
|
||||
OnWheelScroll(menu, selectedScroller, scrollerItems);
|
||||
}
|
||||
|
||||
if (Game.IsKeyDown(Keys.LButton) && Rage.Native.NativeFunction.Natives.UPDATE_ONSCREEN_KEYBOARD<int>() != 0)
|
||||
{
|
||||
Keyboard.KeyDown(Keys.Enter);
|
||||
GameFiber.Wait(1);
|
||||
Keyboard.KeyUp(Keys.Enter);
|
||||
}
|
||||
|
||||
if (menu.SubtitleText.Contains("Path Creation Menu"))
|
||||
{
|
||||
DrawWaypointMarker();
|
||||
}
|
||||
GameFiber.Yield();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
internal static void OnWheelScroll(UIMenu menu, UIMenuItem selectedScroller, List<UIMenuScrollerItem> scrollerItems)
|
||||
{
|
||||
var menuScrollingDisabled = false;
|
||||
var menuItems = menu.MenuItems.Where(x => x != selectedScroller);
|
||||
|
||||
while (Game.IsShiftKeyDownRightNow)
|
||||
{
|
||||
menu.ResetKey(Common.MenuControls.Up);
|
||||
menu.ResetKey(Common.MenuControls.Down);
|
||||
menuScrollingDisabled = true;
|
||||
ScrollMenuItem();
|
||||
if (menu.SubtitleText.Contains("Path Creation Menu") || menu.SubtitleText.Contains("Edit Waypoint"))
|
||||
{
|
||||
CompareScrollerValues();
|
||||
}
|
||||
if(menu.SubtitleText.Contains("Path Creation Menu"))
|
||||
{
|
||||
DrawWaypointMarker();
|
||||
}
|
||||
GameFiber.Yield();
|
||||
}
|
||||
|
||||
if (menuScrollingDisabled)
|
||||
{
|
||||
menuScrollingDisabled = false;
|
||||
menu.SetKey(Common.MenuControls.Up, GameControl.CursorScrollUp);
|
||||
menu.SetKey(Common.MenuControls.Up, GameControl.CellphoneUp);
|
||||
menu.SetKey(Common.MenuControls.Down, GameControl.CursorScrollDown);
|
||||
menu.SetKey(Common.MenuControls.Down, GameControl.CellphoneDown);
|
||||
}
|
||||
|
||||
void ScrollMenuItem()
|
||||
{
|
||||
if (Game.GetMouseWheelDelta() > 0)
|
||||
{
|
||||
Keyboard.KeyDown(Keys.Right);
|
||||
GameFiber.Wait(1);
|
||||
Keyboard.KeyUp(Keys.Right);
|
||||
}
|
||||
else if (Game.GetMouseWheelDelta() < 0)
|
||||
{
|
||||
Keyboard.KeyDown(Keys.Left);
|
||||
GameFiber.Wait(1);
|
||||
Keyboard.KeyUp(Keys.Left);
|
||||
}
|
||||
}
|
||||
|
||||
void CompareScrollerValues()
|
||||
{
|
||||
var collectorRadius = (UIMenuNumericScrollerItem<int>)scrollerItems.Where(x => x.Text == "Collection Radius").FirstOrDefault();
|
||||
var speedZoneRadius = (UIMenuNumericScrollerItem<int>)scrollerItems.Where(x => x.Text == "Speed Zone Radius").FirstOrDefault();
|
||||
|
||||
if (selectedScroller.Text == "Collection Radius" || selectedScroller.Text == "Speed Zone Radius")
|
||||
{
|
||||
if (selectedScroller == collectorRadius && collectorRadius.Value > speedZoneRadius.Value)
|
||||
{
|
||||
while (collectorRadius.Value > speedZoneRadius.Value)
|
||||
{
|
||||
speedZoneRadius.ScrollToNextOption();
|
||||
}
|
||||
}
|
||||
if (selectedScroller == speedZoneRadius && speedZoneRadius.Value < collectorRadius.Value)
|
||||
{
|
||||
collectorRadius.Value = speedZoneRadius.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawWaypointMarker()
|
||||
{
|
||||
var waypointPosition = MousePositionInWorld.GetPosition;
|
||||
if (SettingsMenu.threeDWaypoints.Checked && PathCreationMenu.collectorWaypoint.Checked)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, (float)PathCreationMenu.collectorRadius.Value * 2, (float)PathCreationMenu.collectorRadius.Value * 2, 1f, 80, 130, 255, 80, false, false, 2, false, 0, 0, false);
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, (float)PathCreationMenu.speedZoneRadius.Value * 2, (float)PathCreationMenu.speedZoneRadius.Value * 2, 1f, 255, 185, 80, 80, false, false, 2, false, 0, 0, false);
|
||||
}
|
||||
else if (PathCreationMenu.stopWaypointType.Checked)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 255, 65, 65, 80, false, false, 2, false, 0, 0, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 65, 255, 65, 80, false, false, 2, false, 0, 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,9 +8,10 @@ using System.Xml.Serialization;
|
|||
|
||||
namespace SceneManager.Utils
|
||||
{
|
||||
internal static class PathXMLManager
|
||||
internal static class Serializer
|
||||
{
|
||||
private static Dictionary<Type, XmlSerializer> _serializerCache = new Dictionary<Type, XmlSerializer>();
|
||||
|
||||
private static XmlSerializer _getOrCreateSerializer<T>(XmlAttributeOverrides overrides = null)
|
||||
{
|
||||
if (_serializerCache.ContainsKey(typeof(T)))
|
||||
|
|
@ -74,7 +75,7 @@ namespace SceneManager.Utils
|
|||
SaveItemToXML(list, filePath);
|
||||
}
|
||||
|
||||
public static void SaveItemToXML<T>(T item, string path, XmlAttributeOverrides overrides)
|
||||
public static void SaveItemToXML<T>(T item, string path, XmlAttributeOverrides overrides = null)
|
||||
{
|
||||
Encoding utf8NoBom = new UTF8Encoding(false);
|
||||
using (TextWriter writer = new StreamWriter(path, false, utf8NoBom))
|
||||
|
|
@ -82,17 +83,16 @@ namespace SceneManager.Utils
|
|||
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
|
||||
ns.Add("", "");
|
||||
|
||||
// new XmlSerializer(typeof(T)).Serialize(writer, item);
|
||||
_getOrCreateSerializer<T>(overrides).Serialize(writer, item, ns);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveItemToXML<T>(T item, string path)
|
||||
{
|
||||
SaveItemToXML<T>(item, path, null);
|
||||
}
|
||||
//public static void SaveItemToXML<T>(T item, string path)
|
||||
//{
|
||||
// SaveItemToXML(item, path, null);
|
||||
//}
|
||||
|
||||
public static T LoadItemFromXML<T>(string filePath, XmlAttributeOverrides overrides)
|
||||
public static T LoadItemFromXML<T>(string filePath, XmlAttributeOverrides overrides = null)
|
||||
{
|
||||
if (!File.Exists(filePath)) throw new FileNotFoundException($"{nameof(LoadItemFromXML)}(): specified file does not exist: {filePath}");
|
||||
|
||||
|
|
@ -102,10 +102,10 @@ namespace SceneManager.Utils
|
|||
}
|
||||
}
|
||||
|
||||
public static T LoadItemFromXML<T>(string filePath)
|
||||
{
|
||||
return (T)LoadItemFromXML<T>(filePath, null);
|
||||
}
|
||||
//public static T LoadItemFromXML<T>(string filePath)
|
||||
//{
|
||||
// return LoadItemFromXML<T>(filePath, null);
|
||||
//}
|
||||
|
||||
public static void ModifyItemInXML<T>(string filePath, Action<T> modification)
|
||||
{
|
||||
|
|
@ -130,24 +130,14 @@ namespace SceneManager.Utils
|
|||
ModifyItemInXML<List<T>>(path, t => t.Add(objectToAdd));
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Creates folder in case it doesn't exist and checks file existance.
|
||||
///// </summary>
|
||||
///// <param name="path"></param>
|
||||
///// <returns>false when a file does not exist.</returns>
|
||||
//private static bool ValidatePath(string path)
|
||||
//{
|
||||
// //TODO: implement
|
||||
// // - check extension
|
||||
// // - bool param: createDir
|
||||
// string dir = Path.GetDirectoryName(path);
|
||||
// if (!Directory.Exists(dir))
|
||||
// {
|
||||
// Directory.CreateDirectory(dir);
|
||||
// return false;
|
||||
// }
|
||||
internal static XmlAttributeOverrides DefineOverrides()
|
||||
{
|
||||
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
|
||||
XmlAttributes attr = new XmlAttributes();
|
||||
attr.XmlRoot = new XmlRootAttribute("Paths");
|
||||
overrides.Add(typeof(List<Paths.Path>), attr);
|
||||
|
||||
// return File.Exists(path);
|
||||
//}
|
||||
return overrides;
|
||||
}
|
||||
}
|
||||
}
|
||||
236
SceneManager/Utils/UserInput.cs
Normal file
236
SceneManager/Utils/UserInput.cs
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
using InputManager;
|
||||
using Rage;
|
||||
using Rage.Native;
|
||||
using RAGENativeUI;
|
||||
using RAGENativeUI.Elements;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Menus;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace SceneManager.Utils
|
||||
{
|
||||
// The only reason this class should change is to modify how user input is handled
|
||||
class UserInput
|
||||
{
|
||||
private static bool _menuKeysPressed
|
||||
{
|
||||
get => (Settings.ModifierKey == Keys.None && Game.IsKeyDown(Settings.ToggleKey)) ||
|
||||
(Game.IsKeyDownRightNow(Settings.ModifierKey) && Game.IsKeyDown(Settings.ToggleKey));
|
||||
}
|
||||
private static bool _menuControllerButtonsPressed
|
||||
{
|
||||
get => (Settings.ModifierButton == ControllerButtons.None && Game.IsControllerButtonDown(Settings.ToggleButton)) ||
|
||||
(Game.IsControllerButtonDownRightNow(Settings.ModifierButton) && Game.IsControllerButtonDown(Settings.ToggleButton));
|
||||
}
|
||||
internal static Vector3 PlayerMousePosition { get => GetMousePositionInWorld(); }
|
||||
internal static Vector3 PlayerMousePositionForBarrier { get => GetMousePositionInWorld(Settings.BarrierPlacementDistance); }
|
||||
|
||||
internal static void HandleKeyPress()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
GameFiber.Yield();
|
||||
|
||||
bool isTextEntryOpen = (NativeFunction.Natives.UPDATE_ONSCREEN_KEYBOARD<int>() == 0);
|
||||
if (!isTextEntryOpen && MenuKeysPressed())
|
||||
{
|
||||
if (MenuManager.MenuPool.Any(x => x.Visible))
|
||||
{
|
||||
foreach (UIMenu menu in MenuManager.MenuPool.Where(x => x.Visible))
|
||||
{
|
||||
menu.Visible = !menu.Visible;
|
||||
}
|
||||
MenuManager.MenuPool.CloseAllMenus();
|
||||
continue;
|
||||
}
|
||||
|
||||
Menus.MainMenu.DisplayMenu();
|
||||
GameFiber.StartNew(() => MenuManager.ProcessMenus(), "Menu Processing Fiber");
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (MenuManager.MenuPool.IsAnyMenuOpen())
|
||||
{
|
||||
Game.DisplaySubtitle($"You are using a test build of ~y~Scene Manager~w~. Please report any ~r~bugs/crashes ~w~in the ~p~Discord ~w~server.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private static bool MenuKeysPressed()
|
||||
{
|
||||
if (_menuKeysPressed || _menuControllerButtonsPressed)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Vector3 GetMousePositionInWorld(float maxDistance = 100f)
|
||||
{
|
||||
HitResult TracePlayerView(float maxTraceDistance = 100f, TraceFlags flags = TraceFlags.IntersectWorld) => TracePlayerView2(out Vector3 v1, out Vector3 v2, maxTraceDistance, flags);
|
||||
|
||||
HitResult TracePlayerView2(out Vector3 start, out Vector3 end, float maxTraceDistance, TraceFlags flags)
|
||||
{
|
||||
Vector3 direction = GetPlayerLookingDirection(out start);
|
||||
end = start + (maxTraceDistance * direction);
|
||||
return World.TraceLine(start, end, flags);
|
||||
}
|
||||
|
||||
Vector3 GetPlayerLookingDirection(out Vector3 camPosition)
|
||||
{
|
||||
if (Camera.RenderingCamera)
|
||||
{
|
||||
camPosition = Camera.RenderingCamera.Position;
|
||||
return Camera.RenderingCamera.Direction;
|
||||
}
|
||||
else
|
||||
{
|
||||
float pitch = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_RELATIVE_PITCH<float>();
|
||||
float heading = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_RELATIVE_HEADING<float>();
|
||||
|
||||
camPosition = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_COORD<Vector3>();
|
||||
return (Game.LocalPlayer.Character.Rotation + new Rotator(pitch, 0, heading)).ToVector().ToNormalized();
|
||||
}
|
||||
}
|
||||
|
||||
return TracePlayerView(maxDistance, TraceFlags.IntersectWorld).HitPosition;
|
||||
}
|
||||
|
||||
internal static void InitializeMenuMouseControl(UIMenu menu, List<UIMenuScrollerItem> scrollerItems)
|
||||
{
|
||||
while (menu.Visible)
|
||||
{
|
||||
var selectedScroller = menu.MenuItems.FirstOrDefault(x => scrollerItems.Contains(x) && x.Selected && x.Enabled);
|
||||
if (selectedScroller != null)
|
||||
{
|
||||
OnWheelScroll(menu, selectedScroller, scrollerItems);
|
||||
}
|
||||
|
||||
if (Game.IsKeyDown(Keys.LButton) && NativeFunction.Natives.UPDATE_ONSCREEN_KEYBOARD<int>() != 0)
|
||||
{
|
||||
Keyboard.KeyDown(Keys.Enter);
|
||||
GameFiber.Wait(1);
|
||||
Keyboard.KeyUp(Keys.Enter);
|
||||
}
|
||||
|
||||
if (menu.SubtitleText.Contains("Path Creation Menu"))
|
||||
{
|
||||
DrawWaypointMarkerAtMousePosition();
|
||||
}
|
||||
GameFiber.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnWheelScroll(UIMenu menu, UIMenuItem selectedScroller, List<UIMenuScrollerItem> scrollerItems)
|
||||
{
|
||||
var menuScrollingDisabled = false;
|
||||
var menuItems = menu.MenuItems.Where(x => x != selectedScroller);
|
||||
|
||||
while (Game.IsShiftKeyDownRightNow)
|
||||
{
|
||||
menu.ResetKey(Common.MenuControls.Up);
|
||||
menu.ResetKey(Common.MenuControls.Down);
|
||||
menuScrollingDisabled = true;
|
||||
ScrollMenuItem();
|
||||
if (menu.SubtitleText.Contains("Path Creation Menu") || menu.SubtitleText.Contains("Edit Waypoint"))
|
||||
{
|
||||
CompareScrollerValues();
|
||||
}
|
||||
if (menu.SubtitleText.Contains("Path Creation Menu"))
|
||||
{
|
||||
DrawWaypointMarkerAtMousePosition();
|
||||
}
|
||||
GameFiber.Yield();
|
||||
}
|
||||
|
||||
if (menuScrollingDisabled)
|
||||
{
|
||||
menuScrollingDisabled = false;
|
||||
menu.SetKey(Common.MenuControls.Up, GameControl.CursorScrollUp);
|
||||
menu.SetKey(Common.MenuControls.Up, GameControl.CellphoneUp);
|
||||
menu.SetKey(Common.MenuControls.Down, GameControl.CursorScrollDown);
|
||||
menu.SetKey(Common.MenuControls.Down, GameControl.CellphoneDown);
|
||||
}
|
||||
|
||||
void ScrollMenuItem()
|
||||
{
|
||||
if (Game.GetMouseWheelDelta() > 0)
|
||||
{
|
||||
Keyboard.KeyDown(Keys.Right);
|
||||
GameFiber.Wait(1);
|
||||
Keyboard.KeyUp(Keys.Right);
|
||||
}
|
||||
else if (Game.GetMouseWheelDelta() < 0)
|
||||
{
|
||||
Keyboard.KeyDown(Keys.Left);
|
||||
GameFiber.Wait(1);
|
||||
Keyboard.KeyUp(Keys.Left);
|
||||
}
|
||||
}
|
||||
|
||||
void CompareScrollerValues()
|
||||
{
|
||||
var collectorRadius = (UIMenuNumericScrollerItem<int>)scrollerItems.Where(x => x.Text == "Collection Radius").FirstOrDefault();
|
||||
var speedZoneRadius = (UIMenuNumericScrollerItem<int>)scrollerItems.Where(x => x.Text == "Speed Zone Radius").FirstOrDefault();
|
||||
|
||||
if (selectedScroller.Text == "Collection Radius" || selectedScroller.Text == "Speed Zone Radius")
|
||||
{
|
||||
if (selectedScroller == collectorRadius && collectorRadius.Value > speedZoneRadius.Value)
|
||||
{
|
||||
while (collectorRadius.Value > speedZoneRadius.Value)
|
||||
{
|
||||
speedZoneRadius.ScrollToNextOption();
|
||||
}
|
||||
}
|
||||
if (selectedScroller == speedZoneRadius && speedZoneRadius.Value < collectorRadius.Value)
|
||||
{
|
||||
collectorRadius.Value = speedZoneRadius.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawWaypointMarkerAtMousePosition()
|
||||
{
|
||||
var waypointPosition = PlayerMousePosition;
|
||||
if (SettingsMenu.ThreeDWaypoints.Checked && PathCreationMenu.CollectorWaypoint.Checked)
|
||||
{
|
||||
NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, (float)PathCreationMenu.CollectorRadius.Value * 2, (float)PathCreationMenu.CollectorRadius.Value * 2, 1f, 80, 130, 255, 80, false, false, 2, false, 0, 0, false);
|
||||
NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, (float)PathCreationMenu.SpeedZoneRadius.Value * 2, (float)PathCreationMenu.SpeedZoneRadius.Value * 2, 1f, 255, 185, 80, 80, false, false, 2, false, 0, 0, false);
|
||||
}
|
||||
else if (PathCreationMenu.StopWaypoint.Checked)
|
||||
{
|
||||
NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 255, 65, 65, 80, false, false, 2, false, 0, 0, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 65, 255, 65, 80, false, false, 2, false, 0, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string PromptPlayerForFileName(string windowTitle, string defaultText, int maxLength)
|
||||
{
|
||||
NativeFunction.Natives.DISABLE_ALL_CONTROL_ACTIONS(2);
|
||||
|
||||
NativeFunction.Natives.DISPLAY_ONSCREEN_KEYBOARD(true, windowTitle, 0, defaultText, 0, 0, 0, maxLength);
|
||||
Game.DisplayHelp("Enter the filename you would like to save your path as\n~INPUT_FRONTEND_ACCEPT~ Export path\n~INPUT_FRONTEND_CANCEL~ Cancel", true);
|
||||
Game.DisplaySubtitle(windowTitle, 100000);
|
||||
|
||||
while (NativeFunction.Natives.UPDATE_ONSCREEN_KEYBOARD<int>() == 0)
|
||||
{
|
||||
GameFiber.Yield();
|
||||
}
|
||||
|
||||
NativeFunction.Natives.ENABLE_ALL_CONTROL_ACTIONS(2);
|
||||
Game.DisplaySubtitle("", 5);
|
||||
Game.HideHelp();
|
||||
|
||||
return NativeFunction.Natives.GET_ONSCREEN_KEYBOARD_RESULT<string>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -2,18 +2,22 @@
|
|||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using SceneManager.Utils;
|
||||
using SceneManager.Menus;
|
||||
using SceneManager.Managers;
|
||||
using SceneManager.Paths;
|
||||
using SceneManager.CollectedPeds;
|
||||
|
||||
namespace SceneManager.Objects
|
||||
namespace SceneManager.Waypoints
|
||||
{
|
||||
internal class Waypoint // Change this to Public for import/export
|
||||
public class Waypoint // Change this and select properties to Public for import/export
|
||||
{
|
||||
internal Path Path { get; set; }
|
||||
public int Number { get; set; }
|
||||
internal int Number { get => Path.Waypoints.IndexOf(this) + 1; set { } }
|
||||
public Vector3 Position { get; set; }
|
||||
public float Speed { get; set; }
|
||||
public DrivingFlagType DrivingFlagType { get; set; }
|
||||
public bool IsStopWaypoint { get; set; }
|
||||
internal Blip Blip { get; }
|
||||
internal Blip Blip { get; private set; }
|
||||
public bool IsCollector { get; set; }
|
||||
public float CollectorRadius { get; set; }
|
||||
internal Blip CollectorRadiusBlip { get; set; }
|
||||
|
|
@ -23,26 +27,25 @@ namespace SceneManager.Objects
|
|||
|
||||
private Waypoint() { }
|
||||
|
||||
internal Waypoint(Path path, int waypointNum, Vector3 waypointPos, float speed, DrivingFlagType drivingFlag, bool stopWaypoint, Blip waypointBlip, bool collector = false, float collectorRadius = 1, float speedZoneRadius = 5)
|
||||
internal Waypoint(Path path, Vector3 waypointPosition, float speed, DrivingFlagType drivingFlag, bool stopWaypoint, bool collector = false, float collectorRadius = 1, float speedZoneRadius = 5)
|
||||
{
|
||||
Path = path;
|
||||
Number = waypointNum;
|
||||
Position = waypointPos;
|
||||
Position = waypointPosition;
|
||||
Speed = speed;
|
||||
DrivingFlagType = drivingFlag;
|
||||
IsStopWaypoint = stopWaypoint;
|
||||
Blip = waypointBlip;
|
||||
IsCollector = collector;
|
||||
CollectorRadius = collectorRadius;
|
||||
SpeedZoneRadius = speedZoneRadius;
|
||||
CreateBlip();
|
||||
if (collector)
|
||||
{
|
||||
AddSpeedZone();
|
||||
CollectorRadiusBlip = new Blip(waypointBlip.Position, collectorRadius)
|
||||
CollectorRadiusBlip = new Blip(Blip.Position, collectorRadius)
|
||||
{
|
||||
Color = waypointBlip.Color,
|
||||
Color = Blip.Color,
|
||||
};
|
||||
if (SettingsMenu.mapBlips.Checked)
|
||||
if (SettingsMenu.MapBlips.Checked)
|
||||
{
|
||||
CollectorRadiusBlip.Alpha = 0.5f;
|
||||
}
|
||||
|
|
@ -51,6 +54,9 @@ namespace SceneManager.Objects
|
|||
CollectorRadiusBlip.Alpha = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
Path.Waypoints.Add(this);
|
||||
Game.LogTrivial($"Path {Path.Name} Waypoint {Number} added [Driving style: {DrivingFlagType} | Stop waypoint: {IsStopWaypoint} | Speed: {Speed} | Collector: {IsCollector}]");
|
||||
DrawWaypointMarker();
|
||||
}
|
||||
|
||||
|
|
@ -73,10 +79,9 @@ namespace SceneManager.Objects
|
|||
if (IsStopWaypoint && !stopWaypoint)
|
||||
{
|
||||
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}");
|
||||
cv.Dismiss(DismissOption.FromWaypoint);
|
||||
cp.Dismiss(Dismiss.FromWaypoint);
|
||||
}
|
||||
}
|
||||
else if(stopWaypoint && !IsStopWaypoint)
|
||||
|
|
@ -146,37 +151,18 @@ namespace SceneManager.Objects
|
|||
{
|
||||
if (Blip)
|
||||
{
|
||||
Blip.Position = Game.LocalPlayer.Character.Position;
|
||||
Blip.Position = newWaypointPosition;
|
||||
}
|
||||
if (CollectorRadiusBlip)
|
||||
{
|
||||
CollectorRadiusBlip.Position = Game.LocalPlayer.Character.Position;
|
||||
CollectorRadiusBlip.Position = newWaypointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void Remove()
|
||||
{
|
||||
if (Blip)
|
||||
{
|
||||
Blip.Delete();
|
||||
}
|
||||
if (CollectorRadiusBlip)
|
||||
{
|
||||
CollectorRadiusBlip.Delete();
|
||||
}
|
||||
RemoveSpeedZone();
|
||||
}
|
||||
internal void AddSpeedZone() => SpeedZone = World.AddSpeedZone(Position, SpeedZoneRadius, Speed);
|
||||
|
||||
internal void AddSpeedZone()
|
||||
{
|
||||
SpeedZone = World.AddSpeedZone(Position, SpeedZoneRadius, Speed);
|
||||
}
|
||||
|
||||
internal void RemoveSpeedZone()
|
||||
{
|
||||
World.RemoveSpeedZone(SpeedZone);
|
||||
}
|
||||
internal void RemoveSpeedZone() => World.RemoveSpeedZone(SpeedZone);
|
||||
|
||||
internal void DrawWaypointMarker()
|
||||
{
|
||||
|
|
@ -185,23 +171,23 @@ namespace SceneManager.Objects
|
|||
{
|
||||
while (true)
|
||||
{
|
||||
if(SettingsMenu.threeDWaypoints.Checked && EnableWaypointMarker && Path.Waypoints.Contains(this))
|
||||
if(SettingsMenu.ThreeDWaypoints.Checked && EnableWaypointMarker && Path.Waypoints.Contains(this))
|
||||
{
|
||||
if (EditWaypointMenu.editWaypointMenu.Visible && PathMainMenu.editPath.Value == Path.Number && EditWaypointMenu.editWaypoint.Value == Number)
|
||||
if (EditWaypointMenu.Menu.Visible && PathMainMenu.EditPath.OptionText == Path.Name && EditWaypointMenu.EditWaypoint.Value == Number)
|
||||
{
|
||||
if (EditWaypointMenu.collectorWaypoint.Checked)
|
||||
if (EditWaypointMenu.CollectorWaypoint.Checked)
|
||||
{
|
||||
if (EditWaypointMenu.updateWaypointPosition.Checked)
|
||||
if (EditWaypointMenu.UpdateWaypointPosition.Checked)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, GetMousePositionInWorld(), 0, 0, 0, 0, 0, 0, (float)EditWaypointMenu.changeCollectorRadius.Value * 2, (float)EditWaypointMenu.changeCollectorRadius.Value * 2, 1f, 80, 130, 255, 100, false, false, 2, false, 0, 0, false);
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, GetMousePositionInWorld(), 0, 0, 0, 0, 0, 0, (float)EditWaypointMenu.changeSpeedZoneRadius.Value * 2, (float)EditWaypointMenu.changeSpeedZoneRadius.Value * 2, 1f, 255, 185, 80, 100, false, false, 2, false, 0, 0, false);
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, GetMousePositionInWorld(), 0, 0, 0, 0, 0, 0, (float)EditWaypointMenu.ChangeCollectorRadius.Value * 2, (float)EditWaypointMenu.ChangeCollectorRadius.Value * 2, 1f, 80, 130, 255, 100, false, false, 2, false, 0, 0, false);
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, GetMousePositionInWorld(), 0, 0, 0, 0, 0, 0, (float)EditWaypointMenu.ChangeSpeedZoneRadius.Value * 2, (float)EditWaypointMenu.ChangeSpeedZoneRadius.Value * 2, 1f, 255, 185, 80, 100, false, false, 2, false, 0, 0, false);
|
||||
}
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Position, 0, 0, 0, 0, 0, 0, (float)EditWaypointMenu.changeCollectorRadius.Value * 2, (float)EditWaypointMenu.changeCollectorRadius.Value * 2, 2f, 80, 130, 255, 100, false, false, 2, false, 0, 0, false);
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Position, 0, 0, 0, 0, 0, 0, (float)EditWaypointMenu.changeSpeedZoneRadius.Value * 2, (float)EditWaypointMenu.changeSpeedZoneRadius.Value * 2, 2f, 255, 185, 80, 100, false, false, 2, false, 0, 0, false);
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Position, 0, 0, 0, 0, 0, 0, (float)EditWaypointMenu.ChangeCollectorRadius.Value * 2, (float)EditWaypointMenu.ChangeCollectorRadius.Value * 2, 2f, 80, 130, 255, 100, false, false, 2, false, 0, 0, false);
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Position, 0, 0, 0, 0, 0, 0, (float)EditWaypointMenu.ChangeSpeedZoneRadius.Value * 2, (float)EditWaypointMenu.ChangeSpeedZoneRadius.Value * 2, 2f, 255, 185, 80, 100, false, false, 2, false, 0, 0, false);
|
||||
}
|
||||
else if (EditWaypointMenu.stopWaypointType.Checked)
|
||||
else if (EditWaypointMenu.StopWaypointType.Checked)
|
||||
{
|
||||
if (EditWaypointMenu.updateWaypointPosition.Checked)
|
||||
if (EditWaypointMenu.UpdateWaypointPosition.Checked)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, GetMousePositionInWorld(), 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 255, 65, 65, 100, false, false, 2, false, 0, 0, false);
|
||||
}
|
||||
|
|
@ -209,17 +195,17 @@ namespace SceneManager.Objects
|
|||
}
|
||||
else
|
||||
{
|
||||
if (EditWaypointMenu.updateWaypointPosition.Checked)
|
||||
if (EditWaypointMenu.UpdateWaypointPosition.Checked)
|
||||
{
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, GetMousePositionInWorld(), 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 65, 255, 65, 100, false, false, 2, false, 0, 0, false);
|
||||
}
|
||||
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Position, 0, 0, 0, 0, 0, 0, 1f, 1f, 2f, 65, 255, 65, 100, false, false, 2, false, 0, 0, false);
|
||||
}
|
||||
}
|
||||
else if ((Path.State == State.Finished && MenuManager.menuPool.IsAnyMenuOpen()) || (Path.State == State.Creating && PathCreationMenu.pathCreationMenu.Visible))
|
||||
else if ((Path.State == State.Finished && MenuManager.MenuPool.IsAnyMenuOpen()) || (Path.State == State.Creating && PathCreationMenu.Menu.Visible))
|
||||
{
|
||||
float markerHeight = 1f;
|
||||
if ((PathMainMenu.directDriver.Selected && PathMainMenu.directDriver.Value == Path.Number) || PathMainMenu.editPath.Selected && PathMainMenu.editPath.Value == Path.Number && (PathMainMenu.pathMainMenu.Visible || EditPathMenu.editPathMenu.Visible))
|
||||
if ((DriverMenu.DirectDriver.Selected && DriverMenu.DirectDriver.OptionText == Path.Name) || PathMainMenu.EditPath.Selected && PathMainMenu.EditPath.OptionText == Path.Name && (PathMainMenu.Menu.Visible || EditPathMenu.Menu.Visible))
|
||||
{
|
||||
markerHeight = 2f;
|
||||
}
|
||||
|
|
@ -283,6 +269,85 @@ namespace SceneManager.Objects
|
|||
}
|
||||
}
|
||||
|
||||
internal void Delete()
|
||||
{
|
||||
if (Blip)
|
||||
{
|
||||
Blip.Delete();
|
||||
}
|
||||
if (CollectorRadiusBlip)
|
||||
{
|
||||
CollectorRadiusBlip.Delete();
|
||||
}
|
||||
RemoveSpeedZone();
|
||||
}
|
||||
|
||||
internal void LoadFromImport(Path path)
|
||||
{
|
||||
Path = path;
|
||||
CreateBlip();
|
||||
Game.LogTrivial($"===== WAYPOINT DATA =====");
|
||||
Game.LogTrivial($"Path: {Path.Name}");
|
||||
Game.LogTrivial($"Number: {Number}");
|
||||
Game.LogTrivial($"Position: {Position}");
|
||||
Game.LogTrivial($"Speed: {Speed}");
|
||||
Game.LogTrivial($"DrivingFlag: {DrivingFlagType}");
|
||||
Game.LogTrivial($"Stop Waypoint: {IsStopWaypoint}");
|
||||
Game.LogTrivial($"Blip: {Blip}");
|
||||
Game.LogTrivial($"Collector: {IsCollector}");
|
||||
Game.LogTrivial($"Collector Radius: {CollectorRadius}");
|
||||
Game.LogTrivial($"SpeedZone Radius: {SpeedZoneRadius}");
|
||||
if (IsCollector)
|
||||
{
|
||||
CollectorRadiusBlip = new Blip(Position, CollectorRadius)
|
||||
{
|
||||
Color = Blip.Color,
|
||||
};
|
||||
if (SettingsMenu.MapBlips.Checked)
|
||||
{
|
||||
CollectorRadiusBlip.Alpha = 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
CollectorRadiusBlip.Alpha = 0f;
|
||||
}
|
||||
}
|
||||
DrawWaypointMarker();
|
||||
}
|
||||
|
||||
private void CreateBlip()
|
||||
{
|
||||
var spriteNumericalEnum = Path.Number + 16; // 16 because the numerical value of these sprites are always 16 more than the path index
|
||||
Blip = new Blip(Position)
|
||||
{
|
||||
Scale = 0.5f,
|
||||
Sprite = (BlipSprite)spriteNumericalEnum
|
||||
};
|
||||
|
||||
if (IsCollector)
|
||||
{
|
||||
Blip.Color = Color.Blue;
|
||||
}
|
||||
else if (IsStopWaypoint)
|
||||
{
|
||||
Blip.Color = Color.Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
Blip.Color = Color.Green;
|
||||
}
|
||||
|
||||
if (!SettingsMenu.MapBlips.Checked)
|
||||
{
|
||||
Blip.Alpha = 0f;
|
||||
}
|
||||
|
||||
if (!Path.IsEnabled)
|
||||
{
|
||||
Blip.Alpha = 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector3 GetMousePositionInWorld()
|
||||
{
|
||||
HitResult TracePlayerView(float maxTraceDistance = 100f, TraceFlags flags = TraceFlags.IntersectWorld) => TracePlayerView2(out Vector3 v1, out Vector3 v2, maxTraceDistance, flags);
|
||||
|
|
@ -10,17 +10,11 @@
|
|||
<protection id="anti debug" />
|
||||
<protection id="ref proxy" />
|
||||
<protection id="resources" />
|
||||
<protection id = "rename" >
|
||||
<argument name = "mode" value = "decodable" />
|
||||
<argument name = "renPublic" value = "false" />
|
||||
<argument name = "renEnum" value = "false" />
|
||||
<argument name = "renameArgs" value = "false" />
|
||||
</protection >
|
||||
</rule>
|
||||
</module>
|
||||
<probePath>..\..\..\packages\InputManager.1.0.0\lib</probePath>
|
||||
<probePath>D:\Program Files\Rockstar Games\Grand Theft Auto V</probePath>
|
||||
<probePath>C:\Users\Rich\Desktop\Mod Stuff\Mod Development\Modding Resources\References</probePath>
|
||||
<probePath>..\..\..\packages\RagePluginHook.1.86.1\lib\net472</probePath>
|
||||
<probePath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8</probePath>
|
||||
<probePath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\Facades</probePath>
|
||||
<probePath>..\..\..\packages\RAGENativeUI.1.8.0\lib\net472</probePath>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="InputManager" version="1.0.0" targetFramework="net48" />
|
||||
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net48" />
|
||||
<package id="RAGENativeUI" version="1.8.0" targetFramework="net48" />
|
||||
<package id="RagePluginHook" version="1.86.1" targetFramework="net48" />
|
||||
</packages>
|
||||
Loading…
Add table
Add a link
Reference in a new issue