mirror of
https://github.com/thegeneralist01/Scene-Manager-DevRepo
synced 2026-01-11 15:40:29 +01:00
Mid-refactor
This commit is contained in:
parent
b52f160ff7
commit
f4c1c0c693
18 changed files with 1721 additions and 916 deletions
|
|
@ -1,7 +1,10 @@
|
||||||
using System.Windows.Forms;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Windows.Forms;
|
||||||
using Rage;
|
using Rage;
|
||||||
|
|
||||||
[assembly: Rage.Attributes.Plugin("Scene Manager V2.0", Author = "Rich", Description = "Manage your scenes with custom AI traffic pathing and cone placement.")]
|
[assembly: Rage.Attributes.Plugin("Scene Manager [Test Build]", Author = "Rich", Description = "Manage your scenes with custom AI traffic pathing and cone placement.")]
|
||||||
|
|
||||||
namespace SceneManager
|
namespace SceneManager
|
||||||
{
|
{
|
||||||
|
|
@ -14,15 +17,15 @@ namespace SceneManager
|
||||||
internal static ControllerButtons ToggleButton = ControllerButtons.Y;
|
internal static ControllerButtons ToggleButton = ControllerButtons.Y;
|
||||||
internal static ControllerButtons ModifierButton = ControllerButtons.A;
|
internal static ControllerButtons ModifierButton = ControllerButtons.A;
|
||||||
internal static bool EnableHints = true;
|
internal static bool EnableHints = true;
|
||||||
internal static string id = Verification.passThrough(Verification.GetID());
|
//internal static string id = Verification.passThrough(Verification.GetID());
|
||||||
internal static string PatronKey = null; // This cannot reference VerifyUser because the file can just be shared and it will always work. Must be manually set to each user's ID
|
//internal static string PatronKey = null; // This cannot reference VerifyUser because the file can just be shared and it will always work. Must be manually set to each user's ID
|
||||||
|
|
||||||
internal static void LoadSettings()
|
internal static void LoadSettings()
|
||||||
{
|
{
|
||||||
Game.LogTrivial("Loading SceneManager.ini settings");
|
Game.LogTrivial("Loading SceneManager.ini settings");
|
||||||
InitializationFile ini = new InitializationFile("Plugins/SceneManager.ini");
|
InitializationFile ini = new InitializationFile("Plugins/SceneManager.ini");
|
||||||
ini.Create();
|
ini.Create();
|
||||||
PatronKey = ini.ReadString("Patreon","PatronKey", null);
|
//PatronKey = ini.ReadString("Patreon","PatronKey", null);
|
||||||
ToggleKey = ini.ReadEnum("Keybindings", "ToggleKey", Keys.T);
|
ToggleKey = ini.ReadEnum("Keybindings", "ToggleKey", Keys.T);
|
||||||
ModifierKey = ini.ReadEnum("Keybindings", "ModifierKey", Keys.LShiftKey);
|
ModifierKey = ini.ReadEnum("Keybindings", "ModifierKey", Keys.LShiftKey);
|
||||||
ToggleButton = ini.ReadEnum("Keybindings", "ToggleButton", ControllerButtons.A);
|
ToggleButton = ini.ReadEnum("Keybindings", "ToggleButton", ControllerButtons.A);
|
||||||
|
|
@ -33,54 +36,94 @@ namespace SceneManager
|
||||||
|
|
||||||
public static void Main()
|
public static void Main()
|
||||||
{
|
{
|
||||||
|
AppDomain.CurrentDomain.DomainUnload += MyTerminationHandler;
|
||||||
Settings.LoadSettings();
|
Settings.LoadSettings();
|
||||||
Game.LogTrivial($"Scene Manager is ready.");
|
GetAssemblyVersion();
|
||||||
|
MenuManager.InstantiateMenus();
|
||||||
|
|
||||||
// id is hardware ID and needs to match PatronKey, which is also hardware ID
|
if (Settings.EnableHints)
|
||||||
if (Settings.id == Settings.PatronKey)
|
DisplayHintsToOpenMenu();
|
||||||
|
|
||||||
|
GameFiber UserInputFiber = new GameFiber(() => GetUserInput.LoopForUserInput());
|
||||||
|
UserInputFiber.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetAssemblyVersion()
|
||||||
|
{
|
||||||
|
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||||
|
System.Diagnostics.FileVersionInfo fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location);
|
||||||
|
var version = fvi.FileVersion;
|
||||||
|
Game.LogTrivial($"Scene Manager V{version} is ready.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DisplayHintsToOpenMenu()
|
||||||
|
{
|
||||||
|
if (Settings.ModifierKey == Keys.None && Settings.ModifierButton == ControllerButtons.None)
|
||||||
{
|
{
|
||||||
Game.LogTrivial($"Patron status verified.");
|
Game.DisplayNotification($"~o~Scene Manager\n~y~[Hint]~w~ To open the menu, press the ~b~{Settings.ToggleKey} key ~w~or ~b~{Settings.ToggleButton} button ~w~while on foot");
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~g~[Patreon]~w~ Thanks for the support, enjoy your session!");
|
}
|
||||||
|
else if (Settings.ModifierKey == Keys.None)
|
||||||
|
{
|
||||||
|
Game.DisplayNotification($"~o~Scene Manager\n~y~[Hint]~w~ To open the menu, press the ~b~{Settings.ToggleKey} key ~w~or ~b~{Settings.ModifierButton} ~w~+ ~b~{Settings.ToggleButton} buttons ~w~while on foot");
|
||||||
|
}
|
||||||
|
else if (Settings.ModifierButton == ControllerButtons.None)
|
||||||
|
{
|
||||||
|
Game.DisplayNotification($"~o~Scene Manager\n~y~[Hint]~w~ To open the menu, press ~b~{Settings.ModifierKey} ~w~+ ~b~{Settings.ToggleKey} ~w~or the ~b~{Settings.ToggleButton} button ~w~while on foot");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Game.LogTrivial($"Patron status not verified.");
|
Game.DisplayNotification($"~o~Scene Manager\n~y~[Hint]~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 ~w~while on foot");
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~y~[Patreon]~w~ Thanks for using my plugin! If you would like to gain access to benefits such as ~g~new features for this plugin~w~, ~g~early access to new plugins~w~, and ~g~custom plugins made just for you~w~, please consider supporting me on ~b~Patreon~w~. ~y~https://www.patreon.com/richdevs");
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Settings.EnableHints)
|
private static void MyTerminationHandler(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// Clean up paths
|
||||||
|
for (int i = 0; i < TrafficMenu.paths.Count; i++)
|
||||||
{
|
{
|
||||||
if (Settings.ModifierKey == Keys.None && Settings.ModifierButton == ControllerButtons.None)
|
TrafficMenu.DeletePath(TrafficMenu.paths[i], i, "All");
|
||||||
{
|
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~y~[Hint]~w~ To open the menu, press the ~b~{Settings.ToggleKey} key ~w~or ~b~{Settings.ToggleButton} button ~w~while on foot");
|
|
||||||
}
|
|
||||||
else if (Settings.ModifierKey == Keys.None)
|
|
||||||
{
|
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~y~[Hint]~w~ To open the menu, press the ~b~{Settings.ToggleKey} key ~w~or ~b~{Settings.ModifierButton} ~w~+ ~b~{Settings.ToggleButton} buttons ~w~while on foot");
|
|
||||||
}
|
|
||||||
else if (Settings.ModifierButton == ControllerButtons.None)
|
|
||||||
{
|
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~y~[Hint]~w~ To open the menu, press ~b~{Settings.ModifierKey} ~w~+ ~b~{Settings.ToggleKey} ~w~or the ~b~{Settings.ToggleButton} button ~w~while on foot");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~y~[Hint]~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 ~w~while on foot");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GameFiber TrafficMenuFiber = new GameFiber(() => TrafficMenu.CheckUserInput());
|
// Clean up cones
|
||||||
TrafficMenuFiber.Start();
|
foreach (Rage.Object cone in BarrierMenu.barriers.Where(c => c))
|
||||||
|
{
|
||||||
|
cone.Delete();
|
||||||
|
}
|
||||||
|
if (BarrierMenu.shadowBarrier)
|
||||||
|
{
|
||||||
|
BarrierMenu.shadowBarrier.Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear everything
|
||||||
|
BarrierMenu.barriers.Clear();
|
||||||
|
TrafficPathing.collectedVehicles.Clear();
|
||||||
|
|
||||||
|
Game.LogTrivial($"Scene Manager has been terminated.");
|
||||||
|
Game.DisplayNotification($"~o~Scene Manager\n~r~[Notice]~w~ The plugin has shut down.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
//GameFiber.StartNew(delegate{
|
||||||
* GameFiber.StartNew(delegate{
|
|
||||||
*
|
//});
|
||||||
* });
|
|
||||||
*
|
//public static Vehicle[] GetNearbyVehicles2(Vector3 OriginPosition, int amount)
|
||||||
* public static Vehicle[] GetNearbyVehicles2(Vector3 OriginPosition, int amount)
|
//{
|
||||||
* {
|
// return (Vehicle[])(from x in World.GetAllVehicles() orderby x.DistanceTo(OriginPosition) select x).Take(amount).ToArray();
|
||||||
* return (Vehicle[])(from x in World.GetAllVehicles() orderby x.DistanceTo(OriginPosition) select x).Take(amount).ToArray();
|
//}
|
||||||
* }
|
|
||||||
*/
|
//Type t = typeof(int);
|
||||||
|
//Game.LogTrivial($"Scene Manager V{Assembly.GetAssembly(t).GetName().Version} is ready.");*/
|
||||||
|
|
||||||
|
//// id is hardware ID and needs to match PatronKey, which is also hardware ID
|
||||||
|
//if (Settings.id == Settings.PatronKey)
|
||||||
|
//{
|
||||||
|
// Game.LogTrivial($"Patron status verified.");
|
||||||
|
// Game.DisplayNotification($"~o~Scene Manager\n~g~[Patreon]~w~ Thanks for the support, enjoy your session!");
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// Game.LogTrivial($"Patron status not verified.");
|
||||||
|
// Game.DisplayNotification($"~o~Scene Manager\n~y~[Patreon]~w~ Thanks for using my plugin! If you would like to gain access to benefits such as ~g~new features for this plugin~w~, ~g~early access to new plugins~w~, and ~g~custom plugins made just for you~w~, please consider supporting me on ~b~Patreon~w~. ~y~https://www.patreon.com/richdevs");
|
||||||
|
//}
|
||||||
|
|
|
||||||
75
SceneManager/GetUserInput.cs
Normal file
75
SceneManager/GetUserInput.cs
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Rage;
|
||||||
|
|
||||||
|
namespace SceneManager
|
||||||
|
{
|
||||||
|
class GetUserInput
|
||||||
|
{
|
||||||
|
public static void LoopForUserInput()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// Keyboard
|
||||||
|
GetKeyboardInput();
|
||||||
|
|
||||||
|
// Controller
|
||||||
|
GetControllerInput();
|
||||||
|
|
||||||
|
// Display this message for test versions only
|
||||||
|
if (MenuManager.mainMenu.Visible)
|
||||||
|
{
|
||||||
|
Game.DisplaySubtitle($"You are using a test build of Scene Manager. Please report any bugs/crashes in the Discord server.");
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuManager.menuPool.ProcessMenus();
|
||||||
|
GameFiber.Yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetControllerInput()
|
||||||
|
{
|
||||||
|
if (EntryPoint.Settings.ModifierButton == ControllerButtons.None)
|
||||||
|
{
|
||||||
|
if (Game.IsControllerButtonDown(EntryPoint.Settings.ToggleButton) && AreMenusClosed())
|
||||||
|
{
|
||||||
|
MenuManager.mainMenu.Visible = !MenuManager.mainMenu.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Game.IsControllerButtonDownRightNow(EntryPoint.Settings.ModifierButton) && Game.IsControllerButtonDown(EntryPoint.Settings.ToggleButton) && AreMenusClosed())
|
||||||
|
{
|
||||||
|
MenuManager.mainMenu.Visible = !MenuManager.mainMenu.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetKeyboardInput()
|
||||||
|
{
|
||||||
|
if (EntryPoint.Settings.ModifierKey == System.Windows.Forms.Keys.None)
|
||||||
|
{
|
||||||
|
if (Game.IsKeyDown(EntryPoint.Settings.ToggleKey) && AreMenusClosed())
|
||||||
|
{
|
||||||
|
MenuManager.mainMenu.Visible = !MenuManager.mainMenu.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Game.IsKeyDownRightNow(EntryPoint.Settings.ModifierKey) && Game.IsKeyDown(EntryPoint.Settings.ToggleKey) && AreMenusClosed())
|
||||||
|
{
|
||||||
|
MenuManager.mainMenu.Visible = !MenuManager.mainMenu.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool AreMenusClosed()
|
||||||
|
{
|
||||||
|
if(!MenuManager.barrierMenu.Visible && !MenuManager.pathMenu.Visible && !MenuManager.pathCreationMenu.Visible && !MenuManager.editPathMenu.Visible && !MenuManager.editWaypointMenu.Visible && !MenuManager.settingsMenu.Visible)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
67
SceneManager/MenuManager.cs
Normal file
67
SceneManager/MenuManager.cs
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Drawing;
|
||||||
|
using Rage;
|
||||||
|
using RAGENativeUI;
|
||||||
|
using RAGENativeUI.Elements;
|
||||||
|
|
||||||
|
namespace SceneManager
|
||||||
|
{
|
||||||
|
public static class MenuManager
|
||||||
|
{
|
||||||
|
public static MenuPool menuPool = new MenuPool();
|
||||||
|
public static UIMenu mainMenu, pathMenu, barrierMenu, pathCreationMenu, editPathMenu, editWaypointMenu, settingsMenu;
|
||||||
|
|
||||||
|
public static void InstantiateMenus()
|
||||||
|
{
|
||||||
|
mainMenu = new UIMenu("Scene Manager", "");
|
||||||
|
settingsMenu = new UIMenu("Scene Menu", "~o~Plugin Settings");
|
||||||
|
settingsMenu.ParentMenu = mainMenu;
|
||||||
|
pathMenu = new UIMenu("Scene Manager", "~o~Path Menu");
|
||||||
|
pathMenu.ParentMenu = mainMenu;
|
||||||
|
pathCreationMenu = new UIMenu("Scene Manager", "~o~Path Creation");
|
||||||
|
pathCreationMenu.ParentMenu = pathMenu;
|
||||||
|
barrierMenu = new UIMenu("Scene Manager", "~o~Barrier Management");
|
||||||
|
barrierMenu.ParentMenu = mainMenu;
|
||||||
|
editPathMenu = new UIMenu("Scene Manager", "~o~Edit Path");
|
||||||
|
editPathMenu.ParentMenu = pathMenu;
|
||||||
|
editWaypointMenu = new UIMenu("Scene Manager", "~o~Edit Waypoint");
|
||||||
|
editWaypointMenu.ParentMenu = editPathMenu;
|
||||||
|
|
||||||
|
AddMenusToMenuPool();
|
||||||
|
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();
|
||||||
|
TrafficMenu.BuildPathMenu();
|
||||||
|
PathCreationMenu.BuildPathCreationMenu();
|
||||||
|
EditPathMenu.BuildEditPathMenu();
|
||||||
|
BarrierMenu.BuildBarrierMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddMenusToMenuPool()
|
||||||
|
{
|
||||||
|
menuPool.Add(mainMenu);
|
||||||
|
menuPool.Add(settingsMenu);
|
||||||
|
menuPool.Add(pathMenu);
|
||||||
|
menuPool.Add(barrierMenu);
|
||||||
|
menuPool.Add(pathCreationMenu);
|
||||||
|
menuPool.Add(editPathMenu);
|
||||||
|
menuPool.Add(editWaypointMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
223
SceneManager/Menus/BarrierMenu.cs
Normal file
223
SceneManager/Menus/BarrierMenu.cs
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Rage;
|
||||||
|
using RAGENativeUI;
|
||||||
|
using RAGENativeUI.Elements;
|
||||||
|
|
||||||
|
namespace SceneManager
|
||||||
|
{
|
||||||
|
class BarrierMenu
|
||||||
|
{
|
||||||
|
public static List<Rage.Object> barriers = new List<Rage.Object>() { };
|
||||||
|
|
||||||
|
// TODO: Refactor as dictionary
|
||||||
|
private static UIMenuListScrollerItem<string> barrierList = new UIMenuListScrollerItem<string>("Select Barrier", "", new[] { "Large Striped Cone", "Large Cone", "Medium Striped Cone", "Medium Cone", "Roadpole A", "Roadpole B", "Police Barrier", "Road Barrier", "Flare" });
|
||||||
|
private static string[] barrierObjectNames = new string[] { "prop_mp_cone_01", "prop_roadcone01c", "prop_mp_cone_02", "prop_mp_cone_03", "prop_roadpole_01a", "prop_roadpole_01b", "prop_barrier_work05", "prop_barrier_work06a", "prop_flare_01b" };
|
||||||
|
private static UIMenuNumericScrollerItem<int> rotateBarrier = new UIMenuNumericScrollerItem<int>("Rotate Barrier", "Rotate the barrier.", 0, 359, 10);
|
||||||
|
private static UIMenuListScrollerItem<string> removeBarrierOptions = new UIMenuListScrollerItem<string>("Remove Barrier", "", new[] { "Last Barrier", "Nearest Barrier", "All Barriers" });
|
||||||
|
public static Rage.Object shadowBarrier;
|
||||||
|
|
||||||
|
public static void BuildBarrierMenu()
|
||||||
|
{
|
||||||
|
MenuManager.barrierMenu.AddItem(removeBarrierOptions, 0);
|
||||||
|
removeBarrierOptions.Enabled = false;
|
||||||
|
MenuManager.barrierMenu.AddItem(rotateBarrier, 0);
|
||||||
|
MenuManager.barrierMenu.AddItem(barrierList, 0);
|
||||||
|
MenuManager.barrierMenu.RefreshIndex();
|
||||||
|
|
||||||
|
MenuManager.barrierMenu.OnItemSelect += BarrierMenu_OnItemSelected;
|
||||||
|
MenuManager.barrierMenu.OnScrollerChange += BarrierMenu_OnScrollerChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CreateShadowBarrier(UIMenu barrierMenu)
|
||||||
|
{
|
||||||
|
if (EntryPoint.Settings.EnableHints)
|
||||||
|
{
|
||||||
|
Game.DisplayNotification($"~o~Scene Manager\n~y~[Hint]~y~ ~w~The shadow cone will disappear if you aim too far away.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Game.LogTrivial("Creating shadow cone");
|
||||||
|
if (shadowBarrier)
|
||||||
|
shadowBarrier.Delete();
|
||||||
|
|
||||||
|
shadowBarrier = new Rage.Object(barrierObjectNames[barrierList.Index], TracePlayerView(15, TraceFlags.IntersectEverything).HitPosition, rotateBarrier.Index);
|
||||||
|
Rage.Native.NativeFunction.Natives.PLACE_OBJECT_ON_GROUND_PROPERLY(shadowBarrier);
|
||||||
|
shadowBarrier.IsGravityDisabled = true;
|
||||||
|
shadowBarrier.IsCollisionEnabled = false;
|
||||||
|
shadowBarrier.Opacity = 0.7f;
|
||||||
|
|
||||||
|
GameFiber ShadowConeLoopFiber = new GameFiber(() => LoopToDisplayShadowBarrier(barrierMenu));
|
||||||
|
ShadowConeLoopFiber.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LoopToDisplayShadowBarrier(UIMenu coneMenu)
|
||||||
|
{
|
||||||
|
while (coneMenu.Visible && shadowBarrier)
|
||||||
|
{
|
||||||
|
UpdateShadowBarrierPosition();
|
||||||
|
GameFiber.Yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shadowBarrier)
|
||||||
|
shadowBarrier.Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void UpdateShadowBarrierPosition()
|
||||||
|
{
|
||||||
|
DisableBarrierMenuOptionsIfShadowConeTooFar();
|
||||||
|
shadowBarrier.Position = TracePlayerView(15, TraceFlags.IntersectEverything).HitPosition;
|
||||||
|
Rage.Native.NativeFunction.Natives.PLACE_OBJECT_ON_GROUND_PROPERLY(shadowBarrier);
|
||||||
|
shadowBarrier.Heading = rotateBarrier.Index;
|
||||||
|
|
||||||
|
void DisableBarrierMenuOptionsIfShadowConeTooFar()
|
||||||
|
{
|
||||||
|
if (shadowBarrier.Position.DistanceTo2D(Game.LocalPlayer.Character.Position) > 15f)
|
||||||
|
{
|
||||||
|
barrierList.Enabled = false;
|
||||||
|
rotateBarrier.Enabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
barrierList.Enabled = true;
|
||||||
|
rotateBarrier.Enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BarrierMenu_OnScrollerChange(UIMenu sender, UIMenuScrollerItem scrollerItem, int oldIndex, int newIndex)
|
||||||
|
{
|
||||||
|
if (scrollerItem == barrierList)
|
||||||
|
{
|
||||||
|
CreateShadowBarrier(MenuManager.barrierMenu);
|
||||||
|
|
||||||
|
if (barrierObjectNames[barrierList.Index] == "prop_flare_01b")
|
||||||
|
{
|
||||||
|
rotateBarrier.Enabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rotateBarrier.Enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scrollerItem == rotateBarrier)
|
||||||
|
{
|
||||||
|
shadowBarrier.Heading = rotateBarrier.Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BarrierMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||||
|
{
|
||||||
|
if (selectedItem == barrierList as UIMenuItem)
|
||||||
|
{
|
||||||
|
// Attach some invisible object to the cone which the AI try to drive around
|
||||||
|
// Barrier rotates with cone and becomes invisible similar to ASC when created
|
||||||
|
|
||||||
|
if (shadowBarrier.Model.Name == "prop_flare_01b".ToUpper())
|
||||||
|
{
|
||||||
|
SpawnFlare();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SpawnBarrier();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedItem == removeBarrierOptions as UIMenuItem)
|
||||||
|
{
|
||||||
|
RemoveBarrier();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SpawnBarrier()
|
||||||
|
{
|
||||||
|
var cone = new Rage.Object(shadowBarrier.Model, shadowBarrier.Position, rotateBarrier.Index);
|
||||||
|
cone.SetPositionWithSnap(shadowBarrier.Position);
|
||||||
|
Rage.Native.NativeFunction.Natives.SET_DISABLE_FRAG_DAMAGE(cone, true);
|
||||||
|
Rage.Native.NativeFunction.Natives.SET_DISABLE_BREAKING(cone, true);
|
||||||
|
|
||||||
|
barriers.Add(cone);
|
||||||
|
removeBarrierOptions.Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RemoveBarrier()
|
||||||
|
{
|
||||||
|
switch (removeBarrierOptions.Index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
barriers[barriers.Count - 1].Delete();
|
||||||
|
barriers.RemoveAt(barriers.Count - 1);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
barriers = barriers.OrderBy(c => c.DistanceTo(Game.LocalPlayer.Character)).ToList();
|
||||||
|
barriers[0].Delete();
|
||||||
|
barriers.RemoveAt(0);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
foreach (Rage.Object c in barriers.Where(c => c))
|
||||||
|
{
|
||||||
|
c.Delete();
|
||||||
|
}
|
||||||
|
if (barriers.Count > 0)
|
||||||
|
{
|
||||||
|
barriers.Clear();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBarrierOptions.Enabled = barriers.Count == 0 ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SpawnFlare()
|
||||||
|
{
|
||||||
|
var flare = new Weapon("weapon_flare", shadowBarrier.Position, 1);
|
||||||
|
flare.SetPositionWithSnap(shadowBarrier.Position);
|
||||||
|
|
||||||
|
// The purpose of this fiber is to allow the flare to spawn and fall to the ground naturally before freezing its position because you can't spawn it on the ground gracefully (it stands upright)
|
||||||
|
GameFiber.StartNew(delegate
|
||||||
|
{
|
||||||
|
GameFiber.Sleep(1000);
|
||||||
|
flare.IsPositionFrozen = true;
|
||||||
|
flare.IsCollisionEnabled = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
barriers.Add(flare);
|
||||||
|
removeBarrierOptions.Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------ CREDIT PNWPARKS FOR THESE FUNCTIONS ------------\\
|
||||||
|
// Implement Parks's 'Get Point Player is Looking At' script for better placement in 3rd person https://bitbucket.org/snippets/gtaparks/MeBKxX
|
||||||
|
internal static 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Vector3 GetPlayerLookingDirection() => GetPlayerLookingDirection(out Vector3 v1);
|
||||||
|
|
||||||
|
internal static HitResult TracePlayerView(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static HitResult TracePlayerView(float maxTraceDistance = 15f, TraceFlags flags = TraceFlags.IntersectEverything) => TracePlayerView(out Vector3 v1, out Vector3 v2, maxTraceDistance, flags);
|
||||||
|
//------------ CREDIT PNWPARKS FOR THESE FUNCTIONS ------------\\
|
||||||
|
}
|
||||||
|
}
|
||||||
75
SceneManager/Menus/EditPathMenu.cs
Normal file
75
SceneManager/Menus/EditPathMenu.cs
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
using System.Drawing;
|
||||||
|
using Rage;
|
||||||
|
using RAGENativeUI;
|
||||||
|
using RAGENativeUI.Elements;
|
||||||
|
|
||||||
|
namespace SceneManager
|
||||||
|
{
|
||||||
|
class EditPathMenu
|
||||||
|
{
|
||||||
|
private static UIMenuItem editPathWaypoints, deletePath;
|
||||||
|
public static UIMenuCheckboxItem togglePath, debugGraphics;
|
||||||
|
|
||||||
|
public static void BuildEditPathMenu()
|
||||||
|
{
|
||||||
|
MenuManager.editPathMenu.AddItem(togglePath = new UIMenuCheckboxItem("Disable Path", false));
|
||||||
|
MenuManager.editPathMenu.AddItem(editPathWaypoints = new UIMenuItem("Edit Waypoints"));
|
||||||
|
MenuManager.editPathMenu.AddItem(deletePath = new UIMenuItem("Delete Path"));
|
||||||
|
//MenuManager.editPathMenu.AddItem(debugGraphics = new UIMenuCheckboxItem("Enable Debug Graphics", false));
|
||||||
|
|
||||||
|
MenuManager.editPathMenu.RefreshIndex();
|
||||||
|
MenuManager.editPathMenu.OnItemSelect += EditPath_OnItemSelected;
|
||||||
|
MenuManager.editPathMenu.OnCheckboxChange += EditPath_OnCheckboxChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EditPath_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||||
|
{
|
||||||
|
var currentPath = TrafficMenu.paths[TrafficMenu.editPath.Index];
|
||||||
|
|
||||||
|
if (selectedItem == editPathWaypoints)
|
||||||
|
{
|
||||||
|
EditWaypointMenu.BuildEditWaypointMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedItem == deletePath)
|
||||||
|
{
|
||||||
|
TrafficMenu.DeletePath(currentPath, currentPath.PathNum - 1, "Single");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EditPath_OnCheckboxChange(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked)
|
||||||
|
{
|
||||||
|
if (checkboxItem == togglePath)
|
||||||
|
{
|
||||||
|
if (togglePath.Checked)
|
||||||
|
{
|
||||||
|
TrafficMenu.paths[TrafficMenu.editPath.Index].PathDisabled = true;
|
||||||
|
Game.LogTrivial($"Path {TrafficMenu.paths[TrafficMenu.editPath.Index].PathNum} disabled.");
|
||||||
|
|
||||||
|
foreach (Waypoint wd in TrafficMenu.paths[TrafficMenu.editPath.Index].Waypoint)
|
||||||
|
{
|
||||||
|
wd.WaypointBlip.Alpha = 0.5f;
|
||||||
|
if (wd.CollectorRadiusBlip)
|
||||||
|
{
|
||||||
|
wd.CollectorRadiusBlip.Alpha = 0.25f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TrafficMenu.paths[TrafficMenu.editPath.Index].PathDisabled = false;
|
||||||
|
Game.LogTrivial($"Path {TrafficMenu.paths[TrafficMenu.editPath.Index].PathNum} enabled.");
|
||||||
|
|
||||||
|
foreach (Waypoint wd in TrafficMenu.paths[TrafficMenu.editPath.Index].Waypoint)
|
||||||
|
{
|
||||||
|
wd.WaypointBlip.Alpha = 1.0f;
|
||||||
|
if (wd.CollectorRadiusBlip)
|
||||||
|
{
|
||||||
|
wd.CollectorRadiusBlip.Alpha = 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
189
SceneManager/Menus/EditWaypointMenu.cs
Normal file
189
SceneManager/Menus/EditWaypointMenu.cs
Normal file
|
|
@ -0,0 +1,189 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Rage;
|
||||||
|
using RAGENativeUI;
|
||||||
|
using RAGENativeUI.Elements;
|
||||||
|
|
||||||
|
namespace SceneManager
|
||||||
|
{
|
||||||
|
class EditWaypointMenu
|
||||||
|
{
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete, clear NUI squiggles
|
||||||
|
private static UIMenuItem editUpdateWaypoint, editRemoveWaypoint;
|
||||||
|
private static UIMenuListItem editWaypoint, changeWaypointType, changeWaypointSpeed, changeCollectorRadius;
|
||||||
|
private static UIMenuCheckboxItem collectorWaypoint, updateWaypointPosition;
|
||||||
|
|
||||||
|
private static List<dynamic> pathWaypoints = new List<dynamic>() { };
|
||||||
|
private static List<dynamic> waypointSpeeds = new List<dynamic>() { 5f, 10f, 15f, 20f, 30f, 40f, 50f, 60f, 70f };
|
||||||
|
private static List<dynamic> waypointTypes = new List<dynamic>() { "Drive To", "Stop" };
|
||||||
|
private static List<dynamic> collectorRadii = new List<dynamic>() { 3f, 5f, 10f, 15f, 20f, 30f, 40f, 50f };
|
||||||
|
private static VehicleDrivingFlags[] drivingFlags = new VehicleDrivingFlags[] { VehicleDrivingFlags.Normal, VehicleDrivingFlags.StopAtDestination };
|
||||||
|
|
||||||
|
public static void BuildEditWaypointMenu()
|
||||||
|
{
|
||||||
|
// Need to unsubscribe from these or else there will be duplicate firings if the user left the menu, then re-entered
|
||||||
|
MenuManager.editWaypointMenu.OnItemSelect -= EditWaypoint_OnItemSelected;
|
||||||
|
MenuManager.editWaypointMenu.OnListChange -= EditWaypoint_OnListChanged;
|
||||||
|
|
||||||
|
var currentPath = TrafficMenu.paths[TrafficMenu.editPath.Index];
|
||||||
|
//var currentWaypoint = currentPath.WaypointData[editWaypoint.Index]; // Can't use this before the menu is created, will this be a problem elsewhere?
|
||||||
|
|
||||||
|
// Populating menu list so user can select which waypoint to edit by index
|
||||||
|
pathWaypoints.Clear();
|
||||||
|
for (int i = 0; i < currentPath.Waypoint.Count; i++)
|
||||||
|
{
|
||||||
|
pathWaypoints.Add(i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuManager.editWaypointMenu.Clear();
|
||||||
|
MenuManager.editWaypointMenu.AddItem(editWaypoint = new UIMenuListItem("Edit Waypoint", pathWaypoints, 0));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(changeWaypointType = new UIMenuListItem("Change Waypoint Type", waypointTypes, Array.IndexOf(drivingFlags, currentPath.Waypoint[editWaypoint.Index].DrivingFlag)));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(changeWaypointSpeed = new UIMenuListItem("Change Waypoint Speed", waypointSpeeds, waypointSpeeds.IndexOf(currentPath.Waypoint[editWaypoint.Index].Speed)));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(collectorWaypoint = new UIMenuCheckboxItem("Collector Waypoint", TrafficMenu.paths[TrafficMenu.editPath.Index].Waypoint[editWaypoint.Index].Collector));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(changeCollectorRadius = new UIMenuListItem("Change Collection Radius", collectorRadii, collectorRadii.IndexOf(currentPath.Waypoint[editWaypoint.Index].CollectorRadius)));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(updateWaypointPosition = new UIMenuCheckboxItem("Update Waypoint Position", false));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(editUpdateWaypoint = new UIMenuItem("Update Waypoint"));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(editRemoveWaypoint = new UIMenuItem("Remove Waypoint"));
|
||||||
|
|
||||||
|
MenuManager.editPathMenu.Visible = false;
|
||||||
|
MenuManager.editWaypointMenu.RefreshIndex();
|
||||||
|
MenuManager.editWaypointMenu.Visible = true;
|
||||||
|
|
||||||
|
MenuManager.editWaypointMenu.OnItemSelect += EditWaypoint_OnItemSelected;
|
||||||
|
MenuManager.editWaypointMenu.OnListChange += EditWaypoint_OnListChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EditWaypoint_OnListChanged(UIMenu sender, UIMenuListItem listItem, int index)
|
||||||
|
{
|
||||||
|
var currentPath = TrafficMenu.paths[TrafficMenu.editPath.Index];
|
||||||
|
var currentWaypoint = currentPath.Waypoint[editWaypoint.Index];
|
||||||
|
|
||||||
|
if (listItem == editWaypoint)
|
||||||
|
{
|
||||||
|
while (MenuManager.editWaypointMenu.MenuItems.Count > 1)
|
||||||
|
{
|
||||||
|
MenuManager.editWaypointMenu.RemoveItemAt(1);
|
||||||
|
GameFiber.Yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuManager.editWaypointMenu.AddItem(changeWaypointType = new UIMenuListItem("Change Waypoint Type", waypointTypes, Array.IndexOf(drivingFlags, currentWaypoint.DrivingFlag)));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(changeWaypointSpeed = new UIMenuListItem("Change Waypoint Speed", waypointSpeeds, waypointSpeeds.IndexOf(currentWaypoint.Speed)));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(collectorWaypoint = new UIMenuCheckboxItem("Attractor Waypoint", currentWaypoint.Collector));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(changeCollectorRadius = new UIMenuListItem("Change Collection Radius", collectorRadii, collectorRadii.IndexOf(currentPath.Waypoint[editWaypoint.Index].CollectorRadius)));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(updateWaypointPosition = new UIMenuCheckboxItem("Update Waypoint Position", false));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(editUpdateWaypoint = new UIMenuItem("Update Waypoint"));
|
||||||
|
MenuManager.editWaypointMenu.AddItem(editRemoveWaypoint = new UIMenuItem("Remove Waypoint"));
|
||||||
|
MenuManager.editWaypointMenu.RefreshIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crashed here updating waypoint position for waypoint 2/2
|
||||||
|
private static void EditWaypoint_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||||
|
{
|
||||||
|
var currentPath = TrafficMenu.paths[TrafficMenu.editPath.Index];
|
||||||
|
var currentWaypoint = currentPath.Waypoint[editWaypoint.Index];
|
||||||
|
|
||||||
|
if (selectedItem == editUpdateWaypoint)
|
||||||
|
{
|
||||||
|
currentWaypoint.DrivingFlag = drivingFlags[changeWaypointType.Index];
|
||||||
|
currentWaypoint.Speed = waypointSpeeds[changeWaypointSpeed.Index];
|
||||||
|
if (updateWaypointPosition.Checked)
|
||||||
|
{
|
||||||
|
currentWaypoint.WaypointPos = Game.LocalPlayer.Character.Position;
|
||||||
|
currentWaypoint.WaypointBlip.Position = Game.LocalPlayer.Character.Position;
|
||||||
|
if (currentWaypoint.CollectorRadiusBlip)
|
||||||
|
{
|
||||||
|
currentWaypoint.CollectorRadiusBlip.Position = Game.LocalPlayer.Character.Position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collectorWaypoint.Checked)
|
||||||
|
{
|
||||||
|
currentWaypoint.Collector = true;
|
||||||
|
var yieldZone = World.AddSpeedZone(Game.LocalPlayer.Character.Position, 50f, currentWaypoint.Speed);
|
||||||
|
currentWaypoint.YieldZone = yieldZone;
|
||||||
|
if (currentWaypoint.CollectorRadiusBlip)
|
||||||
|
{
|
||||||
|
//currentWaypoint.CollectorRadiusBlip.Color = currentWaypoint.WaypointBlip.Color;
|
||||||
|
currentWaypoint.CollectorRadiusBlip.Alpha = 0.5f;
|
||||||
|
currentWaypoint.CollectorRadiusBlip.Scale = collectorRadii[changeCollectorRadius.Index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentWaypoint.CollectorRadiusBlip = new Blip(currentWaypoint.WaypointBlip.Position, collectorRadii[changeCollectorRadius.Index])
|
||||||
|
{
|
||||||
|
Color = currentWaypoint.WaypointBlip.Color,
|
||||||
|
Alpha = 0.5f
|
||||||
|
};
|
||||||
|
}
|
||||||
|
currentWaypoint.CollectorRadius = collectorRadii[changeCollectorRadius.Index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentWaypoint.Collector = false;
|
||||||
|
World.RemoveSpeedZone(currentWaypoint.YieldZone);
|
||||||
|
currentWaypoint.YieldZone = 0;
|
||||||
|
if (currentWaypoint.CollectorRadiusBlip)
|
||||||
|
{
|
||||||
|
//currentWaypoint.CollectorRadiusBlip.Color = currentWaypoint.WaypointBlip.Color;
|
||||||
|
currentWaypoint.CollectorRadiusBlip.Alpha = 0.25f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Game.LogTrivial($"Updated path {currentPath.PathNum} waypoint {currentWaypoint.WaypointNum}: Driving flag is {drivingFlags[changeWaypointType.Index].ToString()}, speed is {waypointSpeeds[changeWaypointSpeed.Index].ToString()}, collector is {currentWaypoint.Collector}");
|
||||||
|
|
||||||
|
if (currentPath.Waypoint.Count < 2 && currentPath.Waypoint[0].DrivingFlag == VehicleDrivingFlags.StopAtDestination)
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"The remaining waypoint was updated to be a stop waypoint. Enabling/disabling the path is no longer locked.");
|
||||||
|
EditPathMenu.togglePath.Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Game.DisplayNotification($"~o~Scene Manager\n~g~[Success]~w~ Waypoint {currentWaypoint.WaypointNum} updated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedItem == editRemoveWaypoint)
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"[Path {currentPath.PathNum}] Waypoint {currentWaypoint.WaypointNum} ({currentWaypoint.DrivingFlag}) removed");
|
||||||
|
if (currentPath.Waypoint.Count == 1)
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"Deleting the last waypoint from the path.");
|
||||||
|
TrafficMenu.DeletePath(currentPath, currentPath.PathNum - 1, "Single");
|
||||||
|
//pathWaypoints.Clear();
|
||||||
|
//editPathMenu.Clear();
|
||||||
|
MenuManager.editWaypointMenu.Visible = false;
|
||||||
|
MenuManager.pathMenu.Visible = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentWaypoint.WaypointBlip.Delete(); // Delete the waypoint's blip
|
||||||
|
if (currentWaypoint.CollectorRadiusBlip)
|
||||||
|
{
|
||||||
|
currentWaypoint.CollectorRadiusBlip.Delete();
|
||||||
|
}
|
||||||
|
currentPath.Waypoint.Remove(currentWaypoint); // Delete the waypoint's data object
|
||||||
|
pathWaypoints.RemoveAt(editWaypoint.Index); // Remove the waypoint from the menu list
|
||||||
|
|
||||||
|
// Will this have adverse affects on vehicles currently following the path?
|
||||||
|
// Update waypoint number for each waypoint in the path's waypoint data
|
||||||
|
foreach (Waypoint wp in currentPath.Waypoint)
|
||||||
|
{
|
||||||
|
wp.WaypointNum = currentPath.Waypoint.IndexOf(wp) + 1;
|
||||||
|
Game.LogTrivial($"Waypoint at index {currentPath.Waypoint.IndexOf(wp)} is now waypoint #{wp.WaypointNum}");
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildEditWaypointMenu();
|
||||||
|
|
||||||
|
if (currentPath.Waypoint.Count == 1 && currentPath.Waypoint[0].DrivingFlag != VehicleDrivingFlags.StopAtDestination)
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"The path only has 1 waypoint left, and the waypoint is not a stop waypoint. Disabling the path.");
|
||||||
|
currentPath.PathDisabled = true;
|
||||||
|
EditPathMenu.togglePath.Checked = true;
|
||||||
|
EditPathMenu.togglePath.Enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
SceneManager/Menus/MainMenu.cs
Normal file
37
SceneManager/Menus/MainMenu.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Rage;
|
||||||
|
using RAGENativeUI;
|
||||||
|
using RAGENativeUI.Elements;
|
||||||
|
|
||||||
|
namespace SceneManager
|
||||||
|
{
|
||||||
|
class MainMenu
|
||||||
|
{
|
||||||
|
private static UIMenuItem navigateToPathMenu, navigateToBarrierMenu, navigateToSettingsMenu;
|
||||||
|
|
||||||
|
public static void BuildMainMenu()
|
||||||
|
{
|
||||||
|
MenuManager.mainMenu.AddItem(navigateToPathMenu = new UIMenuItem("~o~Path Menu"));
|
||||||
|
MenuManager.mainMenu.BindMenuToItem(MenuManager.pathMenu, navigateToPathMenu);
|
||||||
|
MenuManager.mainMenu.AddItem(navigateToBarrierMenu = new UIMenuItem("~o~Barrier Menu"));
|
||||||
|
MenuManager.mainMenu.BindMenuToItem(MenuManager.barrierMenu, navigateToBarrierMenu);
|
||||||
|
MenuManager.mainMenu.AddItem(navigateToSettingsMenu = new UIMenuItem("~o~Settings"));
|
||||||
|
MenuManager.mainMenu.BindMenuToItem(MenuManager.settingsMenu, navigateToSettingsMenu);
|
||||||
|
|
||||||
|
MenuManager.mainMenu.RefreshIndex();
|
||||||
|
MenuManager.mainMenu.OnItemSelect += MainMenu_OnItemSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MainMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||||
|
{
|
||||||
|
if (selectedItem == navigateToBarrierMenu)
|
||||||
|
{
|
||||||
|
BarrierMenu.CreateShadowBarrier(MenuManager.barrierMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
241
SceneManager/Menus/PathCreationMenu.cs
Normal file
241
SceneManager/Menus/PathCreationMenu.cs
Normal file
|
|
@ -0,0 +1,241 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Rage;
|
||||||
|
using RAGENativeUI;
|
||||||
|
using RAGENativeUI.Elements;
|
||||||
|
|
||||||
|
namespace SceneManager
|
||||||
|
{
|
||||||
|
class PathCreationMenu
|
||||||
|
{
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete, clear NUI squiggles
|
||||||
|
public static UIMenuItem trafficAddWaypoint, trafficRemoveWaypoint, trafficEndPath;
|
||||||
|
public static UIMenuListItem waypointType, waypointSpeed, collectorRadius;
|
||||||
|
private static UIMenuCheckboxItem collectorWaypoint;
|
||||||
|
|
||||||
|
private static List<dynamic> waypointSpeeds = new List<dynamic>() { 5f, 10f, 15f, 20f, 30f, 40f, 50f, 60f, 70f };
|
||||||
|
//private enum waypointTypes {DriveTo, Stop };
|
||||||
|
private static List<dynamic> waypointTypes = new List<dynamic>() { "Drive To", "Stop" };
|
||||||
|
private static List<dynamic> collectorRadii = new List<dynamic>() { 3f, 5f, 10f, 15f, 20f, 30f, 40f, 50f };
|
||||||
|
private static VehicleDrivingFlags[] drivingFlags = new VehicleDrivingFlags[] { VehicleDrivingFlags.Normal, VehicleDrivingFlags.StopAtDestination }; // Implement custom driving flag for normal
|
||||||
|
|
||||||
|
// Called from EditPathMenu
|
||||||
|
public static void BuildPathCreationMenu()
|
||||||
|
{
|
||||||
|
MenuManager.pathCreationMenu.AddItem(waypointType = new UIMenuListItem("Waypoint Type", waypointTypes, 0));
|
||||||
|
MenuManager.pathCreationMenu.AddItem(waypointSpeed = new UIMenuListItem($"Waypoint Speed (in {SettingsMenu.speedUnits.SelectedItem})", waypointSpeeds, 0));
|
||||||
|
MenuManager.pathCreationMenu.AddItem(collectorWaypoint = new UIMenuCheckboxItem("Collector", false));
|
||||||
|
MenuManager.pathCreationMenu.AddItem(collectorRadius = new UIMenuListItem("Collection Radius", collectorRadii, 0));
|
||||||
|
MenuManager.pathCreationMenu.AddItem(trafficAddWaypoint = new UIMenuItem("Add waypoint"));
|
||||||
|
MenuManager.pathCreationMenu.AddItem(trafficRemoveWaypoint = new UIMenuItem("Remove last waypoint"));
|
||||||
|
trafficRemoveWaypoint.Enabled = false;
|
||||||
|
MenuManager.pathCreationMenu.AddItem(trafficEndPath = new UIMenuItem("End path creation"));
|
||||||
|
|
||||||
|
MenuManager.pathCreationMenu.RefreshIndex();
|
||||||
|
MenuManager.pathCreationMenu.OnItemSelect += PathCreation_OnItemSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PathCreation_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||||
|
{
|
||||||
|
// Do I need to implement a distance restriction? Idiots place waypoints unnecessarily close, possibly causing AI to drive in circles
|
||||||
|
if (selectedItem == trafficAddWaypoint)
|
||||||
|
{
|
||||||
|
uint yieldZone = 0;
|
||||||
|
float speed;
|
||||||
|
|
||||||
|
// Loop through each path and find the first one which isn't finished
|
||||||
|
var getFirstNonNullPath = TrafficMenu.paths.Where(p => p != null && !p.PathFinished).First();
|
||||||
|
var pathIndex = TrafficMenu.paths.IndexOf(getFirstNonNullPath);
|
||||||
|
|
||||||
|
// Create a waypoint blip and set the sprite based on the current path number
|
||||||
|
var blip = new Blip(Game.LocalPlayer.Character.Position)
|
||||||
|
{
|
||||||
|
Scale = 0.5f
|
||||||
|
};
|
||||||
|
switch (pathIndex)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
blip.Sprite = BlipSprite.Numbered1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
blip.Sprite = BlipSprite.Numbered2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
blip.Sprite = BlipSprite.Numbered3;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
blip.Sprite = BlipSprite.Numbered4;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
blip.Sprite = BlipSprite.Numbered5;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
blip.Sprite = BlipSprite.Numbered6;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
blip.Sprite = BlipSprite.Numbered7;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
blip.Sprite = BlipSprite.Numbered8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's the first waypoint, make the blip orange, else make it yellow
|
||||||
|
if (TrafficMenu.paths[pathIndex].Waypoint.Count == 0)
|
||||||
|
{
|
||||||
|
blip.Color = Color.Orange;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blip.Color = Color.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collectorWaypoint.Checked)
|
||||||
|
{
|
||||||
|
if(SettingsMenu.speedUnits.SelectedItem == SettingsMenu.SpeedUnitsOfMeasure.MPH)
|
||||||
|
{
|
||||||
|
yieldZone = World.AddSpeedZone(Game.LocalPlayer.Character.Position, 50f, MathHelper.ConvertMilesPerHourToMetersPerSecond(waypointSpeeds[waypointSpeed.Index]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yieldZone = World.AddSpeedZone(Game.LocalPlayer.Character.Position, 50f, MathHelper.ConvertKilometersPerHourToMetersPerSecond(waypointSpeeds[waypointSpeed.Index]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SettingsMenu.speedUnits.SelectedItem == SettingsMenu.SpeedUnitsOfMeasure.MPH)
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"Original speed: {waypointSpeeds[waypointSpeed.Index]}{SettingsMenu.speedUnits.SelectedItem}");
|
||||||
|
speed = MathHelper.ConvertMilesPerHourToMetersPerSecond(waypointSpeeds[waypointSpeed.Index]);
|
||||||
|
Game.LogTrivial($"Converted speed: {speed}m/s");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"Original speed: {waypointSpeeds[waypointSpeed.Index]}{SettingsMenu.speedUnits.SelectedItem}");
|
||||||
|
speed = MathHelper.ConvertKilometersPerHourToMetersPerSecond(waypointSpeeds[waypointSpeed.Index]);
|
||||||
|
Game.LogTrivial($"Converted speed: {speed}m/s");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the waypoint data to the path
|
||||||
|
TrafficMenu.paths[pathIndex].Waypoint.Add(new Waypoint(pathIndex + 1, TrafficMenu.paths[pathIndex].Waypoint.Count + 1, Game.LocalPlayer.Character.Position, speed, drivingFlags[waypointType.Index], blip, collectorWaypoint.Checked, collectorRadii[collectorRadius.Index], yieldZone));
|
||||||
|
Game.LogTrivial($"[Path {pathIndex + 1}] Waypoint {TrafficMenu.paths[pathIndex].Waypoint[TrafficMenu.paths[pathIndex].Waypoint.Count - 1].WaypointNum} ({drivingFlags[waypointType.Index].ToString()}) added");
|
||||||
|
|
||||||
|
// Refresh the trafficMenu after a waypoint is added in order to show Continue Creating Current Path instead of Create New Path
|
||||||
|
RefreshTrafficMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedItem == trafficRemoveWaypoint)
|
||||||
|
{
|
||||||
|
// Loop through each path and find the first one which isn't finished, then delete the path's last waypoint and corresponding blip
|
||||||
|
for (int i = 0; i < TrafficMenu.paths.Count; i++)
|
||||||
|
{
|
||||||
|
if (TrafficMenu.paths.ElementAtOrDefault(i) != null && !TrafficMenu.paths[i].PathFinished)
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"[Path {i + 1}] {TrafficMenu.paths[i].Waypoint.Last().DrivingFlag.ToString()} waypoint removed");
|
||||||
|
TrafficMenu.paths[i].Waypoint.Last().WaypointBlip.Delete();
|
||||||
|
if (TrafficMenu.paths[i].Waypoint.Last().CollectorRadiusBlip)
|
||||||
|
{
|
||||||
|
TrafficMenu.paths[i].Waypoint.Last().CollectorRadiusBlip.Delete();
|
||||||
|
}
|
||||||
|
TrafficMenu.paths[i].Waypoint.RemoveAt(TrafficMenu.paths[i].Waypoint.IndexOf(TrafficMenu.paths[i].Waypoint.Last()));
|
||||||
|
|
||||||
|
// If the path has no waypoints, disable the menu option to remove a waypoint
|
||||||
|
if (TrafficMenu.paths[i].Waypoint.Count == 0)
|
||||||
|
{
|
||||||
|
trafficRemoveWaypoint.Enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedItem == trafficEndPath)
|
||||||
|
{
|
||||||
|
// Loop through each path and find the first one which isn't finished
|
||||||
|
for (int i = 0; i < TrafficMenu.paths.Count; i++)
|
||||||
|
{
|
||||||
|
if (TrafficMenu.paths.ElementAtOrDefault(i) != null && !TrafficMenu.paths[i].PathFinished)
|
||||||
|
{
|
||||||
|
// If the path has one stop waypoint or at least two waypoints, finish the path and start the vehicle collector loop, else show user the error and delete any waypoints they made and clear the invalid path
|
||||||
|
if (TrafficMenu.paths[i].Waypoint.Count >= 2 || (TrafficMenu.paths[i].Waypoint.Count == 1 && TrafficMenu.paths[i].Waypoint[0].DrivingFlag == VehicleDrivingFlags.StopAtDestination))
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"[Path Creation] Path {i + 1} finished with {TrafficMenu.paths[i].Waypoint.Count} waypoints.");
|
||||||
|
Game.DisplayNotification($"~o~Scene Manager\n~g~[Success]~w~ Path {i + 1} complete.");
|
||||||
|
TrafficMenu.paths[i].Waypoint.Last().WaypointBlip.Color = Color.OrangeRed;
|
||||||
|
if (TrafficMenu.paths[i].Waypoint.Last().CollectorRadiusBlip)
|
||||||
|
{
|
||||||
|
TrafficMenu.paths[i].Waypoint.Last().CollectorRadiusBlip.Color = Color.OrangeRed;
|
||||||
|
}
|
||||||
|
TrafficMenu.paths[i].PathFinished = true;
|
||||||
|
TrafficMenu.paths[i].PathDisabled = false;
|
||||||
|
TrafficMenu.paths[i].PathNum = i + 1;
|
||||||
|
TrafficMenu.pathsNum.Insert(i, TrafficMenu.paths[i].PathNum);
|
||||||
|
|
||||||
|
//GameFiber InitialWaypointVehicleCollectorFiber = new GameFiber(() => TrafficPathing.InitialWaypointVehicleCollector(paths[i]));
|
||||||
|
//InitialWaypointVehicleCollectorFiber.Start();
|
||||||
|
|
||||||
|
// For each waypoint in the path's WaypointData, start a collector game fiber and loop while the path and waypoint exist, and while the path is enabled
|
||||||
|
foreach (Waypoint wd in TrafficMenu.paths[i].Waypoint)
|
||||||
|
{
|
||||||
|
GameFiber WaypointVehicleCollectorFiber = new GameFiber(() => TrafficPathing.WaypointVehicleCollector(TrafficMenu.paths, TrafficMenu.paths[i], wd));
|
||||||
|
WaypointVehicleCollectorFiber.Start();
|
||||||
|
|
||||||
|
GameFiber AssignStopForVehiclesFlagFiber = new GameFiber(() => TrafficPathing.AssignStopForVehiclesFlag(TrafficMenu.paths, TrafficMenu.paths[i], wd));
|
||||||
|
AssignStopForVehiclesFlagFiber.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuManager.menuPool.CloseAllMenus();
|
||||||
|
MenuManager.pathMenu.Clear();
|
||||||
|
TrafficMenu.BuildPathMenu();
|
||||||
|
MenuManager.pathMenu.Visible = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"[Path Error] A minimum of 2 waypoints is required.");
|
||||||
|
Game.DisplayNotification($"~o~Scene Manager\n~r~[Error]~w~ A minimum of 2 waypoints or one stop waypoint is required to create a path.");
|
||||||
|
foreach (Waypoint wd in TrafficMenu.paths[i].Waypoint)
|
||||||
|
{
|
||||||
|
wd.WaypointBlip.Delete();
|
||||||
|
if (wd.CollectorRadiusBlip)
|
||||||
|
{
|
||||||
|
wd.CollectorRadiusBlip.Delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TrafficMenu.paths[i].Waypoint.Clear();
|
||||||
|
TrafficMenu.paths.RemoveAt(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Refresh" the menu to reflect the new path
|
||||||
|
//TrafficMenu.RebuildTrafficMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RefreshTrafficMenu()
|
||||||
|
{
|
||||||
|
trafficRemoveWaypoint.Enabled = true;
|
||||||
|
MenuManager.pathMenu.Clear();
|
||||||
|
MenuManager.pathMenu.AddItem(TrafficMenu.createNewPath = new UIMenuItem("Continue Creating Current Path"));
|
||||||
|
MenuManager.pathMenu.AddItem(TrafficMenu.deleteAllPaths = new UIMenuItem("Delete All Paths"));
|
||||||
|
MenuManager.pathMenu.AddItem(TrafficMenu.directDriver = new UIMenuListItem("Direct nearest driver to path", TrafficMenu.pathsNum, 0));
|
||||||
|
MenuManager.pathMenu.AddItem(TrafficMenu.dismissDriver = new UIMenuListItem("Dismiss nearest driver", TrafficMenu.dismissOptions, 0));
|
||||||
|
|
||||||
|
if (TrafficMenu.paths.Count == 8)
|
||||||
|
{
|
||||||
|
TrafficMenu.createNewPath.Enabled = false;
|
||||||
|
}
|
||||||
|
if (TrafficMenu.paths.Count == 0)
|
||||||
|
{
|
||||||
|
TrafficMenu.editPath.Enabled = false;
|
||||||
|
TrafficMenu.deleteAllPaths.Enabled = false;
|
||||||
|
TrafficMenu.disableAllPaths.Enabled = false;
|
||||||
|
TrafficMenu.directDriver.Enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
374
SceneManager/Menus/TrafficMenu.cs
Normal file
374
SceneManager/Menus/TrafficMenu.cs
Normal file
|
|
@ -0,0 +1,374 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using Rage;
|
||||||
|
using RAGENativeUI;
|
||||||
|
using RAGENativeUI.Elements;
|
||||||
|
|
||||||
|
namespace SceneManager
|
||||||
|
{
|
||||||
|
static class TrafficMenu
|
||||||
|
{
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete, clear NUI squiggles
|
||||||
|
public static UIMenuItem createNewPath, deleteAllPaths;
|
||||||
|
public static UIMenuListItem editPath, directDriver, dismissDriver;
|
||||||
|
public static UIMenuCheckboxItem disableAllPaths;
|
||||||
|
|
||||||
|
public static List<dynamic> pathsNum = new List<dynamic>() { };
|
||||||
|
public static List<Path> paths = new List<Path>() { };
|
||||||
|
public static List<dynamic> dismissOptions = new List<dynamic>() { "From path", "From waypoint", "From position" };
|
||||||
|
|
||||||
|
public static void BuildPathMenu()
|
||||||
|
{
|
||||||
|
// New stuff to mitigate Rebuild method
|
||||||
|
MenuManager.pathMenu.OnItemSelect -= PathMenu_OnItemSelected;
|
||||||
|
MenuManager.pathMenu.OnCheckboxChange -= PathMenu_OnCheckboxChange;
|
||||||
|
MenuManager.menuPool.CloseAllMenus();
|
||||||
|
MenuManager.pathMenu.Clear();
|
||||||
|
|
||||||
|
MenuManager.pathMenu.AddItem(createNewPath = new UIMenuItem("Create New Path"));
|
||||||
|
MenuManager.pathMenu.AddItem(editPath = new UIMenuListItem("Edit Path", pathsNum, 0));
|
||||||
|
MenuManager.pathMenu.AddItem(disableAllPaths = new UIMenuCheckboxItem("Disable All Paths", false));
|
||||||
|
MenuManager.pathMenu.AddItem(deleteAllPaths = new UIMenuItem("Delete All Paths"));
|
||||||
|
MenuManager.pathMenu.AddItem(directDriver = new UIMenuListItem("Direct nearest driver to path", pathsNum, 0));
|
||||||
|
MenuManager.pathMenu.AddItem(dismissDriver = new UIMenuListItem("Dismiss nearest driver", dismissOptions, 0));
|
||||||
|
|
||||||
|
if (paths.Count == 8)
|
||||||
|
{
|
||||||
|
createNewPath.Enabled = false;
|
||||||
|
}
|
||||||
|
if (paths.Count == 0)
|
||||||
|
{
|
||||||
|
editPath.Enabled = false;
|
||||||
|
deleteAllPaths.Enabled = false;
|
||||||
|
disableAllPaths.Enabled = false;
|
||||||
|
directDriver.Enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuManager.pathMenu.RefreshIndex();
|
||||||
|
MenuManager.pathMenu.OnItemSelect += PathMenu_OnItemSelected;
|
||||||
|
MenuManager.pathMenu.OnCheckboxChange += PathMenu_OnCheckboxChange;
|
||||||
|
|
||||||
|
// New stuff to mitigate Rebuild method
|
||||||
|
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 bool IsInCollectedVehicles(this Vehicle v)
|
||||||
|
{
|
||||||
|
if (v && TrafficPathing.collectedVehicles.ContainsKey(v.LicensePlate))
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"{v.Model.Name} was found in the collection.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"{v.Model.Name} was not found in the collection.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refactor string param to enum
|
||||||
|
public static void DeletePath(Path path, int index, string pathsToDelete)
|
||||||
|
{
|
||||||
|
// Before deleting a path, we need to dismiss any vehicles controlled by that path and remove the vehicles from ControlledVehicles
|
||||||
|
//Game.LogTrivial($"Deleting path {index+1}");
|
||||||
|
Game.LogTrivial($"Deleting path {path.PathNum}");
|
||||||
|
var pathVehicles = TrafficPathing.collectedVehicles.Where(cv => cv.Value.Path == path.PathNum).ToList();
|
||||||
|
|
||||||
|
Game.LogTrivial($"Removing all vehicles on the path");
|
||||||
|
foreach (KeyValuePair<string, ControlledVehicle> cv in pathVehicles.Where(cv => cv.Value.Vehicle && cv.Value.Vehicle.Driver))
|
||||||
|
{
|
||||||
|
cv.Value.DismissNow = true;
|
||||||
|
cv.Value.Vehicle.Driver.Tasks.Clear();
|
||||||
|
cv.Value.Vehicle.Driver.Dismiss();
|
||||||
|
cv.Value.Vehicle.Driver.IsPersistent = false;
|
||||||
|
cv.Value.Vehicle.Dismiss();
|
||||||
|
cv.Value.Vehicle.IsPersistent = false;
|
||||||
|
//TrafficPathing.ControlledVehicles.Remove(cv.Value.LicensePlate);
|
||||||
|
//Game.LogTrivial($"{cv.vehicle.Model.Name} cleared from path {cv.path}");
|
||||||
|
TrafficPathing.collectedVehicles.Remove(cv.Value.LicensePlate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the speed zone so cars don't continue to be affected after the path is deleted
|
||||||
|
Game.LogTrivial($"Removing yield zone and waypoint blips");
|
||||||
|
foreach (Waypoint wd in path.Waypoint)
|
||||||
|
{
|
||||||
|
if (wd.YieldZone != 0)
|
||||||
|
{
|
||||||
|
World.RemoveSpeedZone(wd.YieldZone);
|
||||||
|
}
|
||||||
|
if (wd.WaypointBlip)
|
||||||
|
{
|
||||||
|
wd.WaypointBlip.Delete();
|
||||||
|
}
|
||||||
|
if (wd.CollectorRadiusBlip)
|
||||||
|
{
|
||||||
|
wd.CollectorRadiusBlip.Delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Game.LogTrivial($"Clearing path.WaypointData");
|
||||||
|
path.Waypoint.Clear();
|
||||||
|
// Manipulating the menu to reflect specific paths being deleted
|
||||||
|
if (pathsToDelete == "Single")
|
||||||
|
{
|
||||||
|
paths.RemoveAt(index);
|
||||||
|
//Game.LogTrivial("pathsNum count: " + pathsNum.Count);
|
||||||
|
//Game.LogTrivial("index: " + index);
|
||||||
|
pathsNum.RemoveAt(index);
|
||||||
|
//RebuildTrafficMenu();
|
||||||
|
BuildPathMenu();
|
||||||
|
MenuManager.pathMenu.Visible = true;
|
||||||
|
Game.LogTrivial($"Path {path.PathNum} deleted.");
|
||||||
|
Game.DisplayNotification($"~o~Scene Manager\n~w~Path {path.PathNum} deleted.");
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuManager.editPathMenu.Reset(true, true);
|
||||||
|
EditPathMenu.togglePath.Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PathMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
||||||
|
{
|
||||||
|
if (selectedItem == createNewPath)
|
||||||
|
{
|
||||||
|
MenuManager.pathMenu.Visible = false;
|
||||||
|
MenuManager.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].PathFinished == false)
|
||||||
|
{
|
||||||
|
//Game.LogTrivial($"pathFinished: {paths[i].PathFinished}");
|
||||||
|
Game.LogTrivial($"Resuming path {i + 1}");
|
||||||
|
Game.DisplayNotification($"~o~Scene Manager\n~y~[Creating]~w~ Resuming path {i + 1}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (paths.ElementAtOrDefault(i) == null)
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"Creating path {i + 1}");
|
||||||
|
Game.DisplayNotification($"~o~Scene Manager\n~y~[Creating]~w~ Path {i + 1} started.");
|
||||||
|
paths.Insert(i, new Path(i + 1, false));
|
||||||
|
PathCreationMenu.trafficRemoveWaypoint.Enabled = false;
|
||||||
|
|
||||||
|
if (SettingsMenu.debugGraphics.Checked)
|
||||||
|
{
|
||||||
|
GameFiber.StartNew(() =>
|
||||||
|
{
|
||||||
|
while (SettingsMenu.debugGraphics.Checked && paths[i] != null)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < paths[i].Waypoint.Count; j++)
|
||||||
|
{
|
||||||
|
if (paths[i].Waypoint[j].Collector)
|
||||||
|
{
|
||||||
|
Debug.DrawSphere(paths[i].Waypoint[j].WaypointPos, paths[i].Waypoint[j].CollectorRadius, Color.FromArgb(80, Color.Blue));
|
||||||
|
}
|
||||||
|
else if (paths[i].Waypoint[j].DrivingFlag == VehicleDrivingFlags.StopAtDestination)
|
||||||
|
{
|
||||||
|
Debug.DrawSphere(paths[i].Waypoint[j].WaypointPos, 1f, Color.FromArgb(80, Color.Red));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.DrawSphere(paths[i].Waypoint[j].WaypointPos, 1f, Color.FromArgb(80, Color.Green));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j != paths[i].Waypoint.Count - 1)
|
||||||
|
{
|
||||||
|
Debug.DrawLine(paths[i].Waypoint[j].WaypointPos, paths[i].Waypoint[j + 1].WaypointPos, Color.White);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GameFiber.Yield();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedItem == editPath)
|
||||||
|
{
|
||||||
|
MenuManager.pathMenu.Visible = false;
|
||||||
|
MenuManager.editPathMenu.Visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedItem == deleteAllPaths)
|
||||||
|
{
|
||||||
|
// Iterate through each item in paths and delete it
|
||||||
|
for (int i = 0; i < paths.Count; i++)
|
||||||
|
{
|
||||||
|
DeletePath(paths[i], i, "All");
|
||||||
|
}
|
||||||
|
foreach (Path path in paths)
|
||||||
|
{
|
||||||
|
path.Waypoint.Clear();
|
||||||
|
}
|
||||||
|
paths.Clear();
|
||||||
|
pathsNum.Clear();
|
||||||
|
//RebuildTrafficMenu();
|
||||||
|
BuildPathMenu();
|
||||||
|
MenuManager.pathMenu.Visible = true;
|
||||||
|
Game.LogTrivial($"All paths deleted");
|
||||||
|
Game.DisplayNotification($"~o~Scene Manager\n~w~All paths deleted.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedItem == directDriver)
|
||||||
|
{
|
||||||
|
var nearbyVehicle = Game.LocalPlayer.Character.GetNearbyVehicles(1).Where(v => v.VehicleAndDriverValid()).SingleOrDefault();
|
||||||
|
if (nearbyVehicle)
|
||||||
|
{
|
||||||
|
if (nearbyVehicle.IsInCollectedVehicles())
|
||||||
|
{
|
||||||
|
var vehicle = TrafficPathing.collectedVehicles[nearbyVehicle.LicensePlate];
|
||||||
|
|
||||||
|
Game.LogTrivial($"[Direct Driver] {nearbyVehicle.Model.Name} already in collection. Clearing tasks.");
|
||||||
|
nearbyVehicle.Driver.Tasks.Clear();
|
||||||
|
vehicle.Path = paths[directDriver.Index].Waypoint[0].Path;
|
||||||
|
vehicle.TotalWaypoints = paths[directDriver.Index].Waypoint.Count;
|
||||||
|
vehicle.CurrentWaypoint = 1;
|
||||||
|
vehicle.DismissNow = true;
|
||||||
|
vehicle.StoppedAtWaypoint = false;
|
||||||
|
vehicle.Redirected = true;
|
||||||
|
GameFiber DirectTaskFiber = new GameFiber(() => TrafficPathing.DirectTask(vehicle, paths[directDriver.Index].Waypoint));
|
||||||
|
DirectTaskFiber.Start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TrafficPathing.collectedVehicles.Add(nearbyVehicle.LicensePlate, new ControlledVehicle(nearbyVehicle, nearbyVehicle.LicensePlate, paths[directDriver.Index].Waypoint[0].Path, paths[directDriver.Index].Waypoint.Count, 1, false, false, true));
|
||||||
|
Game.LogTrivial($"[Direct Driver] {nearbyVehicle.Model.Name} not in collection, adding to collection for path {paths[directDriver.Index].Waypoint[0].Path} with {paths[directDriver.Index].Waypoint.Count} waypoints");
|
||||||
|
|
||||||
|
GameFiber DirectTaskFiber = new GameFiber(() => TrafficPathing.DirectTask(TrafficPathing.collectedVehicles[nearbyVehicle.LicensePlate], paths[directDriver.Index].Waypoint));
|
||||||
|
DirectTaskFiber.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedItem == dismissDriver)
|
||||||
|
{
|
||||||
|
var nearbyVehicle = Game.LocalPlayer.Character.GetNearbyVehicles(1).Where(v => v.VehicleAndDriverValid()).SingleOrDefault();
|
||||||
|
if (nearbyVehicle)
|
||||||
|
{
|
||||||
|
switch (dismissDriver.Index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Game.LogTrivial($"Dismiss from path");
|
||||||
|
if (nearbyVehicle.IsInCollectedVehicles())
|
||||||
|
{
|
||||||
|
var controlledVehicle = TrafficPathing.collectedVehicles[nearbyVehicle.LicensePlate];
|
||||||
|
controlledVehicle.DismissNow = true;
|
||||||
|
controlledVehicle.Vehicle.Driver.Tasks.Clear();
|
||||||
|
controlledVehicle.Vehicle.Driver.Dismiss();
|
||||||
|
Game.LogTrivial($"Dismissed driver of {controlledVehicle.Vehicle.Model.Name} from path {controlledVehicle.Path}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto case 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
Game.LogTrivial($"Dismiss from waypoint");
|
||||||
|
if (nearbyVehicle.IsInCollectedVehicles())
|
||||||
|
{
|
||||||
|
var controlledVehicle = TrafficPathing.collectedVehicles[nearbyVehicle.LicensePlate];
|
||||||
|
controlledVehicle.StoppedAtWaypoint = false;
|
||||||
|
controlledVehicle.Vehicle.Driver.Tasks.Clear();
|
||||||
|
controlledVehicle.Vehicle.Driver.Dismiss();
|
||||||
|
|
||||||
|
if (controlledVehicle.CurrentWaypoint == controlledVehicle.TotalWaypoints && !controlledVehicle.StoppedAtWaypoint)
|
||||||
|
{
|
||||||
|
controlledVehicle.DismissNow = true;
|
||||||
|
Game.LogTrivial($"Dismissed driver of {controlledVehicle.Vehicle.Model.Name} from final waypoint and ultimately the path");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"Dismissed driver of {controlledVehicle.Vehicle.Model.Name} from waypoint {controlledVehicle.CurrentWaypoint}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto case 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
Game.LogTrivial($"Dismiss from position");
|
||||||
|
if (nearbyVehicle.IsInCollectedVehicles())
|
||||||
|
{
|
||||||
|
nearbyVehicle.Driver.Tasks.Clear();
|
||||||
|
nearbyVehicle.Driver.Dismiss();
|
||||||
|
Game.LogTrivial($"Dismissed driver of {nearbyVehicle.Model.Name} (in collection)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nearbyVehicle.Driver.Tasks.Clear();
|
||||||
|
nearbyVehicle.Driver.Dismiss();
|
||||||
|
Game.LogTrivial($"Dismissed driver of {nearbyVehicle.Model.Name} (was not in collection)");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Game.LogTrivial($"dismissDriver index was unexpected");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"There are no vehicles nearby matching the requirements.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PathMenu_OnCheckboxChange(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked)
|
||||||
|
{
|
||||||
|
if (checkboxItem == disableAllPaths)
|
||||||
|
{
|
||||||
|
if (disableAllPaths.Checked)
|
||||||
|
{
|
||||||
|
foreach (Path path in paths)
|
||||||
|
{
|
||||||
|
path.PathDisabled = true;
|
||||||
|
foreach (Waypoint waypoint in path.Waypoint)
|
||||||
|
{
|
||||||
|
waypoint.WaypointBlip.Alpha = 0.5f;
|
||||||
|
if (waypoint.CollectorRadiusBlip)
|
||||||
|
{
|
||||||
|
waypoint.CollectorRadiusBlip.Alpha = 0.25f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Game.LogTrivial($"All paths disabled.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (Path path in paths)
|
||||||
|
{
|
||||||
|
path.PathDisabled = false;
|
||||||
|
foreach (Waypoint waypoint in path.Waypoint)
|
||||||
|
{
|
||||||
|
waypoint.WaypointBlip.Alpha = 1f;
|
||||||
|
if (waypoint.CollectorRadiusBlip)
|
||||||
|
{
|
||||||
|
waypoint.CollectorRadiusBlip.Alpha = 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Game.LogTrivial($"All paths enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
SceneManager/Object Classes/Path.cs
Normal file
26
SceneManager/Object Classes/Path.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace SceneManager
|
||||||
|
{
|
||||||
|
public class Path
|
||||||
|
{
|
||||||
|
public int PathNum;
|
||||||
|
public bool PathFinished;
|
||||||
|
public bool PathDisabled;
|
||||||
|
public List<Waypoint> Waypoint = new List<Waypoint>() { };
|
||||||
|
|
||||||
|
public Path(int pathNum, bool pathFinished, bool pathDisabled, List<Waypoint> waypointData)
|
||||||
|
{
|
||||||
|
PathNum = pathNum;
|
||||||
|
PathFinished = pathFinished;
|
||||||
|
PathDisabled = pathDisabled;
|
||||||
|
Waypoint = waypointData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path(int pathNum, bool pathFinished)
|
||||||
|
{
|
||||||
|
PathNum = pathNum;
|
||||||
|
PathFinished = pathFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
SceneManager/Object Classes/Waypoint.cs
Normal file
52
SceneManager/Object Classes/Waypoint.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
using Rage;
|
||||||
|
|
||||||
|
namespace SceneManager
|
||||||
|
{
|
||||||
|
public class Waypoint
|
||||||
|
{
|
||||||
|
public int Path;
|
||||||
|
public int WaypointNum;
|
||||||
|
public Vector3 WaypointPos;
|
||||||
|
public float Speed;
|
||||||
|
public VehicleDrivingFlags DrivingFlag;
|
||||||
|
public Blip WaypointBlip;
|
||||||
|
public uint YieldZone;
|
||||||
|
public bool Collector;
|
||||||
|
public float CollectorRadius;
|
||||||
|
public Blip CollectorRadiusBlip;
|
||||||
|
|
||||||
|
// Can this constructor be deleted?
|
||||||
|
//public Waypoint(int path, Vector3 waypointPos, float speed, VehicleDrivingFlags drivingFlag, Blip waypointBlip, uint yieldZone)
|
||||||
|
//{
|
||||||
|
// Path = path;
|
||||||
|
// WaypointPos = waypointPos;
|
||||||
|
// Speed = speed;
|
||||||
|
// DrivingFlag = drivingFlag;
|
||||||
|
// WaypointBlip = waypointBlip;
|
||||||
|
// YieldZone = yieldZone;
|
||||||
|
//}
|
||||||
|
|
||||||
|
public Waypoint(int path, int waypointNum, Vector3 waypointPos, float speed, VehicleDrivingFlags drivingFlag, Blip waypointBlip, bool collector, float collectorRadius, uint yieldZone)
|
||||||
|
{
|
||||||
|
Path = path;
|
||||||
|
WaypointNum = waypointNum;
|
||||||
|
WaypointPos = waypointPos;
|
||||||
|
Speed = speed;
|
||||||
|
DrivingFlag = drivingFlag;
|
||||||
|
WaypointBlip = waypointBlip;
|
||||||
|
Collector = collector;
|
||||||
|
CollectorRadius = collectorRadius;
|
||||||
|
if (collector)
|
||||||
|
{
|
||||||
|
YieldZone = yieldZone;
|
||||||
|
CollectorRadiusBlip = new Blip(waypointBlip.Position, collectorRadius)
|
||||||
|
{
|
||||||
|
Color = waypointBlip.Color,
|
||||||
|
Alpha = 0.5f
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace SceneManager
|
|
||||||
{
|
|
||||||
public class PathData
|
|
||||||
{
|
|
||||||
public int PathNum;
|
|
||||||
public bool PathFinished;
|
|
||||||
public List<WaypointData> WaypointData = new List<WaypointData>() { };
|
|
||||||
|
|
||||||
public PathData(int pathNum, bool pathFinished, List<WaypointData> waypointData)
|
|
||||||
{
|
|
||||||
PathNum = pathNum;
|
|
||||||
PathFinished = pathFinished;
|
|
||||||
WaypointData = waypointData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PathData(int pathNum, bool pathFinished)
|
|
||||||
{
|
|
||||||
PathNum = pathNum;
|
|
||||||
PathFinished = pathFinished;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -51,14 +51,22 @@
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ControlledVehicle.cs" />
|
<Compile Include="Menus\BarrierMenu.cs" />
|
||||||
|
<Compile Include="Object Classes\ControlledVehicle.cs" />
|
||||||
|
<Compile Include="Menus\EditPathMenu.cs" />
|
||||||
|
<Compile Include="Menus\EditWaypointMenu.cs" />
|
||||||
<Compile Include="EntryPoint.cs" />
|
<Compile Include="EntryPoint.cs" />
|
||||||
<Compile Include="PathData.cs" />
|
<Compile Include="GetUserInput.cs" />
|
||||||
|
<Compile Include="Menus\MainMenu.cs" />
|
||||||
|
<Compile Include="MenuManager.cs" />
|
||||||
|
<Compile Include="Object Classes\Path.cs" />
|
||||||
|
<Compile Include="Menus\PathCreationMenu.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="TrafficMenu.cs" />
|
<Compile Include="Menus\TrafficMenu.cs" />
|
||||||
|
<Compile Include="SettingsMenu.cs" />
|
||||||
<Compile Include="TrafficPathing.cs" />
|
<Compile Include="TrafficPathing.cs" />
|
||||||
<Compile Include="Verification.cs" />
|
<Compile Include="Verification.cs" />
|
||||||
<Compile Include="WaypointData.cs" />
|
<Compile Include="Object Classes\Waypoint.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
79
SceneManager/SettingsMenu.cs
Normal file
79
SceneManager/SettingsMenu.cs
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
using Rage;
|
||||||
|
using RAGENativeUI;
|
||||||
|
using RAGENativeUI.Elements;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace SceneManager
|
||||||
|
{
|
||||||
|
class SettingsMenu
|
||||||
|
{
|
||||||
|
public static UIMenuCheckboxItem debugGraphics;
|
||||||
|
public static UIMenuListScrollerItem<SpeedUnitsOfMeasure> speedUnits;
|
||||||
|
public enum SpeedUnitsOfMeasure
|
||||||
|
{
|
||||||
|
MPH,
|
||||||
|
KPH
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BuildSettingsMenu()
|
||||||
|
{
|
||||||
|
MenuManager.settingsMenu.AddItem(debugGraphics = new UIMenuCheckboxItem("Enable Debug Graphics", false));
|
||||||
|
MenuManager.settingsMenu.AddItem(speedUnits = new UIMenuListScrollerItem<SpeedUnitsOfMeasure>("Speed Unit of Measure", "", new[] { SpeedUnitsOfMeasure.MPH, SpeedUnitsOfMeasure.KPH }));
|
||||||
|
|
||||||
|
MenuManager.settingsMenu.OnCheckboxChange += SettingsMenu_OnCheckboxChange;
|
||||||
|
MenuManager.settingsMenu.OnScrollerChange += SettingsMenu_OnScrollerChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SettingsMenu_OnCheckboxChange(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked)
|
||||||
|
{
|
||||||
|
if (checkboxItem == debugGraphics)
|
||||||
|
{
|
||||||
|
// TODO: Fix graphics don't display when new path is created, have to uncheck and re-check the option
|
||||||
|
// TODO: Add branch for this during path creation ... create temp Waypoint list during path creation, then assign to path[i] after creation?
|
||||||
|
if (debugGraphics.Checked)
|
||||||
|
{
|
||||||
|
foreach (Path path in TrafficMenu.paths)
|
||||||
|
{
|
||||||
|
GameFiber.StartNew(() =>
|
||||||
|
{
|
||||||
|
while (debugGraphics.Checked && path != null && path.Waypoint.Count > 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < path.Waypoint.Count; i++)
|
||||||
|
{
|
||||||
|
if (path.Waypoint[i].Collector)
|
||||||
|
{
|
||||||
|
Debug.DrawSphere(path.Waypoint[i].WaypointPos, path.Waypoint[i].CollectorRadius, Color.FromArgb(80, Color.Blue));
|
||||||
|
}
|
||||||
|
else if (path.Waypoint[i].DrivingFlag == VehicleDrivingFlags.StopAtDestination)
|
||||||
|
{
|
||||||
|
Debug.DrawSphere(path.Waypoint[i].WaypointPos, 1f, Color.FromArgb(80, Color.Red));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.DrawSphere(path.Waypoint[i].WaypointPos, 1f, Color.FromArgb(80, Color.Green));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i != path.Waypoint.Count - 1)
|
||||||
|
{
|
||||||
|
Debug.DrawLine(path.Waypoint[i].WaypointPos, path.Waypoint[i + 1].WaypointPos, Color.White);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GameFiber.Yield();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SettingsMenu_OnScrollerChange(UIMenu sender, UIMenuScrollerItem scrollerItem, int oldIndex, int newIndex)
|
||||||
|
{
|
||||||
|
if (scrollerItem == speedUnits)
|
||||||
|
{
|
||||||
|
MenuManager.pathCreationMenu.Clear();
|
||||||
|
PathCreationMenu.BuildPathCreationMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,646 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Drawing;
|
|
||||||
using Rage;
|
|
||||||
using RAGENativeUI;
|
|
||||||
using RAGENativeUI.Elements;
|
|
||||||
|
|
||||||
namespace SceneManager
|
|
||||||
{
|
|
||||||
public static class TrafficMenu
|
|
||||||
{
|
|
||||||
private static MenuPool _menuPool;
|
|
||||||
private static UIMenu mainMenu, trafficMenu, coneMenu, pathCreationMenu;
|
|
||||||
private static UIMenuItem navigateToTrafficMenu, navigateToConeMenu, createNewPath, trafficAddWaypoint, trafficRemoveWaypoint, trafficEndPath, deleteAllPaths, addCone, removeLastCone, removeNearestCone, removeAllCones, dismissDriver;
|
|
||||||
private static UIMenuListItem deleteSinglePath, selectCone, waypointType, waypointSpeed, directDriver;
|
|
||||||
|
|
||||||
private static List<dynamic> pathsNum = new List<dynamic>() { };
|
|
||||||
private static List<PathData> paths = new List<PathData>() { };
|
|
||||||
private static List<Rage.Object> cones = new List<Rage.Object>() { };
|
|
||||||
|
|
||||||
private static List<dynamic> waypointSpeeds = new List<dynamic>() { 5, 10, 15, 20, 30, 40, 50, 60, 70 };
|
|
||||||
private static List<dynamic> waypointTypes = new List<dynamic>() { "Drive To", "Stop" };
|
|
||||||
private static VehicleDrivingFlags[] drivingFlags = new VehicleDrivingFlags[] { VehicleDrivingFlags.Normal, VehicleDrivingFlags.StopAtDestination };
|
|
||||||
private static List<dynamic> coneList = new List<dynamic>() { "Large Striped Cone", "Large Cone", "Medium Striped Cone", "Medium Cone", "Roadpole A", "Roadpole B" };
|
|
||||||
private static string[] coneObjectNames = new string[] { "prop_mp_cone_01", "prop_roadcone01c", "prop_mp_cone_02", "prop_mp_cone_03", "prop_roadpole_01a", "prop_roadpole_01b" };
|
|
||||||
|
|
||||||
private static Rage.Object shadowCone;
|
|
||||||
|
|
||||||
public static void CheckUserInput()
|
|
||||||
{
|
|
||||||
#pragma warning disable CS0618 // Type or member is obsolete, clear NUI squiggles in BuildMenu
|
|
||||||
AppDomain.CurrentDomain.DomainUnload += MyTerminationHandler;
|
|
||||||
|
|
||||||
BuildMenu();
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
// Keyboard
|
|
||||||
if (EntryPoint.Settings.ModifierKey == System.Windows.Forms.Keys.None)
|
|
||||||
{
|
|
||||||
if (Game.LocalPlayer.Character.IsOnFoot && Game.IsKeyDown(EntryPoint.Settings.ToggleKey) && !trafficMenu.Visible && !pathCreationMenu.Visible)
|
|
||||||
{
|
|
||||||
mainMenu.Visible = !mainMenu.Visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Game.LocalPlayer.Character.IsOnFoot && Game.IsKeyDownRightNow(EntryPoint.Settings.ModifierKey) && Game.IsKeyDown(EntryPoint.Settings.ToggleKey) && !trafficMenu.Visible && !pathCreationMenu.Visible)
|
|
||||||
{
|
|
||||||
mainMenu.Visible = !mainMenu.Visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Controller
|
|
||||||
if (EntryPoint.Settings.ModifierButton == ControllerButtons.None)
|
|
||||||
{
|
|
||||||
if (Game.LocalPlayer.Character.IsOnFoot && Game.IsControllerButtonDown(EntryPoint.Settings.ToggleButton) && !trafficMenu.Visible && !pathCreationMenu.Visible)
|
|
||||||
{
|
|
||||||
mainMenu.Visible = !mainMenu.Visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Game.LocalPlayer.Character.IsOnFoot && Game.IsControllerButtonDownRightNow(EntryPoint.Settings.ModifierButton) && Game.IsControllerButtonDown(EntryPoint.Settings.ToggleButton) && !trafficMenu.Visible && !pathCreationMenu.Visible)
|
|
||||||
{
|
|
||||||
mainMenu.Visible = !mainMenu.Visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
_menuPool.ProcessMenus();
|
|
||||||
GameFiber.Yield();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void BuildMenu()
|
|
||||||
{
|
|
||||||
_menuPool = new MenuPool();
|
|
||||||
|
|
||||||
// Instantiate menus
|
|
||||||
mainMenu = new UIMenu("Scene Manager", "");
|
|
||||||
trafficMenu = new UIMenu("Scene Manager", "~o~Traffic Menu");
|
|
||||||
trafficMenu.ParentMenu = mainMenu;
|
|
||||||
pathCreationMenu = new UIMenu("Scene Manager", "~o~Path Creation");
|
|
||||||
pathCreationMenu.ParentMenu = trafficMenu;
|
|
||||||
coneMenu = new UIMenu("Scene Manager", "~o~Cone Menu");
|
|
||||||
coneMenu.ParentMenu = mainMenu;
|
|
||||||
|
|
||||||
// Add menus to the pool
|
|
||||||
_menuPool.Add(mainMenu);
|
|
||||||
_menuPool.Add(trafficMenu);
|
|
||||||
_menuPool.Add(coneMenu);
|
|
||||||
_menuPool.Add(pathCreationMenu);
|
|
||||||
|
|
||||||
// Add menu items to main menu and navigate each item to a submenu
|
|
||||||
mainMenu.AddItem(navigateToTrafficMenu = new UIMenuItem("~o~Traffic Menu"));
|
|
||||||
mainMenu.BindMenuToItem(trafficMenu, navigateToTrafficMenu);
|
|
||||||
mainMenu.AddItem(navigateToConeMenu = new UIMenuItem("~o~Cone Menu"));
|
|
||||||
mainMenu.BindMenuToItem(coneMenu, navigateToConeMenu);
|
|
||||||
|
|
||||||
// Add menu items to trafficMenu
|
|
||||||
trafficMenu.AddItem(createNewPath = new UIMenuItem("Create New Path"));
|
|
||||||
trafficMenu.AddItem(deleteSinglePath = new UIMenuListItem("Delete Path", pathsNum, 0));
|
|
||||||
deleteSinglePath.Enabled = false;
|
|
||||||
trafficMenu.AddItem(deleteAllPaths = new UIMenuItem("Delete All Paths"));
|
|
||||||
deleteAllPaths.Enabled = false;
|
|
||||||
trafficMenu.AddItem(directDriver = new UIMenuListItem("Direct nearest driver to path", pathsNum, 0));
|
|
||||||
directDriver.Enabled = false;
|
|
||||||
trafficMenu.AddItem(dismissDriver = new UIMenuItem("Dismiss nearest driver"));
|
|
||||||
|
|
||||||
// Add menu items to pathCreationMenu
|
|
||||||
pathCreationMenu.AddItem(waypointType = new UIMenuListItem("Waypoint Type", waypointTypes, 0));
|
|
||||||
pathCreationMenu.AddItem(waypointSpeed = new UIMenuListItem("Waypoint Speed", waypointSpeeds, 0));
|
|
||||||
pathCreationMenu.AddItem(trafficAddWaypoint = new UIMenuItem("Add waypoint"));
|
|
||||||
pathCreationMenu.AddItem(trafficRemoveWaypoint = new UIMenuItem("Remove last waypoint"));
|
|
||||||
trafficRemoveWaypoint.Enabled = false;
|
|
||||||
pathCreationMenu.AddItem(trafficEndPath = new UIMenuItem("End path creation"));
|
|
||||||
|
|
||||||
// Add menu items to coneMenu
|
|
||||||
coneMenu.AddItem(selectCone = new UIMenuListItem("Select Cone", coneList, 0));
|
|
||||||
coneMenu.AddItem(addCone = new UIMenuItem("Add Cone"));
|
|
||||||
coneMenu.AddItem(removeLastCone = new UIMenuItem("Remove Last Cone"));
|
|
||||||
removeLastCone.Enabled = false;
|
|
||||||
coneMenu.AddItem(removeNearestCone = new UIMenuItem("Remove Nearest Cone"));
|
|
||||||
removeNearestCone.Enabled = false;
|
|
||||||
coneMenu.AddItem(removeAllCones = new UIMenuItem("Remove All Cones"));
|
|
||||||
removeAllCones.Enabled = false;
|
|
||||||
|
|
||||||
mainMenu.RefreshIndex();
|
|
||||||
trafficMenu.RefreshIndex();
|
|
||||||
pathCreationMenu.RefreshIndex();
|
|
||||||
coneMenu.RefreshIndex();
|
|
||||||
|
|
||||||
// Event handlers for when a menu item is selected
|
|
||||||
mainMenu.OnItemSelect += MainMenu_OnItemSelected;
|
|
||||||
trafficMenu.OnItemSelect += TrafficMenu_OnItemSelected;
|
|
||||||
pathCreationMenu.OnItemSelect += PathCreation_OnItemSelected;
|
|
||||||
coneMenu.OnListChange += ConeMenu_OnListChange;
|
|
||||||
coneMenu.OnItemSelect += ConeMenu_OnItemSelected;
|
|
||||||
|
|
||||||
// Disable mouse control for the menus
|
|
||||||
mainMenu.MouseControlsEnabled = false;
|
|
||||||
mainMenu.AllowCameraMovement = true;
|
|
||||||
trafficMenu.MouseControlsEnabled = false;
|
|
||||||
trafficMenu.AllowCameraMovement = true;
|
|
||||||
pathCreationMenu.MouseControlsEnabled = false;
|
|
||||||
pathCreationMenu.AllowCameraMovement = true;
|
|
||||||
coneMenu.MouseControlsEnabled = false;
|
|
||||||
coneMenu.AllowCameraMovement = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RebuildTrafficMenu()
|
|
||||||
{
|
|
||||||
// The traffic menu has to be "refreshed" in some instances to show changes, so we do that here
|
|
||||||
_menuPool.CloseAllMenus();
|
|
||||||
trafficMenu.Clear();
|
|
||||||
trafficMenu.AddItem(createNewPath = new UIMenuItem("Create New Path"));
|
|
||||||
trafficMenu.AddItem(deleteSinglePath = new UIMenuListItem("Delete Path", pathsNum, 0));
|
|
||||||
trafficMenu.AddItem(deleteAllPaths = new UIMenuItem("Delete All Paths"));
|
|
||||||
trafficMenu.AddItem(directDriver = new UIMenuListItem("Direct nearest driver to path", pathsNum, 0));
|
|
||||||
trafficMenu.AddItem(dismissDriver = new UIMenuItem("Dismiss nearest driver"));
|
|
||||||
|
|
||||||
if (paths.Count == 8)
|
|
||||||
{
|
|
||||||
createNewPath.Enabled = false;
|
|
||||||
}
|
|
||||||
if (paths.Count == 0)
|
|
||||||
{
|
|
||||||
deleteSinglePath.Enabled = false;
|
|
||||||
deleteAllPaths.Enabled = false;
|
|
||||||
directDriver.Enabled = false;
|
|
||||||
}
|
|
||||||
_menuPool.RefreshIndex();
|
|
||||||
trafficMenu.Visible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DeletePath(PathData path, int index, UIMenuItem selectedItem)
|
|
||||||
{
|
|
||||||
// Before deleting a path, we need to dismiss any vehicles controlled by that path and remove the vehicles from ControlledVehicles
|
|
||||||
//Game.LogTrivial($"Deleting path {index+1}");
|
|
||||||
Game.LogTrivial($"Deleting path {path.WaypointData[0].Path}");
|
|
||||||
var matchingVehicle = TrafficPathing.ControlledVehicles.Where(cv => cv.Value.Path == path.WaypointData[0].Path).ToList();
|
|
||||||
Game.LogTrivial($"Running foreach loop");
|
|
||||||
foreach (KeyValuePair<string, ControlledVehicle> cv in matchingVehicle)
|
|
||||||
{
|
|
||||||
if (cv.Value.Vehicle.Exists() && cv.Value.Vehicle.IsValid() && cv.Value.Vehicle.Driver.Exists() && cv.Value.Vehicle.Driver.IsValid())
|
|
||||||
{
|
|
||||||
cv.Value.DismissNow = true;
|
|
||||||
cv.Value.Vehicle.Driver.Tasks.Clear();
|
|
||||||
cv.Value.Vehicle.Driver.Dismiss();
|
|
||||||
TrafficPathing.ControlledVehicles.Remove(cv.Value.LicensePlate);
|
|
||||||
//Game.LogTrivial($"{cv.vehicle.Model.Name} cleared from path {cv.path}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Game.LogTrivial($"Remove all vehicles in the path");
|
|
||||||
//TrafficPathing.ControlledVehicles.RemoveAll(cv => cv.Path == path.WaypointData[0].Path);
|
|
||||||
|
|
||||||
// Remove the speed zone so cars don't continue to be affected after the path is deleted
|
|
||||||
foreach (WaypointData wd in path.WaypointData)
|
|
||||||
{
|
|
||||||
if (wd == path.WaypointData[0])
|
|
||||||
{
|
|
||||||
World.RemoveSpeedZone(wd.YieldZone);
|
|
||||||
}
|
|
||||||
wd.WaypointBlip.Delete();
|
|
||||||
}
|
|
||||||
path.WaypointData.Clear();
|
|
||||||
|
|
||||||
// Manipulating the menu to reflect specific paths being deleted
|
|
||||||
if (selectedItem == deleteSinglePath)
|
|
||||||
{
|
|
||||||
Game.LogTrivial($"Path {path.PathNum} deleted.");
|
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~w~Path {path.PathNum} deleted.");
|
|
||||||
paths.RemoveAt(index);
|
|
||||||
//Game.LogTrivial("pathsNum count: " + pathsNum.Count);
|
|
||||||
//Game.LogTrivial("index: " + index);
|
|
||||||
pathsNum.RemoveAt(index);
|
|
||||||
RebuildTrafficMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void TrafficMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
|
||||||
{
|
|
||||||
if (selectedItem == createNewPath)
|
|
||||||
{
|
|
||||||
trafficMenu.Visible = false;
|
|
||||||
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].PathFinished == false)
|
|
||||||
{
|
|
||||||
//Game.LogTrivial($"pathFinished: {paths[i].PathFinished}");
|
|
||||||
Game.LogTrivial($"Resuming path {i+1}");
|
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~y~[Creating]~w~ Resuming path {i+1}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (paths.ElementAtOrDefault(i) == null)
|
|
||||||
{
|
|
||||||
Game.LogTrivial($"Creating path {i+1}");
|
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~y~[Creating]~w~ Path {i+1} started.");
|
|
||||||
paths.Insert(i, new PathData(i+1,false));// { pathNum = i+1, pathFinished = false });
|
|
||||||
trafficRemoveWaypoint.Enabled = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedItem == deleteSinglePath)
|
|
||||||
{
|
|
||||||
//Game.LogTrivial("pathsNum has " + pathsNum.Count + " items before deleting a path.");
|
|
||||||
//Game.LogTrivial("deletePath index is " + deletePath.Index);
|
|
||||||
//Game.LogTrivial("deletePath selectedPath is " + deletePath.IndexToItem(deletePath.Index));
|
|
||||||
DeletePath(paths[deleteSinglePath.Index], deleteSinglePath.Index, deleteSinglePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedItem == deleteAllPaths)
|
|
||||||
{
|
|
||||||
// Iterate through each item in paths and delete it
|
|
||||||
for(int i = 0; i < paths.Count; i++)
|
|
||||||
{
|
|
||||||
DeletePath(paths[i], i, deleteAllPaths);
|
|
||||||
}
|
|
||||||
pathsNum.Clear();
|
|
||||||
paths.Clear();
|
|
||||||
RebuildTrafficMenu();
|
|
||||||
Game.LogTrivial($"All paths deleted");
|
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~w~All paths deleted.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedItem == directDriver)
|
|
||||||
{
|
|
||||||
// Sometimes GetNearbyVehicles will cause a crash for some reason, so keeping it in a try/catch will prevent that.
|
|
||||||
try
|
|
||||||
{
|
|
||||||
foreach (Vehicle v in Game.LocalPlayer.Character.GetNearbyVehicles(5))
|
|
||||||
{
|
|
||||||
if (v.Exists() && v.IsValid() && v.HasDriver && v.Driver.IsAlive)
|
|
||||||
{
|
|
||||||
// Check if there's a matching vehicle in ControlledVehicles. If so, check if it has tasks and proceed, else add it to the collection and assign tasks
|
|
||||||
var matchingVehicle = TrafficPathing.ControlledVehicles.Where(cv => cv.Value.Vehicle == v).ToList();
|
|
||||||
if (matchingVehicle.ElementAtOrDefault(0).Value != null && matchingVehicle[0].Value.TasksAssigned)
|
|
||||||
{
|
|
||||||
Game.LogTrivial($"[Direct Driver] {v.Model.Name} already in collection with tasks. Clearing tasks.");
|
|
||||||
v.Driver.Tasks.Clear();
|
|
||||||
matchingVehicle[0].Value.Path = paths[directDriver.Index].WaypointData[0].Path;
|
|
||||||
matchingVehicle[0].Value.TotalWaypoints = paths[directDriver.Index].WaypointData.Count;
|
|
||||||
matchingVehicle[0].Value.CurrentWaypoint = 1;
|
|
||||||
matchingVehicle[0].Value.DismissNow = true;
|
|
||||||
matchingVehicle[0].Value.StoppedAtWaypoint = false;
|
|
||||||
matchingVehicle[0].Value.Redirected = true;
|
|
||||||
GameFiber DirectTaskFiber = new GameFiber(() => TrafficPathing.DirectTask(matchingVehicle[0].Value, paths[directDriver.Index].WaypointData));
|
|
||||||
DirectTaskFiber.Start();
|
|
||||||
}
|
|
||||||
else if(matchingVehicle.ElementAtOrDefault(0).Value != null && !matchingVehicle[0].Value.TasksAssigned)
|
|
||||||
{
|
|
||||||
Game.LogTrivial($"[Direct Driver] {v.Model.Name} already in collection, but with no tasks.");
|
|
||||||
v.Driver.Tasks.Clear();
|
|
||||||
matchingVehicle[0].Value.Path = paths[directDriver.Index].WaypointData[0].Path;
|
|
||||||
matchingVehicle[0].Value.TotalWaypoints = paths[directDriver.Index].WaypointData.Count;
|
|
||||||
matchingVehicle[0].Value.CurrentWaypoint = 1;
|
|
||||||
matchingVehicle[0].Value.DismissNow = true;
|
|
||||||
matchingVehicle[0].Value.StoppedAtWaypoint = false;
|
|
||||||
matchingVehicle[0].Value.Redirected = true;
|
|
||||||
GameFiber DirectTaskFiber = new GameFiber(() => TrafficPathing.DirectTask(matchingVehicle[0].Value, paths[directDriver.Index].WaypointData));
|
|
||||||
DirectTaskFiber.Start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TrafficPathing.ControlledVehicles.Add(v.LicensePlate, new ControlledVehicle(v, v.LicensePlate, paths[directDriver.Index].WaypointData[0].Path, paths[directDriver.Index].WaypointData.Count, 1, false, false, true));
|
|
||||||
Game.LogTrivial($"[Direct Driver] {v.Model.Name} not in collection, adding to collection for path {paths[directDriver.Index].WaypointData[0].Path} with {paths[directDriver.Index].WaypointData.Count} waypoints");
|
|
||||||
|
|
||||||
GameFiber DirectTaskFiber = new GameFiber(() => TrafficPathing.DirectTask(TrafficPathing.ControlledVehicles[v.LicensePlate], paths[directDriver.Index].WaypointData));
|
|
||||||
DirectTaskFiber.Start();
|
|
||||||
}
|
|
||||||
Game.LogTrivial($"Directed driver of {v.Model.Name} to path {paths[directDriver.Index].WaypointData[0].Path}.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Game.LogTrivial($"No vehicles nearby");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedItem == dismissDriver)
|
|
||||||
{
|
|
||||||
// Check for nearby vehicles, and if the vehicle is being controlled, release it
|
|
||||||
GameFiber.StartNew(delegate {
|
|
||||||
foreach (Vehicle v in Game.LocalPlayer.Character.GetNearbyVehicles(5))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (v.Exists() && v.IsValid() && v.HasDriver && v.Driver.IsAlive)
|
|
||||||
{
|
|
||||||
var matchingVehicle = TrafficPathing.ControlledVehicles.Where(cv => cv.Value.Vehicle == v).ToList();
|
|
||||||
if (matchingVehicle.ElementAtOrDefault(0).Value != null && matchingVehicle[0].Value.CurrentWaypoint < matchingVehicle[0].Value.TotalWaypoints && !matchingVehicle[0].Value.StoppedAtWaypoint)
|
|
||||||
{
|
|
||||||
matchingVehicle[0].Value.DismissNow = true;
|
|
||||||
v.Driver.Tasks.Clear();
|
|
||||||
v.Driver.Dismiss();
|
|
||||||
Game.LogTrivial($"Dismissed driver of {v.Model.Name} from the path");
|
|
||||||
}
|
|
||||||
else if (matchingVehicle.ElementAtOrDefault(0).Value != null && matchingVehicle[0].Value.CurrentWaypoint < matchingVehicle[0].Value.TotalWaypoints)
|
|
||||||
{
|
|
||||||
matchingVehicle[0].Value.StoppedAtWaypoint = false;
|
|
||||||
Game.LogTrivial($"Dismissed driver of {v.Model.Name} from waypoint {matchingVehicle[0].Value.CurrentWaypoint}");
|
|
||||||
}
|
|
||||||
else if (matchingVehicle.ElementAtOrDefault(0).Value != null && matchingVehicle[0].Value.CurrentWaypoint == matchingVehicle[0].Value.TotalWaypoints)
|
|
||||||
{
|
|
||||||
matchingVehicle[0].Value.StoppedAtWaypoint = false;
|
|
||||||
matchingVehicle[0].Value.DismissNow = true;
|
|
||||||
v.Driver.Tasks.Clear();
|
|
||||||
v.Driver.Dismiss();
|
|
||||||
Game.LogTrivial($"Dismissed driver of {v.Model.Name} from final waypoint and ultimately the path");
|
|
||||||
}
|
|
||||||
else if (matchingVehicle.ElementAtOrDefault(0).Value != null)
|
|
||||||
{
|
|
||||||
matchingVehicle[0].Value.DismissNow = true;
|
|
||||||
v.Driver.Tasks.Clear();
|
|
||||||
v.Driver.Dismiss();
|
|
||||||
Game.LogTrivial($"Dismissed driver of {v.Model.Name} from path {matchingVehicle[0].Value.Path}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
v.Driver.Tasks.Clear();
|
|
||||||
v.Driver.Dismiss();
|
|
||||||
Game.LogTrivial($"Dismissed driver of {v.Model.Name} (was not in collection)");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Game.LogTrivial($"Something went wrong getting nearby vehicles to dismiss");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void PathCreation_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
|
||||||
{
|
|
||||||
if (selectedItem == trafficAddWaypoint)
|
|
||||||
{
|
|
||||||
// Loop through each path and find the first one which isn't finished
|
|
||||||
for (int i = 0; i < paths.Count; i++)
|
|
||||||
{
|
|
||||||
if (paths.ElementAtOrDefault(i) != null && !paths.ElementAtOrDefault(i).PathFinished)
|
|
||||||
{
|
|
||||||
// Create a waypoint blip and set the sprite based on the current path number
|
|
||||||
Blip blip = new Blip(Game.LocalPlayer.Character.Position);
|
|
||||||
blip.Scale = 0.5f;
|
|
||||||
switch (i)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
blip.Sprite = BlipSprite.Numbered1;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
blip.Sprite = BlipSprite.Numbered2;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
blip.Sprite = BlipSprite.Numbered3;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
blip.Sprite = BlipSprite.Numbered4;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
blip.Sprite = BlipSprite.Numbered5;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
blip.Sprite = BlipSprite.Numbered6;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
blip.Sprite = BlipSprite.Numbered7;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
blip.Sprite = BlipSprite.Numbered8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it's the first waypoint, make the blip orange, else make it yellow
|
|
||||||
if (paths[i].WaypointData.Count == 0)
|
|
||||||
{
|
|
||||||
blip.Color = Color.Orange;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
blip.Color = Color.Yellow;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the waypoint data to the path
|
|
||||||
paths[i].WaypointData.Add(new WaypointData(i+1, Game.LocalPlayer.Character.Position, waypointSpeeds[waypointSpeed.Index], drivingFlags[waypointType.Index], blip));
|
|
||||||
Game.LogTrivial($"[Path {i+1}] {drivingFlags[waypointType.Index].ToString()} waypoint added");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh the trafficMenu after a waypoint is added in order to show Continue Creating Current Path instead of Create New Path
|
|
||||||
trafficRemoveWaypoint.Enabled = true;
|
|
||||||
trafficMenu.Clear();
|
|
||||||
trafficMenu.AddItem(createNewPath = new UIMenuItem("Continue Creating Current Path"));
|
|
||||||
trafficMenu.AddItem(deleteSinglePath = new UIMenuListItem("Delete Path", pathsNum, 0));
|
|
||||||
trafficMenu.AddItem(deleteAllPaths = new UIMenuItem("Delete All Paths"));
|
|
||||||
trafficMenu.AddItem(directDriver = new UIMenuListItem("Direct nearest driver to path", pathsNum, 0));
|
|
||||||
trafficMenu.AddItem(dismissDriver = new UIMenuItem("Dismiss nearest driver"));
|
|
||||||
if (pathsNum.Count == 8)
|
|
||||||
{
|
|
||||||
createNewPath.Enabled = false;
|
|
||||||
}
|
|
||||||
if (pathsNum.Count == 0)
|
|
||||||
{
|
|
||||||
deleteSinglePath.Enabled = false;
|
|
||||||
deleteAllPaths.Enabled = false;
|
|
||||||
directDriver.Enabled = false;
|
|
||||||
}
|
|
||||||
//_menuPool.RefreshIndex(); // Disabling this to stop resetting waypoint menu after waypoint is added
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedItem == trafficRemoveWaypoint)
|
|
||||||
{
|
|
||||||
// Loop through each path and find the first one which isn't finished, then delete the path's last waypoint and corresponding blip
|
|
||||||
for (int i = 0; i < paths.Count; i++)
|
|
||||||
{
|
|
||||||
if (paths.ElementAtOrDefault(i) != null && !paths[i].PathFinished)
|
|
||||||
{
|
|
||||||
Game.LogTrivial($"[Path {i+1}] {paths[i].WaypointData.Last().DrivingFlag.ToString()} waypoint removed");
|
|
||||||
paths[i].WaypointData.Last().WaypointBlip.Delete();
|
|
||||||
paths[i].WaypointData.RemoveAt(paths[i].WaypointData.IndexOf(paths[i].WaypointData.Last()));
|
|
||||||
|
|
||||||
// If the path has no waypoints, disable the menu option to remove a waypoint
|
|
||||||
if (paths[i].WaypointData.Count == 0)
|
|
||||||
{
|
|
||||||
trafficRemoveWaypoint.Enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedItem == trafficEndPath)
|
|
||||||
{
|
|
||||||
// Loop through each path and find the first one which isn't finished
|
|
||||||
for (int i = 0; i < paths.Count; i++)
|
|
||||||
{
|
|
||||||
if (paths.ElementAtOrDefault(i) != null && !paths[i].PathFinished)
|
|
||||||
{
|
|
||||||
// If the path has one stop waypoint or at least two waypoints, finish the path and start the vehicle collector loop, else show user the error and delete any waypoints they made and clear the invalid path
|
|
||||||
if (paths[i].WaypointData.Count >= 2 || (paths[i].WaypointData.Count == 1 && paths[i].WaypointData[0].DrivingFlag == VehicleDrivingFlags.StopAtDestination))
|
|
||||||
{
|
|
||||||
Game.LogTrivial($"[Path Creation] Path {i+1} finished with {paths[i].WaypointData.Count} waypoints.");
|
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~g~[Success]~w~ Path {i+1} complete.");
|
|
||||||
paths[i].WaypointData.Last().WaypointBlip.Color = Color.OrangeRed;
|
|
||||||
paths[i].PathFinished = true;
|
|
||||||
paths[i].PathNum = i + 1;
|
|
||||||
pathsNum.Insert(i, paths[i].PathNum);
|
|
||||||
|
|
||||||
GameFiber InitialWaypointVehicleCollectorFiber = new GameFiber(() => TrafficPathing.InitialWaypointVehicleCollector(paths[i].WaypointData));
|
|
||||||
InitialWaypointVehicleCollectorFiber.Start();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Game.LogTrivial($"[Path Error] A minimum of 2 waypoints is required.");
|
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~r~[Error]~w~ A minimum of 2 waypoints or one stop waypoint is required to create a path.");
|
|
||||||
foreach (WaypointData wd in paths[i].WaypointData)
|
|
||||||
{
|
|
||||||
wd.WaypointBlip.Delete();
|
|
||||||
}
|
|
||||||
paths[i].WaypointData.Clear();
|
|
||||||
paths.RemoveAt(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// "Refresh" the menu to reflect the new path
|
|
||||||
RebuildTrafficMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ConeMenu_OnListChange(UIMenu sender, UIMenuListItem listItem, int index)
|
|
||||||
{
|
|
||||||
if (shadowCone.Exists())
|
|
||||||
{
|
|
||||||
shadowCone.IsVisible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
shadowCone = new Rage.Object(coneObjectNames[selectCone.Index], Game.LocalPlayer.Character.GetOffsetPosition(new Vector3(0f, 3f, -1f)));
|
|
||||||
shadowCone.Opacity = 70f;
|
|
||||||
shadowCone.IsCollisionEnabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void MainMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
|
||||||
{
|
|
||||||
if (selectedItem == navigateToConeMenu)
|
|
||||||
{
|
|
||||||
if (EntryPoint.Settings.EnableHints)
|
|
||||||
{
|
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~y~[Hint]~y~ ~w~It's easier to place cones in first-person view.");
|
|
||||||
}
|
|
||||||
|
|
||||||
shadowCone = new Rage.Object(coneObjectNames[selectCone.Index], Game.LocalPlayer.Character.GetOffsetPosition(new Vector3(0f, 3f, -1f)));
|
|
||||||
shadowCone.IsCollisionEnabled = false;
|
|
||||||
shadowCone.Opacity = 70f;
|
|
||||||
|
|
||||||
GameFiber ConeHoverFiber = new GameFiber(() => ConeHover(sender, selectedItem, index));
|
|
||||||
ConeHoverFiber.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ConeHover(UIMenu sender, UIMenuItem selectedItem, int index)
|
|
||||||
{
|
|
||||||
// Run a loop to show currently selected cone hovering in front of player
|
|
||||||
//Game.LogTrivial("Creating shadow cone");
|
|
||||||
|
|
||||||
while (coneMenu.Visible)
|
|
||||||
{
|
|
||||||
shadowCone.Position = Game.LocalPlayer.Character.GetOffsetPosition(new Vector3(0f, 3f, -1f));
|
|
||||||
GameFiber.Yield();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ConeMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
|
|
||||||
{
|
|
||||||
Rage.Object cone;
|
|
||||||
if (selectedItem == addCone)
|
|
||||||
{
|
|
||||||
// Attach some invisible object to the cone which the AI try to drive around
|
|
||||||
// Barrier, new rotate option in menu, barrier rotates with cone and becomes invisible similar to ASC when created
|
|
||||||
cone = new Rage.Object(shadowCone.Model, shadowCone.Position);
|
|
||||||
cones.Add(cone);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedItem == removeLastCone)
|
|
||||||
{
|
|
||||||
//Game.LogTrivial($"cones count before deletion: {cones.Count}");
|
|
||||||
cones[cones.Count - 1].Delete();
|
|
||||||
cones.RemoveAt(cones.Count - 1);
|
|
||||||
//Game.LogTrivial($"cones count after deletion: {cones.Count}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedItem == removeNearestCone)
|
|
||||||
{
|
|
||||||
cones = cones.OrderBy(o => o.DistanceTo(Game.LocalPlayer.Character)).ToList();
|
|
||||||
cones[0].Delete();
|
|
||||||
cones.RemoveAt(0);
|
|
||||||
//Game.LogTrivial($"cones count: {cones.Count}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedItem == removeAllCones)
|
|
||||||
{
|
|
||||||
foreach (Rage.Object c in cones)
|
|
||||||
{
|
|
||||||
c.Delete();
|
|
||||||
}
|
|
||||||
if (cones.Count > 0)
|
|
||||||
{
|
|
||||||
cones.Clear();
|
|
||||||
}
|
|
||||||
//Game.LogTrivial($"cones count: {cones.Count}");
|
|
||||||
}
|
|
||||||
|
|
||||||
coneMenu.RemoveItemAt(2);
|
|
||||||
coneMenu.RemoveItemAt(2);
|
|
||||||
coneMenu.RemoveItemAt(2);
|
|
||||||
coneMenu.AddItem(removeLastCone = new UIMenuItem("Remove Last Cone"));
|
|
||||||
if (cones.Count == 0)
|
|
||||||
{
|
|
||||||
removeLastCone.Enabled = false;
|
|
||||||
}
|
|
||||||
coneMenu.AddItem(removeNearestCone = new UIMenuItem("Remove Nearest Cone"));
|
|
||||||
if (cones.Count == 0)
|
|
||||||
{
|
|
||||||
removeNearestCone.Enabled = false;
|
|
||||||
}
|
|
||||||
coneMenu.AddItem(removeAllCones = new UIMenuItem("Remove All Cones"));
|
|
||||||
if (cones.Count == 0)
|
|
||||||
{
|
|
||||||
removeAllCones.Enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void MyTerminationHandler(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
// Clean up paths
|
|
||||||
for (int i = 0; i < paths.Count; i++)
|
|
||||||
{
|
|
||||||
DeletePath(paths[i], i, deleteAllPaths);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up cones
|
|
||||||
foreach (Rage.Object cone in cones)
|
|
||||||
{
|
|
||||||
if (cone.IsValid() && cone.Exists())
|
|
||||||
{
|
|
||||||
cone.Delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear everything
|
|
||||||
cones.Clear();
|
|
||||||
TrafficPathing.ControlledVehicles.Clear();
|
|
||||||
|
|
||||||
Game.LogTrivial($"Scene Manager has been terminated.");
|
|
||||||
Game.DisplayNotification($"~o~Scene Manager\n~r~[Notice]~w~ The plugin has shut down.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,189 +1,166 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Drawing;
|
||||||
using Rage;
|
using Rage;
|
||||||
|
|
||||||
namespace SceneManager
|
namespace SceneManager
|
||||||
{
|
{
|
||||||
public static class TrafficPathing
|
public static class TrafficPathing
|
||||||
{
|
{
|
||||||
public static Dictionary<string, ControlledVehicle> ControlledVehicles = new Dictionary<string, ControlledVehicle>();
|
public static Dictionary<string, ControlledVehicle> collectedVehicles = new Dictionary<string, ControlledVehicle>();
|
||||||
//public static List<ControlledVehicle> ControlledVehicles = new List<ControlledVehicle> { };
|
|
||||||
|
|
||||||
public static void InitialWaypointVehicleCollector(List<WaypointData> waypointData)
|
public static void WaypointVehicleCollector(List<Path> paths, Path path, Waypoint waypoint)
|
||||||
{
|
{
|
||||||
waypointData[0].YieldZone = World.AddSpeedZone(waypointData[0].WaypointPos, 10f, waypointData[0].Speed);
|
//GameFiber AssignStopForVehiclesFlagFiber = new GameFiber(() => AssignStopForVehiclesFlag(paths, path, waypointData));
|
||||||
|
//AssignStopForVehiclesFlagFiber.Start();
|
||||||
|
|
||||||
// If there's a path with a single stop waypoint, run a loop to give all nearby AI the StopForVehicle driving flag so they don't just go around
|
while (paths.Contains(path) && path.Waypoint.Contains(waypoint))
|
||||||
if(waypointData.Count == 1)
|
|
||||||
{
|
{
|
||||||
GameFiber.StartNew(delegate
|
if (!path.PathDisabled && waypoint.Collector)
|
||||||
{
|
{
|
||||||
while (waypointData.ElementAtOrDefault(0) != null)
|
foreach (Vehicle v in GetNearbyVehicles(waypoint.WaypointPos, waypoint.CollectorRadius).Where(v => v.IsValidForCollection()))
|
||||||
{
|
{
|
||||||
foreach (Vehicle v in GetNearbyVehicles(waypointData[0].WaypointPos, 50f))
|
v.IsPersistent = true;
|
||||||
{
|
v.Driver.IsPersistent = true;
|
||||||
if(v.Exists() && v.IsValid() && v.HasDriver && v.Driver.Exists() && v.Driver.IsValid())
|
v.Driver.BlockPermanentEvents = true;
|
||||||
{
|
v.Driver.Tasks.Clear();
|
||||||
SetDriveTaskDrivingFlags(v.Driver, EDrivingFlags.StopForVehicles);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GameFiber.Yield();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
while (waypointData.ElementAtOrDefault(0) != null)
|
// If the vehicle is not in the collection yet
|
||||||
{
|
if (!collectedVehicles.ContainsKey(v.LicensePlate))
|
||||||
//Game.DisplaySubtitle($"Vehicles in collection: {ControlledVehicles.Count()}");
|
|
||||||
// Getting vehicles within 3f of waypoint
|
|
||||||
try
|
|
||||||
{
|
|
||||||
foreach (Vehicle v in GetNearbyVehicles(waypointData[0].WaypointPos, 3f))
|
|
||||||
{
|
|
||||||
// No protection for player if they drive into the waypoints
|
|
||||||
if(VehicleAndDriverValid(v) && v != Game.LocalPlayer.Character.CurrentVehicle && v.HasDriver && v.Driver.IsAlive && (v.IsCar || v.IsBike || v.IsBicycle || v.IsQuadBike))
|
|
||||||
{
|
{
|
||||||
// Check if there's an object in the list with a matching vehicle
|
var collectedVehicle = new ControlledVehicle(v, v.LicensePlate, path.PathNum, path.Waypoint.Count, waypoint.WaypointNum, true, false, false);
|
||||||
var matchingVehicle = ControlledVehicles.Where(cv => cv.Value.Vehicle == v).ToList();
|
collectedVehicles.Add(v.LicensePlate, collectedVehicle);
|
||||||
// If there's a match, then check if the first match has tasksAssigned. If not, AssignTasks
|
Game.LogTrivial($"[WaypointVehicleCollector] Added {v.Model.Name} to collection from path {path.PathNum}, waypoint {waypoint.WaypointNum}.");
|
||||||
if (matchingVehicle.ElementAtOrDefault(0).Value != null && !matchingVehicle[0].Value.TasksAssigned && !matchingVehicle[0].Value.DismissNow)
|
|
||||||
{
|
|
||||||
Game.LogTrivial($"[InitialWaypointVehicleCollector] {v.Model.Name} already in collection, but with no tasks. Assigning tasks.");
|
|
||||||
matchingVehicle[0].Value.TasksAssigned = true;
|
|
||||||
GameFiber AssignTasksFiber = new GameFiber(() => AssignTasks(matchingVehicle[0].Value, waypointData));
|
|
||||||
AssignTasksFiber.Start();
|
|
||||||
}
|
|
||||||
// Else if object doesn't exist, add to collection and AssignTasks
|
|
||||||
else if (matchingVehicle.ElementAtOrDefault(0).Value != null && matchingVehicle[0].Value.TasksAssigned)
|
|
||||||
{
|
|
||||||
//Game.LogTrivial($"Vehicle already in collection with tasks. Do nothing.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ControlledVehicles.Add(v.LicensePlate, new ControlledVehicle(v, v.LicensePlate, waypointData[0].Path, waypointData.Count, 1, true, false, false));
|
|
||||||
Game.LogTrivial($"Added {v.Model.Name} to collection from initial waypoint at path {waypointData[0].Path} with {waypointData.Count} waypoints");
|
|
||||||
|
|
||||||
GameFiber AssignTasksFiber = new GameFiber(() => AssignTasks(ControlledVehicles[v.LicensePlate], waypointData));
|
GameFiber DismissCheckFiber = new GameFiber(() => VehicleDismissed(collectedVehicle, path.Waypoint));
|
||||||
AssignTasksFiber.Start();
|
DismissCheckFiber.Start();
|
||||||
}
|
|
||||||
|
AssignTasks(collectedVehicle, path.Waypoint, waypoint);
|
||||||
|
}
|
||||||
|
// If the vehicle is in the collection, but has no tasks
|
||||||
|
else if (collectedVehicles.ContainsKey(v.LicensePlate) && !collectedVehicles[v.LicensePlate].TasksAssigned)
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"[WaypointVehicleCollector] {v.Model.Name} already in collection, but with no tasks. Assigning tasks.");
|
||||||
|
collectedVehicles[v.LicensePlate].TasksAssigned = true;
|
||||||
|
|
||||||
|
AssignTasks(collectedVehicles[v.LicensePlate], path.Waypoint, waypoint);
|
||||||
|
}
|
||||||
|
// If the vehicle is in the collection and has tasks
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"[WaypointVehicleCollector]: {v.Model.Name} was not collected because it's already in the collection and has tasks.");
|
||||||
}
|
}
|
||||||
GameFiber.Yield();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
GameFiber.Sleep(100);
|
||||||
{
|
//GameFiber.Yield();
|
||||||
Game.LogTrivial($"There was a problem getting vehicles near the start waypoint");
|
|
||||||
}
|
|
||||||
|
|
||||||
GameFiber.Yield();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DirectTask(ControlledVehicle cv, List<WaypointData> waypointData)
|
private static bool IsValidForCollection(this Vehicle v)
|
||||||
{
|
{
|
||||||
cv.DismissNow = false;
|
if (v && v.HasDriver && v.Driver && v.Driver.IsAlive && v != Game.LocalPlayer.Character.CurrentVehicle && (v.IsCar || v.IsBike || v.IsBicycle || v.IsQuadBike || (v.HasSiren && !v.IsSirenOn)))
|
||||||
if (VehicleAndDriverValid(cv))
|
|
||||||
{
|
{
|
||||||
cv.Vehicle.IsPersistent = true;
|
return true;
|
||||||
cv.Vehicle.Driver.BlockPermanentEvents = true;
|
|
||||||
cv.Vehicle.Driver.Tasks.Clear();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// Give vehicle task to initial waypoint of desired path, then run a loop to keep giving the task until they're close enough in case they try to wander away too early
|
|
||||||
cv.Vehicle.Driver.Tasks.DriveToPosition(waypointData[0].WaypointPos, waypointData[0].Speed, VehicleDrivingFlags.FollowTraffic, 1f);
|
|
||||||
while (waypointData.ElementAtOrDefault(0) != null && VehicleAndDriverValid(cv) && cv.Vehicle.DistanceTo(waypointData[0].WaypointPos) > 3f && !cv.DismissNow)
|
|
||||||
{
|
{
|
||||||
cv.Vehicle.Driver.Tasks.DriveToPosition(waypointData[0].WaypointPos, waypointData[0].Speed, VehicleDrivingFlags.FollowTraffic, 1f);
|
return false;
|
||||||
GameFiber.Sleep(500);
|
|
||||||
}
|
}
|
||||||
cv.Redirected = false;
|
|
||||||
Game.LogTrivial($"DirectTask loop over");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AssignTasks(ControlledVehicle cv, List<WaypointData> waypointData)
|
private static void AssignTasks(ControlledVehicle collectedVehicle, List<Waypoint> waypointData, Waypoint waypoint)
|
||||||
{
|
{
|
||||||
if (VehicleAndDriverValid(cv))
|
if (waypointData.Count == 1)
|
||||||
{
|
{
|
||||||
cv.Vehicle.IsPersistent = true;
|
GameFiber AssignSingleTaskFiber = new GameFiber(() => AssignSingleWaypointTask(collectedVehicle, waypointData));
|
||||||
cv.Vehicle.Driver.BlockPermanentEvents = true;
|
AssignSingleTaskFiber.Start();
|
||||||
cv.Vehicle.Driver.Tasks.Clear();
|
|
||||||
}
|
}
|
||||||
|
else if (waypointData.Count > 1)
|
||||||
if (waypointData.Count == 1 && VehicleAndDriverValid(cv) && !cv.DismissNow)
|
|
||||||
{
|
{
|
||||||
AssignSingleWaypointTask(cv, waypointData);
|
GameFiber AssignMultiTaskFiber = new GameFiber(() => AssignMultiWaypointTasks(collectedVehicle, waypointData, waypoint));
|
||||||
|
AssignMultiTaskFiber.Start();
|
||||||
}
|
}
|
||||||
else if(waypointData.Count > 1 && VehicleAndDriverValid(cv))
|
|
||||||
{
|
|
||||||
AssignMultiWaypointTasks(cv, waypointData);
|
|
||||||
}
|
|
||||||
while(!cv.DismissNow || cv.StoppedAtWaypoint)
|
|
||||||
{
|
|
||||||
GameFiber.Yield();
|
|
||||||
}
|
|
||||||
ControlledVehicles.Remove(cv.LicensePlate);
|
|
||||||
Game.LogTrivial($"AssignTasks exit");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AssignSingleWaypointTask(ControlledVehicle cv, List<WaypointData> waypointData)
|
// TODO: Combine single and multiwaypoint tasks into one method
|
||||||
|
private static void AssignSingleWaypointTask(ControlledVehicle cv, List<Waypoint> waypointData)
|
||||||
{
|
{
|
||||||
// Give driver a task to the single path waypoint. Run a loop with a condition checking for DismissNow for cases where the driver is dismissed or redirected
|
// Give driver a task to the single path waypoint. Run a loop with a condition checking for DismissNow for cases where the driver is dismissed or redirected
|
||||||
Game.LogTrivial($"Assigning task for single waypoint.");
|
Game.LogTrivial($"Assigning task for single waypoint.");
|
||||||
cv.Vehicle.Driver.Tasks.DriveToPosition(waypointData[0].WaypointPos, waypointData[0].Speed, VehicleDrivingFlags.FollowTraffic, 1f);
|
cv.Vehicle.Driver.Tasks.DriveToPosition(waypointData[0].WaypointPos, waypointData[0].Speed, (VehicleDrivingFlags)262539, 1f);
|
||||||
while (waypointData.ElementAtOrDefault(0) != null && VehicleAndDriverValid(cv) && cv.Vehicle.DistanceTo(waypointData[0].WaypointPos) > 3f && !cv.DismissNow)
|
//SetDriveTaskDrivingFlags(cv.Vehicle.Driver, EDrivingFlags.TotalControl);
|
||||||
|
while (waypointData.ElementAtOrDefault(0) != null && cv.Vehicle && cv.Vehicle.Driver && cv.Vehicle.DistanceTo(waypointData[0].WaypointPos) > 3f && !cv.DismissNow)
|
||||||
{
|
{
|
||||||
GameFiber.Sleep(1000);
|
GameFiber.Sleep(1000);
|
||||||
}
|
}
|
||||||
Game.LogTrivial($"{cv.Vehicle.Model.Name} should be stopped at the waypoint.");
|
|
||||||
cv.Vehicle.Driver.Tasks.PerformDrivingManeuver(VehicleManeuver.GoForwardStraightBraking);//.WaitForCompletion();
|
if (cv.DismissNow)
|
||||||
cv.Vehicle.Driver.Tasks.PerformDrivingManeuver(VehicleManeuver.Wait);
|
{
|
||||||
cv.StoppedAtWaypoint = true;
|
Game.LogTrivial($"{cv.Vehicle.Model.Name} dismissed while in AssignSingleWaypointTask.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"{cv.Vehicle.Model.Name} should be stopped at the waypoint.");
|
||||||
|
cv.Vehicle.Driver.Tasks.PerformDrivingManeuver(VehicleManeuver.GoForwardStraightBraking);//.WaitForCompletion();
|
||||||
|
cv.Vehicle.Driver.Tasks.PerformDrivingManeuver(VehicleManeuver.Wait);
|
||||||
|
cv.StoppedAtWaypoint = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AssignMultiWaypointTasks(ControlledVehicle cv, List<WaypointData> waypointData)
|
private static void AssignMultiWaypointTasks(ControlledVehicle cv, List<Waypoint> waypointData, Waypoint collectorWaypoint)
|
||||||
{
|
{
|
||||||
// For each waypoint in the path, give driver a task to that waypoint
|
// For each waypoint in the path, give driver a task to that waypoint
|
||||||
for (int i = 1; i < waypointData.Count; i++)
|
// i needs to be the index of the waypoint the vehicle was collected from
|
||||||
|
for (int i = waypointData.IndexOf(collectorWaypoint); i < waypointData.Count; i++)
|
||||||
|
//for (int i = 1; i < waypointData.Count; i++)
|
||||||
{
|
{
|
||||||
if (cv.DismissNow)
|
if (!cv.DismissNow)
|
||||||
{
|
{
|
||||||
break;
|
cv.CurrentWaypoint = waypointData[i].WaypointNum;
|
||||||
}
|
var nextWaypoint = i + 1;
|
||||||
Game.LogTrivial($"Assigning task to {cv.Vehicle.Model.Name} for waypoint {i+1} of {waypointData.Count}");
|
Game.LogTrivial($"Assigning task to {cv.Vehicle.Model.Name} from waypoint {nextWaypoint} of {waypointData.Count}");
|
||||||
cv.CurrentWaypoint++;
|
|
||||||
//if (VehicleAndDriverValid(cv) && waypointData.ElementAtOrDefault(i) != null && i == waypointData.IndexOf(waypointData.Last()) && waypointData.Last().DrivingFlag == VehicleDrivingFlags.StopAtDestination)
|
if (cv.Vehicle && cv.Vehicle.Driver && waypointData.ElementAtOrDefault(nextWaypoint) != null && waypointData[nextWaypoint].DrivingFlag == VehicleDrivingFlags.StopAtDestination)
|
||||||
if (VehicleAndDriverValid(cv) && waypointData.ElementAtOrDefault(i) != null && waypointData[i].DrivingFlag == VehicleDrivingFlags.StopAtDestination) // NEW
|
|
||||||
{
|
|
||||||
// Give driver a task to the waypoint. Run a loop with a condition checking for DismissNow for cases where the driver is dismissed or redirected
|
|
||||||
cv.Vehicle.Driver.Tasks.DriveToPosition(waypointData[i].WaypointPos, waypointData[i].Speed, VehicleDrivingFlags.FollowTraffic, 1f);
|
|
||||||
while (waypointData.ElementAtOrDefault(i) != null && cv.Vehicle.DistanceTo(waypointData[i].WaypointPos) > 3f && !cv.DismissNow)
|
|
||||||
{
|
{
|
||||||
GameFiber.Yield();
|
// Give driver a task to the waypoint. Run a loop with a condition checking for DismissNow for cases where the driver is dismissed or redirected
|
||||||
}
|
SetDriveTaskDrivingFlags(cv.Vehicle.Driver, EDrivingFlags.TotalControl);
|
||||||
if (cv.DismissNow)
|
if (waypointData[nextWaypoint] != null)
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (waypointData.ElementAtOrDefault(i) != null)
|
|
||||||
{
|
|
||||||
Game.LogTrivial($"{cv.Vehicle.Model.Name} stopping at stop waypoint");
|
|
||||||
//Rage.Native.NativeFunction.Natives.x260BE8F09E326A20(v, 3f, 1, false);
|
|
||||||
cv.Vehicle.Driver.Tasks.PerformDrivingManeuver(VehicleManeuver.GoForwardStraightBraking);
|
|
||||||
cv.StoppedAtWaypoint = true;
|
|
||||||
while(waypointData.ElementAtOrDefault(i) != null && cv.StoppedAtWaypoint && !cv.DismissNow)
|
|
||||||
{
|
{
|
||||||
GameFiber.Yield();
|
//Game.LogTrivial($"Driving to stop waypoint");
|
||||||
|
cv.Vehicle.Driver.Tasks.DriveToPosition(waypointData[nextWaypoint].WaypointPos, waypointData[nextWaypoint].Speed, (VehicleDrivingFlags)262539, 1f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"i is out of bounds for assigning task");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cv.Vehicle && cv.Vehicle.Driver && waypointData.ElementAtOrDefault(nextWaypoint) != null && cv.Vehicle.DistanceTo(waypointData[nextWaypoint].WaypointPos) > 3f && !cv.DismissNow)
|
||||||
|
{
|
||||||
|
GameFiber.Sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waypointData.ElementAtOrDefault(i) != null && !cv.DismissNow)
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"{cv.Vehicle.Model.Name} stopping at stop waypoint");
|
||||||
|
cv.Vehicle.Driver.Tasks.PerformDrivingManeuver(VehicleManeuver.GoForwardStraightBraking);
|
||||||
|
cv.StoppedAtWaypoint = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (cv.Vehicle && cv.Vehicle.Driver && waypointData.ElementAtOrDefault(nextWaypoint) != null && !cv.DismissNow)
|
||||||
|
{
|
||||||
|
cv.Vehicle.Driver.Tasks.DriveToPosition(waypointData[nextWaypoint].WaypointPos, waypointData[nextWaypoint].Speed, (VehicleDrivingFlags)262539, 1f).WaitForCompletion();
|
||||||
|
}
|
||||||
|
Game.LogTrivial($"{cv.Vehicle.Model.Name} waypoint {nextWaypoint} task complete");
|
||||||
}
|
}
|
||||||
else if (VehicleAndDriverValid(cv) && waypointData.ElementAtOrDefault(i) != null && !cv.DismissNow)
|
else
|
||||||
{
|
{
|
||||||
cv.Vehicle.Driver.Tasks.DriveToPosition(waypointData[i].WaypointPos, waypointData[i].Speed, VehicleDrivingFlags.FollowTraffic, 1f).WaitForCompletion();
|
Game.LogTrivial($"{cv.Vehicle.Model.Name} was dismissed while in AssignMultiWaypointTasks");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
Game.LogTrivial($"{cv.Vehicle.Model.Name} waypoint {i+1} task complete");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cv.Redirected)
|
if (cv.Redirected)
|
||||||
{
|
{
|
||||||
Game.LogTrivial($"{cv.Vehicle.Model.Name} was redirected, all old path tasks have been cleared.");
|
Game.LogTrivial($"{cv.Vehicle.Model.Name} was redirected, all old path tasks have been cleared.");
|
||||||
|
|
@ -193,45 +170,102 @@ namespace SceneManager
|
||||||
Game.LogTrivial($"{cv.Vehicle.Model.Name} all path {cv.Path} tasks complete.");
|
Game.LogTrivial($"{cv.Vehicle.Model.Name} all path {cv.Path} tasks complete.");
|
||||||
}
|
}
|
||||||
|
|
||||||
cv.TasksAssigned = false;
|
DismissDriver(cv);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DismissDriver(ControlledVehicle cv)
|
||||||
|
{
|
||||||
cv.DismissNow = true;
|
cv.DismissNow = true;
|
||||||
cv.StoppedAtWaypoint = false;
|
cv.StoppedAtWaypoint = false;
|
||||||
if (VehicleAndDriverValid(cv) && !cv.Redirected)
|
if (cv.Vehicle && cv.Vehicle.Driver && !cv.Redirected)
|
||||||
{
|
{
|
||||||
cv.Vehicle.Driver.Dismiss();
|
cv.Vehicle.Driver.Dismiss();
|
||||||
cv.Vehicle.Driver.Tasks.Clear();
|
cv.Vehicle.Driver.Tasks.Clear();
|
||||||
//cv.Vehicle.IsPersistent = false;
|
|
||||||
cv.Vehicle.Driver.BlockPermanentEvents = false;
|
cv.Vehicle.Driver.BlockPermanentEvents = false;
|
||||||
|
cv.Vehicle.Driver.IsPersistent = false;
|
||||||
|
|
||||||
|
cv.Vehicle.Dismiss();
|
||||||
|
cv.Vehicle.IsPersistent = false;
|
||||||
|
|
||||||
|
Game.LogTrivial($"{cv.Vehicle.Model.Name} dismissed successfully.");
|
||||||
}
|
}
|
||||||
else if(!VehicleAndDriverValid(cv))
|
else if (!cv.Vehicle)
|
||||||
{
|
{
|
||||||
Game.LogTrivial($"The vehicle is not valid after tasks completed.");
|
Game.LogTrivial($"{cv.Vehicle.Model.Name} is not valid after tasks completed.");
|
||||||
|
}
|
||||||
|
else if (!cv.Vehicle.Driver)
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"{cv.Vehicle.Model.Name} driver is not valid after tasks completed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool VehicleAndDriverValid(Vehicle v)
|
public static void AssignStopForVehiclesFlag(List<Path> paths, Path path, Waypoint waypointData)
|
||||||
{
|
{
|
||||||
// Ensure everything is valid before we do stuff with them so there isn't a crash
|
while (paths.Contains(path) && path.Waypoint.Contains(waypointData))
|
||||||
if (v.Exists() && v.IsValid() && v.Driver.Exists() && v.Driver.IsValid())
|
|
||||||
{
|
{
|
||||||
return true;
|
if (!path.PathDisabled)
|
||||||
}
|
{
|
||||||
else
|
foreach (Vehicle v in GetNearbyVehicles(waypointData.WaypointPos, 50f).Where(v => v && v.HasDriver && v.Driver))
|
||||||
{
|
{
|
||||||
return false;
|
SetDriveTaskDrivingFlags(v.Driver, EDrivingFlags.StopForVehicles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GameFiber.Sleep(500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool VehicleAndDriverValid(ControlledVehicle cv)
|
public static void DirectTask(ControlledVehicle cv, List<Waypoint> waypointData)
|
||||||
{
|
{
|
||||||
// Ensure everything is valid before we do stuff with them so there isn't a crash
|
cv.DismissNow = false;
|
||||||
if(cv.Vehicle.Exists() && cv.Vehicle.IsValid() && cv.Vehicle.Driver.Exists() && cv.Vehicle.Driver.IsValid())
|
if (cv.Vehicle && cv.Vehicle.Driver)
|
||||||
{
|
{
|
||||||
return true;
|
cv.Vehicle.IsPersistent = true;
|
||||||
|
cv.Vehicle.Driver.IsPersistent = true;
|
||||||
|
cv.Vehicle.Driver.BlockPermanentEvents = true;
|
||||||
|
cv.Vehicle.Driver.Tasks.Clear();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Give vehicle task to initial waypoint of desired path, then run a loop to keep giving the task until they're close enough in case they try to wander away too early
|
||||||
|
// Need to figure out how to only get waypoints which are in front of or within 90 degrees of either side of the vehicle
|
||||||
|
var nearestWaypoint = waypointData.OrderBy(wp => wp.WaypointPos).Take(1) as Waypoint;
|
||||||
|
|
||||||
|
cv.Vehicle.Driver.Tasks.DriveToPosition(nearestWaypoint.WaypointPos, nearestWaypoint.Speed, (VehicleDrivingFlags)262539, 1f); // waypointData[0].WaypointPos
|
||||||
|
while (waypointData.ElementAtOrDefault(0) != null && cv.Vehicle && cv.Vehicle.Driver && cv.Vehicle.DistanceTo(waypointData[0].WaypointPos) > 3f && !cv.DismissNow)
|
||||||
{
|
{
|
||||||
return false;
|
cv.Vehicle.Driver.Tasks.DriveToPosition(nearestWaypoint.WaypointPos, nearestWaypoint.Speed, (VehicleDrivingFlags)262539, 1f);
|
||||||
|
GameFiber.Sleep(500);
|
||||||
|
}
|
||||||
|
cv.Redirected = false;
|
||||||
|
Game.LogTrivial($"DirectTask loop over");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void VehicleDismissed(ControlledVehicle cv, List<Waypoint> waypointData)
|
||||||
|
{
|
||||||
|
while (!cv.DismissNow)
|
||||||
|
{
|
||||||
|
GameFiber.Sleep(500);
|
||||||
|
}
|
||||||
|
Game.LogTrivial($"{cv.Vehicle.Model.Name} was dismissed (dismissal check loop).");
|
||||||
|
|
||||||
|
|
||||||
|
Game.LogTrivial($"Looping to ensure the vehicle is far enough away from all attractor waypoints so it can be removed from the collection.");
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var collectorWaypoints = waypointData.Where(wp => wp.Collector);
|
||||||
|
var vehicleFarEnoughAwayFromCollectors = collectorWaypoints.All(wp => cv.Vehicle.DistanceTo(wp.WaypointPos) > wp.CollectorRadius);
|
||||||
|
|
||||||
|
if (collectedVehicles.ContainsKey(cv.LicensePlate) && vehicleFarEnoughAwayFromCollectors)
|
||||||
|
{
|
||||||
|
Game.LogTrivial($"{cv.Vehicle.Model.Name} is far enough away from all attractor waypoints and has been removed from the collection.");
|
||||||
|
cv.TasksAssigned = false;
|
||||||
|
cv.Vehicle.Driver.BlockPermanentEvents = false;
|
||||||
|
cv.Vehicle.Driver.IsPersistent = false;
|
||||||
|
cv.Vehicle.IsPersistent = false;
|
||||||
|
collectedVehicles.Remove(cv.LicensePlate);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GameFiber.Sleep(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -241,6 +275,7 @@ namespace SceneManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// Driving styles https://gtaforums.com/topic/822314-guide-driving-styles/
|
// Driving styles https://gtaforums.com/topic/822314-guide-driving-styles/
|
||||||
|
// also https://vespura.com/fivem/drivingstyle/
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum EDrivingFlags
|
public enum EDrivingFlags
|
||||||
{
|
{
|
||||||
|
|
@ -248,13 +283,17 @@ namespace SceneManager
|
||||||
StopForVehicles = 1,
|
StopForVehicles = 1,
|
||||||
StopForPeds = 2,
|
StopForPeds = 2,
|
||||||
AvoidEmptyVehicles = 8,
|
AvoidEmptyVehicles = 8,
|
||||||
|
AvoidPeds = 16,
|
||||||
|
AvoidObjects = 32,
|
||||||
StopForTrafficLights = 128,
|
StopForTrafficLights = 128,
|
||||||
UseBlinkers = 256,
|
UseBlinkers = 256,
|
||||||
|
AllowWrongWay = 512,
|
||||||
TakeShortestPath = 262144,
|
TakeShortestPath = 262144,
|
||||||
IgnoreRoads = 4194304,
|
IgnoreRoads = 4194304,
|
||||||
|
IgnorePathfinding = 16777216,
|
||||||
AvoidHighways = 536870912,
|
AvoidHighways = 536870912,
|
||||||
Normal = StopForVehicles | StopForPeds | AvoidEmptyVehicles | StopForTrafficLights | UseBlinkers,
|
Normal = StopForVehicles | StopForPeds | AvoidEmptyVehicles | StopForTrafficLights | UseBlinkers,
|
||||||
//TotalControl = AllowMedianCrossing | AllowWrongWay | DriveAroundObjects | DriveAroundPeds | DriveBySight | FollowTraffic | IgnorePathfinding
|
TotalControl = AllowWrongWay | AvoidObjects | AvoidPeds | TakeShortestPath | StopForTrafficLights | IgnorePathfinding | StopForVehicles
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetDriveTaskDrivingFlags(this Ped ped, EDrivingFlags flags)
|
public static void SetDriveTaskDrivingFlags(this Ped ped, EDrivingFlags flags)
|
||||||
|
|
@ -264,23 +303,3 @@ namespace SceneManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
//while (waypointData.ElementAtOrDefault(0) != null && v.Exists() && v.IsValid() && v.Driver.Exists() && v.Driver.IsValid() && !cv.DismissNow)
|
|
||||||
//{
|
|
||||||
//if (waypointData.ElementAtOrDefault(0) == null || cv.DismissNow)
|
|
||||||
//{
|
|
||||||
//driver.Tasks.Clear();
|
|
||||||
//Game.LogTrivial($"{v.Model.Name} released from wait loop");
|
|
||||||
//break;
|
|
||||||
//}
|
|
||||||
//else if (waypointData.ElementAtOrDefault(0) != null && !cv.DismissNow && v.Driver.IsInVehicle(v, false))
|
|
||||||
//{
|
|
||||||
v.Driver.Tasks.PerformDrivingManeuver(VehicleManeuver.GoForwardStraightBraking);
|
|
||||||
//v.Driver.Tasks.PerformDrivingManeuver(VehicleManeuver.Wait);
|
|
||||||
//}
|
|
||||||
//GameFiber.Yield();
|
|
||||||
//}
|
|
||||||
//v.Driver.Tasks.Clear();
|
|
||||||
//Game.LogTrivial($"{v.Model.Name} is dismissed or the driver is not in the vehicle.");
|
|
||||||
*/
|
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
using Rage;
|
|
||||||
|
|
||||||
namespace SceneManager
|
|
||||||
{
|
|
||||||
public class WaypointData
|
|
||||||
{
|
|
||||||
public int Path;
|
|
||||||
public Vector3 WaypointPos;
|
|
||||||
public float Speed;
|
|
||||||
public VehicleDrivingFlags DrivingFlag;
|
|
||||||
public Blip WaypointBlip;
|
|
||||||
public uint YieldZone;
|
|
||||||
|
|
||||||
public WaypointData(int path, Vector3 waypointPos, float speed, VehicleDrivingFlags drivingFlag, Blip waypointBlip, uint yieldZone)
|
|
||||||
{
|
|
||||||
Path = path;
|
|
||||||
WaypointPos = waypointPos;
|
|
||||||
Speed = speed;
|
|
||||||
DrivingFlag = drivingFlag;
|
|
||||||
WaypointBlip = waypointBlip;
|
|
||||||
YieldZone = yieldZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WaypointData(int path, Vector3 waypointPos, float speed, VehicleDrivingFlags drivingFlag, Blip waypointBlip)
|
|
||||||
{
|
|
||||||
Path = path;
|
|
||||||
WaypointPos = waypointPos;
|
|
||||||
Speed = speed;
|
|
||||||
DrivingFlag = drivingFlag;
|
|
||||||
WaypointBlip = waypointBlip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue