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

Mouse can now be used to fully navigate menus

This commit is contained in:
Rich Dunne 2020-10-23 06:22:19 -06:00
parent f81c7675c8
commit 9ff7aabd9f
8 changed files with 1476 additions and 607 deletions

View file

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Windows.Forms;
using Rage; using Rage;
using RAGENativeUI; using RAGENativeUI;
using RAGENativeUI.Elements; using RAGENativeUI.Elements;
@ -21,6 +22,10 @@ namespace SceneManager
{ {
barrierMenu.ParentMenu = MainMenu.mainMenu; barrierMenu.ParentMenu = MainMenu.mainMenu;
MenuManager.menuPool.Add(barrierMenu); MenuManager.menuPool.Add(barrierMenu);
barrierMenu.OnItemSelect += BarrierMenu_OnItemSelected;
barrierMenu.OnScrollerChange += BarrierMenu_OnScrollerChange;
barrierMenu.OnMenuOpen += BarrierMenu_OnMouseDown;
} }
internal static void BuildBarrierMenu() internal static void BuildBarrierMenu()
@ -37,23 +42,20 @@ namespace SceneManager
barrierMenu.AddItem(barrierList, 0); barrierMenu.AddItem(barrierList, 0);
barrierList.ForeColor = Color.Gold; barrierList.ForeColor = Color.Gold;
barrierMenu.OnItemSelect += BarrierMenu_OnItemSelected;
barrierMenu.OnScrollerChange += BarrierMenu_OnScrollerChange;
} }
internal static void CreateShadowBarrier(UIMenu barrierMenu) internal static void CreateShadowBarrier(UIMenu barrierMenu)
{ {
Hints.Display($"~o~Scene Manager ~y~[Hint]\n~y~ ~w~The shadow cone will disappear if you aim too far away."); Hints.Display($"~o~Scene Manager ~y~[Hint]\n~w~The shadow cone will disappear if you aim too far away.");
if (shadowBarrier) if (shadowBarrier)
shadowBarrier.Delete(); shadowBarrier.Delete();
shadowBarrier = new Rage.Object(Settings.barrierValues[barrierList.Index], TracePlayerView(Settings.BarrierPlacementDistance, TraceFlags.IntersectWorld).HitPosition, rotateBarrier.Value); shadowBarrier = new Object(Settings.barrierValues[barrierList.Index], GetMousePositionInWorld(), rotateBarrier.Value);
if (!shadowBarrier) if (!shadowBarrier)
{ {
barrierMenu.Close(); barrierMenu.Close();
Game.DisplayNotification($"~o~Scene Manager ~red~[Error]\n~w~ Something went wrong creating the shadow barrier. Please try again."); Game.DisplayNotification($"~o~Scene Manager ~r~[Error]\n~w~Something went wrong creating the shadow barrier. Please try again.");
return; return;
} }
Rage.Native.NativeFunction.Natives.PLACE_OBJECT_ON_GROUND_PROPERLY(shadowBarrier); Rage.Native.NativeFunction.Natives.PLACE_OBJECT_ON_GROUND_PROPERLY(shadowBarrier);
@ -86,7 +88,7 @@ namespace SceneManager
void UpdateShadowBarrierPosition() void UpdateShadowBarrierPosition()
{ {
DisableBarrierMenuOptionsIfShadowConeTooFar(); DisableBarrierMenuOptionsIfShadowConeTooFar();
shadowBarrier.SetPositionWithSnap(TracePlayerView(Settings.BarrierPlacementDistance, TraceFlags.IntersectWorld).HitPosition); shadowBarrier.SetPositionWithSnap(GetMousePositionInWorld());
void DisableBarrierMenuOptionsIfShadowConeTooFar() void DisableBarrierMenuOptionsIfShadowConeTooFar()
{ {
@ -108,37 +110,95 @@ namespace SceneManager
} }
} }
} }
//------------ 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
HitResult TracePlayerView(float maxTraceDistance = 30f, TraceFlags flags = TraceFlags.IntersectWorld) => TracePlayerView2(out Vector3 v1, out Vector3 v2, maxTraceDistance, flags);
HitResult TracePlayerView2(out Vector3 start, out Vector3 end, float maxTraceDistance, TraceFlags flags)
{
Vector3 direction = GetPlayerLookingDirection(out start);
end = start + (maxTraceDistance * direction);
var barrierObjects = barriers.Where(b => b.Object).Select(b => b.Object).ToArray();
return World.TraceLine(start, end, flags, barrierObjects);
} }
Vector3 GetPlayerLookingDirection(out Vector3 camPosition) private static void SpawnBarrier()
{ {
if (Camera.RenderingCamera) var barrier = new Rage.Object(shadowBarrier.Model, shadowBarrier.Position, rotateBarrier.Value);
{ barrier.SetPositionWithSnap(shadowBarrier.Position);
camPosition = Camera.RenderingCamera.Position; Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(barrier, true);
return Camera.RenderingCamera.Direction; barrier.IsPositionFrozen = false;
} Rage.Native.NativeFunction.Natives.SET_DISABLE_FRAG_DAMAGE(barrier, true);
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>(); barriers.Add(new Barrier(barrier, barrier.Position, barrier.Heading));
return (Game.LocalPlayer.Character.Rotation + new Rotator(pitch, 0, heading)).ToVector().ToNormalized(); removeBarrierOptions.Enabled = true;
resetBarriers.Enabled = true;
} }
private static void SpawnFlare()
{
var flare = new Weapon("weapon_flare", shadowBarrier.Position, 1);
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(flare, true);
GameFiber.StartNew(() =>
{
while (flare && flare.HeightAboveGround > 0.05f)
{
GameFiber.Yield();
} }
//------------ CREDIT PNWPARKS FOR THESE FUNCTIONS ------------\\ GameFiber.Sleep(1000);
if (flare)
{
flare.IsPositionFrozen = true;
}
});
barriers.Add(new Barrier(flare, flare.Position, flare.Heading));
removeBarrierOptions.Enabled = true;
}
private static void RemoveBarrier()
{
switch (removeBarrierOptions.Index)
{
case 0:
barriers[barriers.Count - 1].Object.Delete();
barriers.RemoveAt(barriers.Count - 1);
break;
case 1:
var nearestBarrier = barriers.OrderBy(b => b.Object.DistanceTo2D(Game.LocalPlayer.Character)).FirstOrDefault();
if (nearestBarrier != null)
{
nearestBarrier.Object.Delete();
barriers.Remove(nearestBarrier);
}
break;
case 2:
foreach (Barrier b in barriers.Where(b => b.Object))
{
b.Object.Delete();
}
if (barriers.Count > 0)
{
barriers.Clear();
}
break;
}
removeBarrierOptions.Enabled = barriers.Count == 0 ? false : true;
resetBarriers.Enabled = barriers.Count == 0 ? false : true;
}
private static void ResetBarriers()
{
var currentBarriers = barriers.Where(b => b.Model.Name != "0xa2c44e80").ToList(); // 0xa2c44e80 is the flare weapon hash
foreach (Barrier barrier in currentBarriers)
{
var newBarrier = new Rage.Object(barrier.Model, barrier.Position, barrier.Rotation);
newBarrier.SetPositionWithSnap(barrier.Position);
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(newBarrier, true);
newBarrier.IsPositionFrozen = false;
Rage.Native.NativeFunction.Natives.SET_DISABLE_FRAG_DAMAGE(newBarrier, true);
barriers.Add(new Barrier(newBarrier, newBarrier.Position, newBarrier.Heading));
if (barrier.Object)
{
barrier.Object.Delete();
}
barriers.Remove(barrier);
}
currentBarriers.Clear();
} }
private static void BarrierMenu_OnScrollerChange(UIMenu sender, UIMenuScrollerItem scrollerItem, int oldIndex, int newIndex) private static void BarrierMenu_OnScrollerChange(UIMenu sender, UIMenuScrollerItem scrollerItem, int oldIndex, int newIndex)
@ -167,7 +227,7 @@ namespace SceneManager
private static void BarrierMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index) private static void BarrierMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
{ {
if (selectedItem == barrierList as UIMenuItem) if (selectedItem == barrierList)
{ {
// Attach some invisible object to the cone which the AI try to drive around // 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 // Barrier rotates with cone and becomes invisible similar to ASC when created
@ -182,99 +242,174 @@ namespace SceneManager
} }
if (selectedItem == removeBarrierOptions as UIMenuItem) if (selectedItem == removeBarrierOptions)
{ {
RemoveBarrier(); RemoveBarrier();
} }
if (selectedItem == resetBarriers) if (selectedItem == resetBarriers)
{ {
var currentBarriers = barriers.Where(b => b.Model.Name != "0xa2c44e80").ToList(); // 0xa2c44e80 is the flare weapon hash ResetBarriers();
foreach (Barrier barrier in currentBarriers)
{
var newBarrier = new Rage.Object(barrier.Model, barrier.Position, barrier.Rotation);
newBarrier.SetPositionWithSnap(barrier.Position);
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(newBarrier, true);
newBarrier.IsPositionFrozen = false;
Rage.Native.NativeFunction.Natives.SET_DISABLE_FRAG_DAMAGE(newBarrier, true);
barriers.Add(new Barrier(newBarrier, newBarrier.Position, newBarrier.Heading));
if (barrier.Object)
{
barrier.Object.Delete();
} }
barriers.Remove(barrier);
}
currentBarriers.Clear();
} }
void SpawnBarrier() private static void BarrierMenu_OnMouseDown(UIMenu menu)
{ {
var barrier = new Rage.Object(shadowBarrier.Model, shadowBarrier.Position, rotateBarrier.Value);
barrier.SetPositionWithSnap(shadowBarrier.Position);
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(barrier, true);
barrier.IsPositionFrozen = false;
Rage.Native.NativeFunction.Natives.SET_DISABLE_FRAG_DAMAGE(barrier, true);
barriers.Add(new Barrier(barrier, barrier.Position, barrier.Heading));
removeBarrierOptions.Enabled = true;
resetBarriers.Enabled = true;
}
void SpawnFlare()
{
var flare = new Weapon("weapon_flare", shadowBarrier.Position, 1);
Rage.Native.NativeFunction.Natives.SET_ENTITY_DYNAMIC(flare, true);
GameFiber.StartNew(() => GameFiber.StartNew(() =>
{ {
while (flare && flare.HeightAboveGround > 0.05f) while (menu.Visible)
{ {
GameFiber.Yield(); var selectedScroller = menu.MenuItems.Where(x => (x == barrierList || x == rotateBarrier || x == removeBarrierOptions) && x.Selected).FirstOrDefault();
if (selectedScroller != null)
{
HandleScrollerItemsWithMouseWheel(selectedScroller);
} }
GameFiber.Sleep(1000);
if (flare) // Add waypoint if menu item is selected and user left clicks
if (Game.IsKeyDown(Keys.LButton))
{ {
flare.IsPositionFrozen = true; OnMenuItemClicked();
}
GameFiber.Yield();
} }
}); });
barriers.Add(new Barrier(flare, flare.Position, flare.Heading)); void OnMenuItemClicked()
removeBarrierOptions.Enabled = true; {
if (barrierList.Selected)
{
if (barrierList.SelectedItem == "Flare")
{
SpawnFlare();
}
else
{
SpawnBarrier();
}
}
else if (removeBarrierOptions.Selected)
{
RemoveBarrier();
}
else if (resetBarriers.Selected)
{
ResetBarriers();
}
} }
void RemoveBarrier() void HandleScrollerItemsWithMouseWheel(UIMenuItem selectedScroller)
{ {
switch (removeBarrierOptions.Index) var menuScrollingDisabled = false;
var menuItems = menu.MenuItems.Where(x => x != selectedScroller);
while (Game.IsShiftKeyDownRightNow)
{ {
case 0: menu.ResetKey(Common.MenuControls.Up);
barriers[barriers.Count - 1].Object.Delete(); menu.ResetKey(Common.MenuControls.Down);
barriers.RemoveAt(barriers.Count - 1); menuScrollingDisabled = true;
break; ScrollMenuItem();
case 1: GameFiber.Yield();
var nearestBarrier = barriers.OrderBy(b => b.Object.DistanceTo2D(Game.LocalPlayer.Character)).FirstOrDefault();
if(nearestBarrier != null)
{
nearestBarrier.Object.Delete();
barriers.Remove(nearestBarrier);
}
break;
case 2:
foreach (Barrier b in barriers.Where(b => b.Object))
{
b.Object.Delete();
}
if (barriers.Count > 0)
{
barriers.Clear();
}
break;
} }
removeBarrierOptions.Enabled = barriers.Count == 0 ? false : true; if (menuScrollingDisabled)
resetBarriers.Enabled = barriers.Count == 0 ? false : true; {
menuScrollingDisabled = false;
menu.SetKey(Common.MenuControls.Up, GameControl.CursorScrollUp);
menu.SetKey(Common.MenuControls.Up, GameControl.CellphoneUp);
menu.SetKey(Common.MenuControls.Down, GameControl.CursorScrollDown);
menu.SetKey(Common.MenuControls.Down, GameControl.CellphoneDown);
} }
void ScrollMenuItem()
{
if (Game.GetMouseWheelDelta() > 0)
{
if (selectedScroller == barrierList)
{
barrierList.ScrollToNextOption();
CreateShadowBarrier(barrierMenu);
if (barrierList.SelectedItem == "Flare")
{
rotateBarrier.Enabled = false;
}
else
{
rotateBarrier.Enabled = true;
}
barrierMenu.Width = SetMenuWidth();
}
else if (selectedScroller == rotateBarrier)
{
rotateBarrier.ScrollToNextOption();
shadowBarrier.Heading = rotateBarrier.Value;
}
else if (selectedScroller == removeBarrierOptions)
{
removeBarrierOptions.ScrollToNextOption();
}
}
else if (Game.GetMouseWheelDelta() < 0)
{
if (selectedScroller == barrierList)
{
barrierList.ScrollToPreviousOption();
CreateShadowBarrier(barrierMenu);
if (barrierList.SelectedItem == "Flare")
{
rotateBarrier.Enabled = false;
}
else
{
rotateBarrier.Enabled = true;
}
barrierMenu.Width = SetMenuWidth();
}
else if (selectedScroller == rotateBarrier)
{
rotateBarrier.ScrollToPreviousOption();
shadowBarrier.Heading = rotateBarrier.Value;
}
else if(selectedScroller == removeBarrierOptions)
{
removeBarrierOptions.ScrollToPreviousOption();
}
}
}
}
}
private static Vector3 GetMousePositionInWorld()
{
HitResult TracePlayerView(float maxTraceDistance = 30f, TraceFlags flags = TraceFlags.IntersectWorld) => TracePlayerView2(out Vector3 v1, out Vector3 v2, maxTraceDistance, flags);
HitResult TracePlayerView2(out Vector3 start, out Vector3 end, float maxTraceDistance, TraceFlags flags)
{
Vector3 direction = GetPlayerLookingDirection(out start);
end = start + (maxTraceDistance * direction);
return World.TraceLine(start, end, flags);
}
Vector3 GetPlayerLookingDirection(out Vector3 camPosition)
{
if (Camera.RenderingCamera)
{
camPosition = Camera.RenderingCamera.Position;
return Camera.RenderingCamera.Direction;
}
else
{
float pitch = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_RELATIVE_PITCH<float>();
float heading = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_RELATIVE_HEADING<float>();
camPosition = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_COORD<Vector3>();
return (Game.LocalPlayer.Character.Rotation + new Rotator(pitch, 0, heading)).ToVector().ToNormalized();
}
}
return TracePlayerView(Settings.BarrierPlacementDistance, TraceFlags.IntersectWorld).HitPosition;
} }
private static float SetMenuWidth() private static float SetMenuWidth()

View file

@ -1,4 +1,6 @@
using System.Drawing; using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Rage; using Rage;
using RAGENativeUI; using RAGENativeUI;
using RAGENativeUI.Elements; using RAGENativeUI.Elements;
@ -15,6 +17,9 @@ namespace SceneManager
{ {
editPathMenu.ParentMenu = PathMainMenu.pathMainMenu; editPathMenu.ParentMenu = PathMainMenu.pathMainMenu;
MenuManager.menuPool.Add(editPathMenu); MenuManager.menuPool.Add(editPathMenu);
editPathMenu.OnItemSelect += EditPath_OnItemSelected;
editPathMenu.OnCheckboxChange += EditPath_OnCheckboxChange;
editPathMenu.OnMenuOpen += EditPath_OnMouseDown;
} }
internal static void BuildEditPathMenu() internal static void BuildEditPathMenu()
@ -26,22 +31,44 @@ namespace SceneManager
deletePath.ForeColor = Color.Gold; deletePath.ForeColor = Color.Gold;
editPathMenu.RefreshIndex(); editPathMenu.RefreshIndex();
editPathMenu.OnItemSelect += EditPath_OnItemSelected;
editPathMenu.OnCheckboxChange += EditPath_OnCheckboxChange;
} }
private static void EditPath_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index) private static void EditPathWaypoints()
{
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
if (selectedItem == editPathWaypoints)
{ {
EditWaypointMenu.BuildEditWaypointMenu(); EditWaypointMenu.BuildEditWaypointMenu();
} }
private static void DeletePath()
{
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
PathMainMenu.DeletePath(currentPath, PathMainMenu.Delete.Single);
}
private static void DisablePath()
{
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
if (disablePath.Checked)
{
currentPath.DisablePath();
Game.LogTrivial($"Path {currentPath.Number} disabled.");
}
else
{
currentPath.EnablePath();
Game.LogTrivial($"Path {currentPath.Number} enabled.");
}
}
private static void EditPath_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
{
if (selectedItem == editPathWaypoints)
{
EditPathWaypoints();
}
if (selectedItem == deletePath) if (selectedItem == deletePath)
{ {
PathMainMenu.DeletePath(currentPath, PathMainMenu.Delete.Single); DeletePath();
} }
} }
@ -49,16 +76,44 @@ namespace SceneManager
{ {
if (checkboxItem == disablePath) if (checkboxItem == disablePath)
{ {
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index]; DisablePath();
if (disablePath.Checked)
{
currentPath.DisablePath();
Logger.Log($"Path {currentPath.Number} disabled.");
} }
else }
private static void EditPath_OnMouseDown(UIMenu menu)
{ {
currentPath.EnablePath(); GameFiber.StartNew(() =>
Logger.Log($"Path {currentPath.Number} enabled."); {
while (menu.Visible)
{
// Add waypoint if menu item is selected and user left clicks
if (Game.IsKeyDown(Keys.LButton))
{
OnCheckboxItemClicked();
OnMenuItemClicked();
}
GameFiber.Yield();
}
});
void OnCheckboxItemClicked()
{
if (disablePath.Selected && disablePath.Enabled)
{
disablePath.Checked = !disablePath.Checked;
DisablePath();
}
}
void OnMenuItemClicked()
{
if (editPathWaypoints.Selected)
{
EditPathWaypoints();
}
else if (deletePath.Selected)
{
DeletePath();
} }
} }
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Windows.Forms;
using Rage; using Rage;
using RAGENativeUI; using RAGENativeUI;
using RAGENativeUI.Elements; using RAGENativeUI.Elements;
@ -16,26 +17,27 @@ namespace SceneManager
internal static UIMenuItem removeWaypoint = new UIMenuItem("Remove Waypoint"); internal static UIMenuItem removeWaypoint = new UIMenuItem("Remove Waypoint");
internal static UIMenuItem addAsNewWaypoint = new UIMenuItem("Add as New Waypoint", "Adds a new waypoint to the end of the path with these settings"); internal static UIMenuItem addAsNewWaypoint = new UIMenuItem("Add as New Waypoint", "Adds a new waypoint to the end of the path with these settings");
internal static UIMenuNumericScrollerItem<int> editWaypoint; internal static UIMenuNumericScrollerItem<int> editWaypoint;
internal static UIMenuListScrollerItem<string> changeWaypointType = new UIMenuListScrollerItem<string>("Waypoint Type", "", waypointTypes);
private static UIMenuNumericScrollerItem<int> changeWaypointSpeed; private static UIMenuNumericScrollerItem<int> changeWaypointSpeed;
internal static UIMenuCheckboxItem stopWaypointType; internal static UIMenuCheckboxItem stopWaypointType;
internal static UIMenuCheckboxItem directWaypointBehavior = new UIMenuCheckboxItem("Drive directly to waypoint?", false, "If checked, vehicles will ignore traffic rules and drive directly to this waypoint."); internal static UIMenuCheckboxItem directWaypointBehavior = new UIMenuCheckboxItem("Drive directly to waypoint?", false, "If checked, vehicles will ignore traffic rules and drive directly to this waypoint.");
internal static UIMenuCheckboxItem collectorWaypoint; internal static UIMenuCheckboxItem collectorWaypoint;
internal static UIMenuNumericScrollerItem<int> changeCollectorRadius = new UIMenuNumericScrollerItem<int>("Collection Radius", "The distance from this waypoint (in meters) vehicles will be collected", 1, 50, 1); internal static UIMenuNumericScrollerItem<int> changeCollectorRadius = new UIMenuNumericScrollerItem<int>("Collection Radius", "The distance from this waypoint (in meters) vehicles will be collected", 1, 50, 1);
internal static UIMenuNumericScrollerItem<int> changeSpeedZoneRadius = new UIMenuNumericScrollerItem<int>("Speed Zone Radius", "The distance from this collector waypoint (in meters) non-collected vehicles will drive at this waypoint's speed", 5, 200, 5); internal static UIMenuNumericScrollerItem<int> changeSpeedZoneRadius = new UIMenuNumericScrollerItem<int>("Speed Zone Radius", "The distance from this collector waypoint (in meters) non-collected vehicles will drive at this waypoint's speed", 5, 200, 5);
internal static UIMenuCheckboxItem updateWaypointPosition = new UIMenuCheckboxItem("Update Waypoint Position", false, "Updates the waypoint's position to the player's current position. You should turn this on if you're planning on adding this waypoint as a new waypoint."); internal static UIMenuCheckboxItem updateWaypointPosition = new UIMenuCheckboxItem("Update Waypoint Position", false, "Updates the waypoint's position to the player's chosen position. You should turn this on if you're planning on adding this waypoint as a new waypoint.");
internal static void InstantiateMenu() internal static void InstantiateMenu()
{ {
editWaypointMenu.ParentMenu = EditPathMenu.editPathMenu; editWaypointMenu.ParentMenu = EditPathMenu.editPathMenu;
MenuManager.menuPool.Add(editWaypointMenu); MenuManager.menuPool.Add(editWaypointMenu);
editWaypointMenu.OnScrollerChange += EditWaypoint_OnScrollerChanged;
editWaypointMenu.OnCheckboxChange += EditWaypoint_OnCheckboxChanged;
editWaypointMenu.OnItemSelect += EditWaypoint_OnItemSelected;
editWaypointMenu.OnMenuOpen += EditWaypoint_OnMouseDown;
} }
internal static void BuildEditWaypointMenu() internal static void BuildEditWaypointMenu()
{ {
// Need to unsubscribe from these or else there will be duplicate firings if the user left the menu, then re-entered
ResetEventHandlerSubscriptions();
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Value-1]; var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Value-1];
//Logger.Log($"Current path: {currentPath.Number}"); //Logger.Log($"Current path: {currentPath.Number}");
@ -85,17 +87,116 @@ namespace SceneManager
editWaypointMenu.RefreshIndex(); editWaypointMenu.RefreshIndex();
editWaypointMenu.Visible = true; editWaypointMenu.Visible = true;
} }
}
private static void UpdateWaypoint(Path currentPath, Waypoint currentWaypoint, DrivingFlagType drivingFlag)
void ResetEventHandlerSubscriptions()
{ {
editWaypointMenu.OnItemSelect -= EditWaypoint_OnItemSelected; if (currentPath.Waypoints.Count == 1)
editWaypointMenu.OnCheckboxChange -= EditWaypoint_OnCheckboxChanged; {
editWaypointMenu.OnScrollerChange -= EditWaypoint_OnScrollerChanged; currentWaypoint.UpdateWaypoint(currentWaypoint, GetMousePositionInWorld(), drivingFlag, stopWaypointType.Checked, SetDriveSpeedForWaypoint(), true, changeCollectorRadius.Value, changeSpeedZoneRadius.Value, updateWaypointPosition.Checked);
}
else
{
currentWaypoint.UpdateWaypoint(currentWaypoint, GetMousePositionInWorld(), drivingFlag, stopWaypointType.Checked, SetDriveSpeedForWaypoint(), collectorWaypoint.Checked, changeCollectorRadius.Value, changeSpeedZoneRadius.Value, updateWaypointPosition.Checked);
}
editWaypointMenu.OnScrollerChange += EditWaypoint_OnScrollerChanged; Game.LogTrivial($"Path {currentPath.Number} Waypoint {currentWaypoint.Number} updated [Driving style: {drivingFlag} | Stop waypoint: {stopWaypointType.Checked} | Speed: {changeWaypointSpeed.Value} | Collector: {currentWaypoint.IsCollector}]");
editWaypointMenu.OnCheckboxChange += EditWaypoint_OnCheckboxChanged;
editWaypointMenu.OnItemSelect += EditWaypoint_OnItemSelected; updateWaypointPosition.Checked = false;
Game.DisplayNotification($"~o~Scene Manager\n~g~[Success]~w~ Waypoint {currentWaypoint.Number} updated.");
}
private static void RemoveWaypoint(Path currentPath, Waypoint currentWaypoint, DrivingFlagType drivingFlag)
{
if (currentPath.Waypoints.Count == 1)
{
Game.LogTrivial($"Deleting the last waypoint from the path.");
PathMainMenu.DeletePath(currentPath, PathMainMenu.Delete.Single);
editWaypointMenu.Visible = false;
PathMainMenu.pathMainMenu.Visible = true;
}
else
{
currentWaypoint.Remove();
currentPath.Waypoints.Remove(currentWaypoint);
Game.LogTrivial($"[Path {currentPath.Number}] Waypoint {currentWaypoint.Number} ({currentWaypoint.DrivingFlagType}) removed");
foreach (Waypoint wp in currentPath.Waypoints)
{
wp.Number = currentPath.Waypoints.IndexOf(wp) + 1;
//Logger.Log($"Waypoint at index {currentPath.Waypoints.IndexOf(wp)} is now waypoint #{wp.Number}");
}
editWaypointMenu.Clear();
BuildEditWaypointMenu();
if (currentPath.Waypoints.Count == 1)
{
Hints.Display($"~o~Scene Manager\n~y~[Hint]~w~ Your path's first waypoint ~b~must~w~ be a collector. If it's not, it will automatically be made into one.");
Game.LogTrivial($"The path only has 1 waypoint left, this waypoint must be a collector.");
currentPath.Waypoints[0].UpdateWaypoint(currentWaypoint, GetMousePositionInWorld(), drivingFlag, stopWaypointType.Checked, SetDriveSpeedForWaypoint(), true, changeCollectorRadius.Value, changeSpeedZoneRadius.Value, updateWaypointPosition.Checked);
collectorWaypoint.Checked = true;
changeCollectorRadius.Enabled = true;
changeSpeedZoneRadius.Enabled = true;
}
}
}
private static void AddAsNewWaypoint(Path currentPath, DrivingFlagType drivingFlag)
{
var pathIndex = PathMainMenu.paths.IndexOf(currentPath);
var newWaypointBlip = CreateNewWaypointBlip();
if (!currentPath.IsEnabled)
{
newWaypointBlip.Alpha = 0.5f;
}
if (collectorWaypoint.Checked)
{
currentPath.Waypoints.Add(new Waypoint(currentPath, currentPath.Waypoints.Last().Number + 1, GetMousePositionInWorld(), SetDriveSpeedForWaypoint(), drivingFlag, stopWaypointType.Checked, newWaypointBlip, true, changeCollectorRadius.Value, changeSpeedZoneRadius.Value));
}
else
{
currentPath.Waypoints.Add(new Waypoint(currentPath, currentPath.Waypoints.Last().Number + 1, GetMousePositionInWorld(), SetDriveSpeedForWaypoint(), drivingFlag, stopWaypointType.Checked, newWaypointBlip));
}
editWaypointMenu.RemoveItemAt(0);
editWaypoint = new UIMenuNumericScrollerItem<int>("Edit Waypoint", "", currentPath.Waypoints.First().Number, currentPath.Waypoints.Last().Number, 1);
editWaypointMenu.AddItem(editWaypoint, 0);
editWaypoint.Index = editWaypoint.OptionCount - 1;
editWaypointMenu.RefreshIndex();
updateWaypointPosition.Checked = false;
Game.LogTrivial($"New waypoint (#{currentPath.Waypoints.Last().Number}) added.");
Blip CreateNewWaypointBlip()
{
var spriteNumericalEnum = pathIndex + 17; // 17 because the numerical value of these sprites are always 17 more than the path index
var blip = new Blip(GetMousePositionInWorld())
{
Scale = 0.5f,
Sprite = (BlipSprite)spriteNumericalEnum
};
if (collectorWaypoint.Checked)
{
blip.Color = Color.Blue;
}
else if (stopWaypointType.Checked)
{
blip.Color = Color.Red;
}
else
{
blip.Color = Color.Green;
}
if (!SettingsMenu.mapBlips.Checked)
{
blip.Alpha = 0f;
}
return blip;
} }
} }
@ -106,8 +207,6 @@ namespace SceneManager
if (scrollerItem == editWaypoint) if (scrollerItem == editWaypoint)
{ {
//changeWaypointType.Index = Array.IndexOf(drivingFlags, currentWaypoint.DrivingFlag);
changeWaypointSpeed.Value = (int)MathHelper.ConvertMetersPerSecondToMilesPerHour(currentWaypoint.Speed); changeWaypointSpeed.Value = (int)MathHelper.ConvertMetersPerSecondToMilesPerHour(currentWaypoint.Speed);
stopWaypointType.Checked = currentWaypoint.IsStopWaypoint; stopWaypointType.Checked = currentWaypoint.IsStopWaypoint;
directWaypointBehavior.Checked = currentWaypoint.DrivingFlagType == DrivingFlagType.Direct ? true : false; directWaypointBehavior.Checked = currentWaypoint.DrivingFlagType == DrivingFlagType.Direct ? true : false;
@ -156,117 +255,238 @@ namespace SceneManager
if (selectedItem == updateWaypoint) if (selectedItem == updateWaypoint)
{ {
if(currentPath.Waypoints.Count == 1) UpdateWaypoint(currentPath, currentWaypoint, drivingFlag);
{
currentWaypoint.UpdateWaypoint(currentWaypoint, drivingFlag, stopWaypointType.Checked, SetDriveSpeedForWaypoint(), true, changeCollectorRadius.Value, changeSpeedZoneRadius.Value, updateWaypointPosition.Checked);
}
else
{
currentWaypoint.UpdateWaypoint(currentWaypoint, drivingFlag, stopWaypointType.Checked, SetDriveSpeedForWaypoint(), collectorWaypoint.Checked, changeCollectorRadius.Value, changeSpeedZoneRadius.Value, updateWaypointPosition.Checked);
}
Logger.Log($"Path {currentPath.Number} Waypoint {currentWaypoint.Number} updated [Driving style: {drivingFlag} | Stop waypoint: {stopWaypointType.Checked} | Speed: {changeWaypointSpeed.Value} | Collector: {currentWaypoint.IsCollector}]");
updateWaypointPosition.Checked = false;
Game.DisplayNotification($"~o~Scene Manager\n~g~[Success]~w~ Waypoint {currentWaypoint.Number} updated.");
// Why am I rebuilding the menu??
//BuildEditWaypointMenu();
} }
if (selectedItem == addAsNewWaypoint) if (selectedItem == addAsNewWaypoint)
{ {
var pathIndex = PathMainMenu.paths.IndexOf(currentPath); AddAsNewWaypoint(currentPath, drivingFlag);
var newWaypointBlip = CreateNewWaypointBlip();
if (!currentPath.IsEnabled)
{
newWaypointBlip.Alpha = 0.5f;
}
if (collectorWaypoint.Checked)
{
currentPath.Waypoints.Add(new Waypoint(currentPath, currentPath.Waypoints.Last().Number + 1, Game.LocalPlayer.Character.Position, SetDriveSpeedForWaypoint(), drivingFlag, stopWaypointType.Checked, newWaypointBlip, true, changeCollectorRadius.Value, changeSpeedZoneRadius.Value));
}
else
{
currentPath.Waypoints.Add(new Waypoint(currentPath, currentPath.Waypoints.Last().Number + 1, Game.LocalPlayer.Character.Position, SetDriveSpeedForWaypoint(), drivingFlag, stopWaypointType.Checked, newWaypointBlip));
}
editWaypointMenu.RemoveItemAt(0);
editWaypoint = new UIMenuNumericScrollerItem<int>("Edit Waypoint", "", currentPath.Waypoints.First().Number, currentPath.Waypoints.Last().Number, 1);
editWaypointMenu.AddItem(editWaypoint, 0);
editWaypoint.Index = editWaypoint.OptionCount - 1;
editWaypointMenu.RefreshIndex();
updateWaypointPosition.Checked = false;
Logger.Log($"New waypoint (#{currentPath.Waypoints.Last().Number}) added.");
Blip CreateNewWaypointBlip()
{
var spriteNumericalEnum = pathIndex + 17; // 17 because the numerical value of these sprites are always 17 more than the path index
var blip = new Blip(Game.LocalPlayer.Character.Position)
{
Scale = 0.5f,
Sprite = (BlipSprite)spriteNumericalEnum
};
if (collectorWaypoint.Checked)
{
blip.Color = Color.Blue;
}
else if (stopWaypointType.Checked)
{
blip.Color = Color.Red;
}
else
{
blip.Color = Color.Green;
}
if (!SettingsMenu.mapBlips.Checked)
{
blip.Alpha = 0f;
}
return blip;
}
} }
if (selectedItem == removeWaypoint) if (selectedItem == removeWaypoint)
{ {
if (currentPath.Waypoints.Count == 1) RemoveWaypoint(currentPath, currentWaypoint, drivingFlag);
{ }
Logger.Log($"Deleting the last waypoint from the path."); }
PathMainMenu.DeletePath(currentPath, PathMainMenu.Delete.Single);
editWaypointMenu.Visible = false; private static void EditWaypoint_OnMouseDown(UIMenu menu)
PathMainMenu.pathMainMenu.Visible = true; {
GameFiber.StartNew(() =>
{
while (menu.Visible)
{
var selectedScroller = menu.MenuItems.Where(x => (x == editWaypoint || x == changeWaypointSpeed || x == changeCollectorRadius || x == changeSpeedZoneRadius) && x.Selected).FirstOrDefault();
if (selectedScroller != null)
{
HandleScrollerItemsWithMouseWheel(selectedScroller);
}
if (Game.IsKeyDown(Keys.LButton))
{
OnCheckboxItemClicked();
OnMenuItemClicked();
}
GameFiber.Yield();
}
});
void OnCheckboxItemClicked()
{
if (collectorWaypoint.Selected && collectorWaypoint.Enabled)
{
collectorWaypoint.Checked = !collectorWaypoint.Checked;
}
else if (stopWaypointType.Selected)
{
stopWaypointType.Checked = !stopWaypointType.Checked;
}
else if (directWaypointBehavior.Selected)
{
directWaypointBehavior.Checked = !directWaypointBehavior.Checked;
}
else if (updateWaypointPosition.Selected)
{
updateWaypointPosition.Checked = !updateWaypointPosition.Checked;
if (updateWaypointPosition.Checked)
{
DrawWaypointMarker(GetMousePositionInWorld());
}
}
}
void OnMenuItemClicked()
{
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
var currentWaypoint = currentPath.Waypoints[editWaypoint.Index];
DrivingFlagType drivingFlag = directWaypointBehavior.Checked ? DrivingFlagType.Direct : DrivingFlagType.Normal;
if (updateWaypoint.Selected)
{
UpdateWaypoint(currentPath, currentWaypoint, drivingFlag);
}
else if (removeWaypoint.Selected)
{
RemoveWaypoint(currentPath, currentWaypoint, drivingFlag);
}
else if (addAsNewWaypoint.Selected)
{
AddAsNewWaypoint(currentPath, drivingFlag);
}
}
void HandleScrollerItemsWithMouseWheel(UIMenuItem selectedScroller)
{
var menuScrollingDisabled = false;
var menuItems = menu.MenuItems.Where(x => x != selectedScroller);
while (Game.IsShiftKeyDownRightNow)
{
menu.ResetKey(Common.MenuControls.Up);
menu.ResetKey(Common.MenuControls.Down);
menuScrollingDisabled = true;
ScrollMenuItem();
CompareScrollerValues();
GameFiber.Yield();
}
if (menuScrollingDisabled)
{
menuScrollingDisabled = false;
menu.SetKey(Common.MenuControls.Up, GameControl.CursorScrollUp);
menu.SetKey(Common.MenuControls.Up, GameControl.CellphoneUp);
menu.SetKey(Common.MenuControls.Down, GameControl.CursorScrollDown);
menu.SetKey(Common.MenuControls.Down, GameControl.CellphoneDown);
}
void ScrollMenuItem()
{
if (Game.GetMouseWheelDelta() > 0)
{
if (selectedScroller == changeCollectorRadius)
{
changeCollectorRadius.ScrollToNextOption();
}
else if (selectedScroller == changeSpeedZoneRadius)
{
changeSpeedZoneRadius.ScrollToNextOption();
}
else if (selectedScroller == changeWaypointSpeed)
{
changeWaypointSpeed.ScrollToNextOption();
}
else if(selectedScroller == editWaypoint)
{
editWaypoint.ScrollToNextOption();
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
var currentWaypoint = currentPath.Waypoints[editWaypoint.Value - 1];
changeWaypointSpeed.Value = (int)MathHelper.ConvertMetersPerSecondToMilesPerHour(currentWaypoint.Speed);
stopWaypointType.Checked = currentWaypoint.IsStopWaypoint;
directWaypointBehavior.Checked = currentWaypoint.DrivingFlagType == DrivingFlagType.Direct ? true : false;
collectorWaypoint.Checked = currentWaypoint.IsCollector;
changeCollectorRadius.Enabled = collectorWaypoint.Checked ? true : false;
changeCollectorRadius.Value = (int)currentWaypoint.CollectorRadius;
changeSpeedZoneRadius.Enabled = collectorWaypoint.Checked ? true : false;
changeSpeedZoneRadius.Value = (int)currentWaypoint.SpeedZoneRadius;
updateWaypointPosition.Checked = false;
}
}
else if (Game.GetMouseWheelDelta() < 0)
{
if (selectedScroller == changeCollectorRadius)
{
changeCollectorRadius.ScrollToPreviousOption();
}
else if (selectedScroller == changeSpeedZoneRadius)
{
changeSpeedZoneRadius.ScrollToPreviousOption();
}
else if (selectedScroller == changeWaypointSpeed)
{
changeWaypointSpeed.ScrollToPreviousOption();
}
else if (selectedScroller == editWaypoint)
{
editWaypoint.ScrollToPreviousOption();
var currentPath = PathMainMenu.paths[PathMainMenu.editPath.Index];
var currentWaypoint = currentPath.Waypoints[editWaypoint.Value - 1];
changeWaypointSpeed.Value = (int)MathHelper.ConvertMetersPerSecondToMilesPerHour(currentWaypoint.Speed);
stopWaypointType.Checked = currentWaypoint.IsStopWaypoint;
directWaypointBehavior.Checked = currentWaypoint.DrivingFlagType == DrivingFlagType.Direct ? true : false;
collectorWaypoint.Checked = currentWaypoint.IsCollector;
changeCollectorRadius.Enabled = collectorWaypoint.Checked ? true : false;
changeCollectorRadius.Value = (int)currentWaypoint.CollectorRadius;
changeSpeedZoneRadius.Enabled = collectorWaypoint.Checked ? true : false;
changeSpeedZoneRadius.Value = (int)currentWaypoint.SpeedZoneRadius;
updateWaypointPosition.Checked = false;
}
}
}
void CompareScrollerValues()
{
if (selectedScroller == changeCollectorRadius && changeCollectorRadius.Value > changeSpeedZoneRadius.Value)
{
while (changeCollectorRadius.Value > changeSpeedZoneRadius.Value)
{
changeSpeedZoneRadius.ScrollToNextOption();
}
}
if (selectedScroller == changeSpeedZoneRadius && changeSpeedZoneRadius.Value < changeCollectorRadius.Value)
{
changeCollectorRadius.Value = changeSpeedZoneRadius.Value;
}
}
}
}
private static void DrawWaypointMarker(Vector3 waypointPosition)
{
if (SettingsMenu.threeDWaypoints.Checked && collectorWaypoint.Checked)
{
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, (float)PathCreationMenu.collectorRadius.Value * 2, (float)PathCreationMenu.collectorRadius.Value * 2, 1f, 80, 130, 255, 80, false, false, 2, false, 0, 0, false);
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, (float)PathCreationMenu.speedZoneRadius.Value * 2, (float)PathCreationMenu.speedZoneRadius.Value * 2, 1f, 255, 185, 80, 80, false, false, 2, false, 0, 0, false);
}
else if (stopWaypointType.Checked)
{
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 255, 65, 65, 80, false, false, 2, false, 0, 0, false);
} }
else else
{ {
currentWaypoint.Remove(); Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 65, 255, 65, 80, false, false, 2, false, 0, 0, false);
currentPath.Waypoints.Remove(currentWaypoint); }
Logger.Log($"[Path {currentPath.Number}] Waypoint {currentWaypoint.Number} ({currentWaypoint.DrivingFlagType}) removed"); }
foreach (Waypoint wp in currentPath.Waypoints) private static Vector3 GetMousePositionInWorld()
{ {
wp.Number = currentPath.Waypoints.IndexOf(wp) + 1; HitResult TracePlayerView(float maxTraceDistance = 100f, TraceFlags flags = TraceFlags.IntersectWorld) => TracePlayerView2(out Vector3 v1, out Vector3 v2, maxTraceDistance, flags);
//Logger.Log($"Waypoint at index {currentPath.Waypoints.IndexOf(wp)} is now waypoint #{wp.Number}");
}
editWaypointMenu.Clear(); HitResult TracePlayerView2(out Vector3 start, out Vector3 end, float maxTraceDistance, TraceFlags flags)
BuildEditWaypointMenu();
if (currentPath.Waypoints.Count == 1)
{ {
Hints.Display($"~o~Scene Manager\n~y~[Hint]~w~ Your path's first waypoint ~b~must~w~ be a collector. If it's not, it will automatically be made into one."); Vector3 direction = GetPlayerLookingDirection(out start);
Logger.Log($"The path only has 1 waypoint left, this waypoint must be a collector."); end = start + (maxTraceDistance * direction);
currentPath.Waypoints[0].UpdateWaypoint(currentWaypoint, drivingFlag, stopWaypointType.Checked, SetDriveSpeedForWaypoint(), true, changeCollectorRadius.Value, changeSpeedZoneRadius.Value, updateWaypointPosition.Checked); return World.TraceLine(start, end, flags);
collectorWaypoint.Checked = true; }
changeCollectorRadius.Enabled = true;
changeSpeedZoneRadius.Enabled = true; Vector3 GetPlayerLookingDirection(out Vector3 camPosition)
} {
if (Camera.RenderingCamera)
{
camPosition = Camera.RenderingCamera.Position;
return Camera.RenderingCamera.Direction;
}
else
{
float pitch = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_RELATIVE_PITCH<float>();
float heading = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_RELATIVE_HEADING<float>();
camPosition = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_COORD<Vector3>();
return (Game.LocalPlayer.Character.Rotation + new Rotator(pitch, 0, heading)).ToVector().ToNormalized();
} }
} }
return TracePlayerView(100f, TraceFlags.IntersectWorld).HitPosition;
} }
private static float SetDriveSpeedForWaypoint() private static float SetDriveSpeedForWaypoint()

View file

@ -1,6 +1,9 @@
using RAGENativeUI; using Rage;
using RAGENativeUI;
using RAGENativeUI.Elements; using RAGENativeUI.Elements;
using System.Drawing; using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace SceneManager namespace SceneManager
{ {
@ -29,6 +32,7 @@ namespace SceneManager
mainMenu.RefreshIndex(); mainMenu.RefreshIndex();
mainMenu.OnItemSelect += MainMenu_OnItemSelected; mainMenu.OnItemSelect += MainMenu_OnItemSelected;
mainMenu.OnMenuOpen += MainMenu_OnMouseDown;
} }
private static void MainMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index) private static void MainMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
@ -38,5 +42,38 @@ namespace SceneManager
BarrierMenu.CreateShadowBarrier(BarrierMenu.barrierMenu); BarrierMenu.CreateShadowBarrier(BarrierMenu.barrierMenu);
} }
} }
private static void MainMenu_OnMouseDown(UIMenu menu)
{
GameFiber.StartNew(() =>
{
while (menu.Visible)
{
if (Game.IsKeyDown(Keys.LButton))
{
menu.Visible = false;
OnMenuItemClicked();
}
GameFiber.Yield();
}
});
void OnMenuItemClicked()
{
if (navigateToPathMenu.Selected)
{
PathMainMenu.pathMainMenu.Visible = true;
}
else if (navigateToBarrierMenu.Selected)
{
BarrierMenu.barrierMenu.Visible = true;
BarrierMenu.CreateShadowBarrier(BarrierMenu.barrierMenu);
}
else if (navigateToSettingsMenu.Selected)
{
SettingsMenu.settingsMenu.Visible = true;
}
}
}
} }
} }

View file

@ -34,7 +34,6 @@ namespace SceneManager
MainMenu.BuildMainMenu(); MainMenu.BuildMainMenu();
SettingsMenu.BuildSettingsMenu(); SettingsMenu.BuildSettingsMenu();
PathMainMenu.BuildPathMenu(); PathMainMenu.BuildPathMenu();
PathCreationMenu.BuildPathCreationMenu();
EditPathMenu.BuildEditPathMenu(); EditPathMenu.BuildEditPathMenu();
BarrierMenu.BuildBarrierMenu(); BarrierMenu.BuildBarrierMenu();
} }

View file

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Windows.Forms;
using Rage; using Rage;
using RAGENativeUI; using RAGENativeUI;
using RAGENativeUI.Elements; using RAGENativeUI.Elements;
@ -10,22 +11,24 @@ namespace SceneManager
{ {
class PathCreationMenu class PathCreationMenu
{ {
private static VehicleDrivingFlags[] drivingFlags = new VehicleDrivingFlags[] { VehicleDrivingFlags.Normal, VehicleDrivingFlags.IgnorePathFinding, VehicleDrivingFlags.StopAtDestination }; // Implement custom driving flag for normal
private static string[] waypointTypes = new string[] { "Drive To (Normal)", "Drive To (Direct)", "Stop" };
internal static UIMenu pathCreationMenu = new UIMenu("Scene Manager", "~o~Path Creation Menu"); internal static UIMenu pathCreationMenu = new UIMenu("Scene Manager", "~o~Path Creation Menu");
private static UIMenuItem trafficAddWaypoint = new UIMenuItem("Add waypoint"), trafficRemoveWaypoint = new UIMenuItem("Remove last waypoint"), trafficEndPath = new UIMenuItem("End path creation"); private static UIMenuItem trafficAddWaypoint = new UIMenuItem("Add waypoint"), trafficRemoveWaypoint = new UIMenuItem("Remove last waypoint"), trafficEndPath = new UIMenuItem("End path creation");
internal static UIMenuListScrollerItem<string> waypointType = new UIMenuListScrollerItem<string>("Waypoint Type", $"~b~Drive To (Normal): ~w~AI obeys traffic as much as possible{Environment.NewLine}~b~Drive To (Direct): ~w~AI ignores pathfinding rules{Environment.NewLine}~b~Stop: ~w~AI stops at the waypoint until dismissed", waypointTypes); internal static UIMenuNumericScrollerItem<int> waypointSpeed;
private static UIMenuNumericScrollerItem<int> waypointSpeed;
internal static UIMenuCheckboxItem stopWaypointType = new UIMenuCheckboxItem("Is this a Stop waypoint?", false, "If checked, vehicles will drive to this waypoint, then stop."); internal static UIMenuCheckboxItem stopWaypointType = new UIMenuCheckboxItem("Is this a Stop waypoint?", false, "If checked, vehicles will drive to this waypoint, then stop.");
internal static UIMenuCheckboxItem directWaypointBehavior = new UIMenuCheckboxItem("Drive directly to waypoint?", false, "If checked, vehicles will ignore traffic rules and drive directly to this waypoint."); internal static UIMenuCheckboxItem directWaypointBehavior = new UIMenuCheckboxItem("Drive directly to waypoint?", false, "If checked, vehicles will ignore traffic rules and drive directly to this waypoint.");
internal static UIMenuCheckboxItem collectorWaypoint = new UIMenuCheckboxItem("Collector", true, "If checked, this waypoint will collect vehicles to follow the path. Your path's first waypoint ~b~must~w~ be a collector."); internal static UIMenuCheckboxItem collectorWaypoint = new UIMenuCheckboxItem("Collector", true, "If checked, this waypoint will collect vehicles to follow the path. Your path's first waypoint ~b~must~w~ be a collector.");
internal static UIMenuNumericScrollerItem<int> collectorRadius = new UIMenuNumericScrollerItem<int>("Collection Radius", "The distance from this waypoint (in meters) vehicles will be collected", 1, 50, 1); internal static UIMenuNumericScrollerItem<int> collectorRadius = new UIMenuNumericScrollerItem<int>("Collection Radius", "The distance from this waypoint (in meters) vehicles will be collected", 1, 50, 1);
internal static UIMenuNumericScrollerItem<int> speedZoneRadius = new UIMenuNumericScrollerItem<int>("Speed Zone Radius", "The distance from this collector waypoint (in meters) non-collected vehicles will drive at this waypoint's speed", 5, 200, 5); internal static UIMenuNumericScrollerItem<int> speedZoneRadius = new UIMenuNumericScrollerItem<int>("Speed Zone Radius", "The distance from this collector waypoint (in meters) non-collected vehicles will drive at this waypoint's speed", 5, 200, 5);
private static List<UIMenuItem> menuItems = new List<UIMenuItem> {collectorWaypoint, collectorRadius, speedZoneRadius, stopWaypointType, directWaypointBehavior, waypointSpeed, trafficAddWaypoint, trafficRemoveWaypoint, trafficEndPath };
internal static void InstantiateMenu() internal static void InstantiateMenu()
{ {
pathCreationMenu.ParentMenu = PathMainMenu.pathMainMenu; pathCreationMenu.ParentMenu = PathMainMenu.pathMainMenu;
MenuManager.menuPool.Add(pathCreationMenu); MenuManager.menuPool.Add(pathCreationMenu);
pathCreationMenu.OnItemSelect += PathCreation_OnItemSelected;
pathCreationMenu.OnCheckboxChange += PathCreation_OnCheckboxChanged;
pathCreationMenu.OnScrollerChange += PathCreation_OnScrollerChanged;
pathCreationMenu.OnMenuOpen += PathCreation_OnMouseDown;
} }
internal static void BuildPathCreationMenu() internal static void BuildPathCreationMenu()
@ -35,18 +38,20 @@ namespace SceneManager
collectorWaypoint.Checked = true; collectorWaypoint.Checked = true;
pathCreationMenu.AddItem(collectorRadius); pathCreationMenu.AddItem(collectorRadius);
collectorRadius.Index = 0; collectorRadius.Index = Settings.CollectorRadius - 1;
collectorRadius.Enabled = true; collectorRadius.Enabled = true;
pathCreationMenu.AddItem(speedZoneRadius); pathCreationMenu.AddItem(speedZoneRadius);
speedZoneRadius.Index = 0; speedZoneRadius.Index = (Settings.SpeedZoneRadius / 5) - 1;
speedZoneRadius.Enabled = true; speedZoneRadius.Enabled = true;
pathCreationMenu.AddItem(stopWaypointType); pathCreationMenu.AddItem(stopWaypointType);
stopWaypointType.Checked = Settings.StopWaypoint;
pathCreationMenu.AddItem(directWaypointBehavior); pathCreationMenu.AddItem(directWaypointBehavior);
directWaypointBehavior.Checked = Settings.DirectDrivingBehavior;
pathCreationMenu.AddItem(waypointSpeed = new UIMenuNumericScrollerItem<int>("Waypoint Speed", $"How fast the AI will drive to this waypoint in ~b~{SettingsMenu.speedUnits.SelectedItem}", 5, 100, 5)); pathCreationMenu.AddItem(waypointSpeed = new UIMenuNumericScrollerItem<int>("Waypoint Speed", $"How fast the AI will drive to this waypoint in ~b~{SettingsMenu.speedUnits.SelectedItem}", 5, 100, 5));
waypointSpeed.Index = 0; waypointSpeed.Index = (Settings.WaypointSpeed / 5) - 1;
pathCreationMenu.AddItem(trafficAddWaypoint); pathCreationMenu.AddItem(trafficAddWaypoint);
trafficAddWaypoint.ForeColor = Color.Gold; trafficAddWaypoint.ForeColor = Color.Gold;
@ -60,9 +65,6 @@ namespace SceneManager
trafficEndPath.Enabled = false; trafficEndPath.Enabled = false;
pathCreationMenu.RefreshIndex(); pathCreationMenu.RefreshIndex();
pathCreationMenu.OnItemSelect += PathCreation_OnItemSelected;
pathCreationMenu.OnCheckboxChange += PathCreation_OnCheckboxChanged;
pathCreationMenu.OnScrollerChange += PathCreation_OnScrollerChanged;
} }
private static void PathCreation_OnCheckboxChanged(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked) private static void PathCreation_OnCheckboxChanged(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked)
@ -77,6 +79,176 @@ namespace SceneManager
private static void PathCreation_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index) private static void PathCreation_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
{ {
if (selectedItem == trafficAddWaypoint) if (selectedItem == trafficAddWaypoint)
{
AddNewWaypoint(GetMousePositionInWorld());
}
if (selectedItem == trafficRemoveWaypoint)
{
RemoveWaypoint();
}
if (selectedItem == trafficEndPath)
{
EndPath();
}
}
private static void PathCreation_OnScrollerChanged(UIMenu sender, UIMenuScrollerItem scrollerItem, int first, int last)
{
if (scrollerItem == collectorRadius)
{
if (collectorRadius.Value > speedZoneRadius.Value)
{
while (collectorRadius.Value > speedZoneRadius.Value)
{
speedZoneRadius.ScrollToNextOption();
}
}
}
if (scrollerItem == speedZoneRadius)
{
if (speedZoneRadius.Value < collectorRadius.Value)
{
collectorRadius.Value = speedZoneRadius.Value;
}
}
}
private static void PathCreation_OnMouseDown(UIMenu menu)
{
GameFiber.StartNew(() =>
{
while (menu.Visible)
{
var selectedScroller = menu.MenuItems.Where(x => (x == collectorRadius || x == speedZoneRadius || x == waypointSpeed) && x.Selected).FirstOrDefault();
if (selectedScroller != null)
{
HandleScrollerItemsWithMouseWheel(selectedScroller);
}
// Draw marker at mouse position
DrawWaypointMarker(GetMousePositionInWorld());
// Add waypoint if menu item is selected and user left clicks
if (Game.IsKeyDown(Keys.LButton))
{
OnCheckboxItemClicked();
OnMenuItemClicked();
}
GameFiber.Yield();
}
});
void OnCheckboxItemClicked()
{
if (collectorWaypoint.Selected && collectorWaypoint.Enabled)
{
collectorWaypoint.Checked = !collectorWaypoint.Checked;
}
else if (stopWaypointType.Selected)
{
stopWaypointType.Checked = !stopWaypointType.Checked;
}
else if (directWaypointBehavior.Selected)
{
directWaypointBehavior.Checked = !directWaypointBehavior.Checked;
}
}
void OnMenuItemClicked()
{
if (trafficAddWaypoint.Selected)
{
AddNewWaypoint(GetMousePositionInWorld());
}
else if (trafficRemoveWaypoint.Selected)
{
RemoveWaypoint();
}
else if (trafficEndPath.Selected)
{
EndPath();
}
}
void HandleScrollerItemsWithMouseWheel(UIMenuItem selectedScroller)
{
var menuScrollingDisabled = false;
var menuItems = menu.MenuItems.Where(x => x != selectedScroller);
while (Game.IsShiftKeyDownRightNow)
{
menu.ResetKey(Common.MenuControls.Up);
menu.ResetKey(Common.MenuControls.Down);
menuScrollingDisabled = true;
ScrollMenuItem();
CompareScrollerValues();
DrawWaypointMarker(GetMousePositionInWorld());
GameFiber.Yield();
}
if (menuScrollingDisabled)
{
menuScrollingDisabled = false;
menu.SetKey(Common.MenuControls.Up, GameControl.CursorScrollUp);
menu.SetKey(Common.MenuControls.Up, GameControl.CellphoneUp);
menu.SetKey(Common.MenuControls.Down, GameControl.CursorScrollDown);
menu.SetKey(Common.MenuControls.Down, GameControl.CellphoneDown);
}
void ScrollMenuItem()
{
if (Game.GetMouseWheelDelta() > 0)
{
if (selectedScroller == collectorRadius)
{
collectorRadius.ScrollToNextOption();
}
else if (selectedScroller == speedZoneRadius)
{
speedZoneRadius.ScrollToNextOption();
}
else if (selectedScroller == waypointSpeed)
{
waypointSpeed.ScrollToNextOption();
}
}
else if (Game.GetMouseWheelDelta() < 0)
{
if (selectedScroller == collectorRadius)
{
collectorRadius.ScrollToPreviousOption();
}
else if (selectedScroller == speedZoneRadius)
{
speedZoneRadius.ScrollToPreviousOption();
}
else if (selectedScroller == waypointSpeed)
{
waypointSpeed.ScrollToPreviousOption();
}
}
}
void CompareScrollerValues()
{
if (selectedScroller == collectorRadius && collectorRadius.Value > speedZoneRadius.Value)
{
while (collectorRadius.Value > speedZoneRadius.Value)
{
speedZoneRadius.ScrollToNextOption();
}
}
if (selectedScroller == speedZoneRadius && speedZoneRadius.Value < collectorRadius.Value)
{
collectorRadius.Value = speedZoneRadius.Value;
}
}
}
}
private static void AddNewWaypoint(Vector3 waypointPosition)
{ {
var anyPathsExist = PathMainMenu.paths.Count > 0; var anyPathsExist = PathMainMenu.paths.Count > 0;
@ -84,7 +256,7 @@ namespace SceneManager
{ {
AddNewPathToPathsCollection(PathMainMenu.paths, 0); AddNewPathToPathsCollection(PathMainMenu.paths, 0);
} }
else if(anyPathsExist && !PathMainMenu.paths.Any(p => p != null && p.State == State.Creating)) else if (anyPathsExist && !PathMainMenu.paths.Any(p => p != null && p.State == State.Creating))
{ {
AddNewPathToPathsCollection(PathMainMenu.paths, PathMainMenu.paths.IndexOf(PathMainMenu.paths.Where(p => p.State == State.Finished).Last()) + 1); AddNewPathToPathsCollection(PathMainMenu.paths, PathMainMenu.paths.IndexOf(PathMainMenu.paths.Where(p => p.State == State.Finished).Last()) + 1);
} }
@ -97,13 +269,13 @@ namespace SceneManager
if (collectorWaypoint.Checked) if (collectorWaypoint.Checked)
{ {
PathMainMenu.paths[pathIndex].Waypoints.Add(new Waypoint(firstNonNullPath, waypointNumber, Game.LocalPlayer.Character.Position, SetDriveSpeedForWaypoint(), drivingFlag, stopWaypointType.Checked, CreateWaypointBlip(), true, collectorRadius.Value, speedZoneRadius.Value)); PathMainMenu.paths[pathIndex].Waypoints.Add(new Waypoint(firstNonNullPath, waypointNumber, waypointPosition, SetDriveSpeedForWaypoint(), drivingFlag, stopWaypointType.Checked, CreateWaypointBlip(), true, collectorRadius.Value, speedZoneRadius.Value));
} }
else else
{ {
PathMainMenu.paths[pathIndex].Waypoints.Add(new Waypoint(firstNonNullPath, waypointNumber, Game.LocalPlayer.Character.Position, SetDriveSpeedForWaypoint(), drivingFlag, stopWaypointType.Checked, CreateWaypointBlip())); PathMainMenu.paths[pathIndex].Waypoints.Add(new Waypoint(firstNonNullPath, waypointNumber, waypointPosition, SetDriveSpeedForWaypoint(), drivingFlag, stopWaypointType.Checked, CreateWaypointBlip()));
} }
Logger.Log($"Path {pathNumber} Waypoint {waypointNumber} added [Driving style: {drivingFlag} | Stop waypoint: {stopWaypointType.Checked} | Speed: {waypointSpeed.Value} | Collector: {collectorWaypoint.Checked}]"); Game.LogTrivial($"Path {pathNumber} Waypoint {waypointNumber} added [Driving style: {drivingFlag} | Stop waypoint: {stopWaypointType.Checked} | Speed: {waypointSpeed.Value} | Collector: {collectorWaypoint.Checked}]");
ToggleTrafficEndPathMenuItem(pathIndex); ToggleTrafficEndPathMenuItem(pathIndex);
collectorWaypoint.Enabled = true; collectorWaypoint.Enabled = true;
@ -133,7 +305,7 @@ namespace SceneManager
Blip CreateWaypointBlip() Blip CreateWaypointBlip()
{ {
var spriteNumericalEnum = pathIndex + 17; // 17 because the numerical value of these sprites are always 17 more than the path index var spriteNumericalEnum = pathIndex + 17; // 17 because the numerical value of these sprites are always 17 more than the path index
var blip = new Blip(Game.LocalPlayer.Character.Position) var blip = new Blip(waypointPosition)
{ {
Scale = 0.5f, Scale = 0.5f,
Sprite = (BlipSprite)spriteNumericalEnum Sprite = (BlipSprite)spriteNumericalEnum
@ -161,14 +333,13 @@ namespace SceneManager
} }
} }
if (selectedItem == trafficRemoveWaypoint) private static void RemoveWaypoint()
{ {
// 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 < PathMainMenu.paths.Count; i++) for (int i = 0; i < PathMainMenu.paths.Count; i++)
{ {
if (PathMainMenu.paths.ElementAtOrDefault(i) != null && PathMainMenu.paths[i].State == State.Creating) if (PathMainMenu.paths.ElementAtOrDefault(i) != null && PathMainMenu.paths[i].State == State.Creating)
{ {
Logger.Log($"[Path {i + 1}] {PathMainMenu.paths[i].Waypoints.Last().DrivingFlagType} waypoint removed"); Game.LogTrivial($"[Path {i + 1}] {PathMainMenu.paths[i].Waypoints.Last().DrivingFlagType} waypoint removed");
PathMainMenu.paths[i].Waypoints.Last().Blip.Delete(); PathMainMenu.paths[i].Waypoints.Last().Blip.Delete();
PathMainMenu.paths[i].Waypoints.Last().RemoveSpeedZone(); PathMainMenu.paths[i].Waypoints.Last().RemoveSpeedZone();
@ -194,16 +365,15 @@ namespace SceneManager
} }
} }
if (selectedItem == trafficEndPath) private static void EndPath()
{ {
// Loop through each path and find the first one which isn't finished
for (int i = 0; i < PathMainMenu.paths.Count; i++) for (int i = 0; i < PathMainMenu.paths.Count; i++)
{ {
var currentPath = PathMainMenu.paths[i]; var currentPath = PathMainMenu.paths[i];
if (PathMainMenu.paths.ElementAtOrDefault(i) != null && currentPath.State == State.Creating) if (PathMainMenu.paths.ElementAtOrDefault(i) != null && currentPath.State == State.Creating)
{ {
Logger.Log($"[Path Creation] Path {currentPath.Number} finished with {currentPath.Waypoints.Count} waypoints."); Game.LogTrivial($"[Path Creation] Path {currentPath.Number} finished with {currentPath.Waypoints.Count} waypoints.");
Game.DisplayNotification($"~o~Scene Manager\n~g~[Success]~w~ Path {i + 1} complete."); Game.DisplayNotification($"~o~Scene Manager ~g~[Success]\n~w~Path {i + 1} complete.");
currentPath.State = State.Finished; currentPath.State = State.Finished;
currentPath.IsEnabled = true; currentPath.IsEnabled = true;
currentPath.Number = i + 1; currentPath.Number = i + 1;
@ -212,57 +382,17 @@ namespace SceneManager
GameFiber.StartNew(() => GameFiber.StartNew(() =>
{ {
currentPath.LoopWaypointCollection(); currentPath.LoopWaypointCollection();
//foreach(Waypoint waypoint in PathMainMenu.paths[i].Waypoints)
//{
// GameFiber WaypointVehicleCollectorFiber = new GameFiber(() => waypoint.CollectVehicles(PathMainMenu.paths));
// WaypointVehicleCollectorFiber.Start();
// GameFiber.Sleep(1000);
//}
}); });
PathMainMenu.createNewPath.Text = "Create New Path"; PathMainMenu.createNewPath.Text = "Create New Path";
PathMainMenu.BuildPathMenu(); PathMainMenu.BuildPathMenu();
PathMainMenu.pathMainMenu.RefreshIndex(); PathMainMenu.pathMainMenu.RefreshIndex();
pathCreationMenu.RefreshIndex(); pathCreationMenu.Clear();
waypointSpeed.Index = 0;
collectorWaypoint.Enabled = false;
collectorWaypoint.Checked = true;
speedZoneRadius.Enabled = true;
speedZoneRadius.Index = 0;
collectorRadius.Enabled = true;
collectorRadius.Index = 0;
stopWaypointType.Checked = false;
directWaypointBehavior.Checked = false;
trafficEndPath.Enabled = false;
PathMainMenu.pathMainMenu.Visible = true; PathMainMenu.pathMainMenu.Visible = true;
break; break;
} }
} }
} }
}
private static void PathCreation_OnScrollerChanged(UIMenu sender, UIMenuScrollerItem scrollerItem, int first, int last)
{
if (scrollerItem == collectorRadius)
{
if (collectorRadius.Value > speedZoneRadius.Value)
{
while(collectorRadius.Value > speedZoneRadius.Value)
{
speedZoneRadius.ScrollToNextOption();
}
}
}
if(scrollerItem == speedZoneRadius)
{
if(speedZoneRadius.Value < collectorRadius.Value)
{
collectorRadius.Value = speedZoneRadius.Value;
}
}
}
private static void ToggleTrafficEndPathMenuItem(int pathIndex) private static void ToggleTrafficEndPathMenuItem(int pathIndex)
{ {
@ -279,11 +409,59 @@ namespace SceneManager
internal static void AddNewPathToPathsCollection(List<Path> paths, int pathIndex) internal static void AddNewPathToPathsCollection(List<Path> paths, int pathIndex)
{ {
var pathNum = pathIndex + 1; var pathNum = pathIndex + 1;
Logger.Log($"Creating path {pathNum}"); Game.LogTrivial($"Creating path {pathNum}");
Game.DisplayNotification($"~o~Scene Manager\n~y~[Creating]~w~ Path {pathNum} started."); Game.DisplayNotification($"~o~Scene Manager\n~y~[Creating]~w~ Path {pathNum} started.");
paths.Insert(pathIndex, new Path(pathNum, State.Creating)); paths.Insert(pathIndex, new Path(pathNum, State.Creating));
trafficRemoveWaypoint.Enabled = false; trafficRemoveWaypoint.Enabled = false;
trafficEndPath.Enabled = false; trafficEndPath.Enabled = false;
} }
private static void DrawWaypointMarker(Vector3 waypointPosition)
{
if (SettingsMenu.threeDWaypoints.Checked && collectorWaypoint.Checked)
{
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, (float)PathCreationMenu.collectorRadius.Value * 2, (float)PathCreationMenu.collectorRadius.Value * 2, 1f, 80, 130, 255, 80, false, false, 2, false, 0, 0, false);
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, (float)PathCreationMenu.speedZoneRadius.Value * 2, (float)PathCreationMenu.speedZoneRadius.Value * 2, 1f, 255, 185, 80, 80, false, false, 2, false, 0, 0, false);
}
else if (stopWaypointType.Checked)
{
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 255, 65, 65, 80, false, false, 2, false, 0, 0, false);
}
else
{
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, waypointPosition, 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 65, 255, 65, 80, false, false, 2, false, 0, 0, false);
}
}
private static Vector3 GetMousePositionInWorld()
{
HitResult TracePlayerView(float maxTraceDistance = 100f, TraceFlags flags = TraceFlags.IntersectWorld) => TracePlayerView2(out Vector3 v1, out Vector3 v2, maxTraceDistance, flags);
HitResult TracePlayerView2(out Vector3 start, out Vector3 end, float maxTraceDistance, TraceFlags flags)
{
Vector3 direction = GetPlayerLookingDirection(out start);
end = start + (maxTraceDistance * direction);
return World.TraceLine(start, end, flags);
}
Vector3 GetPlayerLookingDirection(out Vector3 camPosition)
{
if (Camera.RenderingCamera)
{
camPosition = Camera.RenderingCamera.Position;
return Camera.RenderingCamera.Direction;
}
else
{
float pitch = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_RELATIVE_PITCH<float>();
float heading = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_RELATIVE_HEADING<float>();
camPosition = Rage.Native.NativeFunction.Natives.GET_GAMEPLAY_CAM_COORD<Vector3>();
return (Game.LocalPlayer.Character.Rotation + new Rotator(pitch, 0, heading)).ToVector().ToNormalized();
}
}
return TracePlayerView(100f, TraceFlags.IntersectWorld).HitPosition;
}
} }
} }

View file

@ -2,25 +2,20 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Windows.Forms;
using Rage; using Rage;
using RAGENativeUI; using RAGENativeUI;
using RAGENativeUI.Elements; using RAGENativeUI.Elements;
namespace SceneManager namespace SceneManager
{ {
public enum DismissOption
{
FromPath = 0,
FromWaypoint = 1,
FromWorld = 2,
FromPlayer = 3,
FromDirected = 4
}
static class PathMainMenu static class PathMainMenu
{ {
internal static List<Path> paths = new List<Path>() { }; internal static List<Path> paths = new List<Path>() { };
private static List<string> dismissOptions = new List<string>() { "From path", "From waypoint", "From world" }; private static string[] dismissOptions = new string[] { "From path", "From waypoint", "From world" };
//private static List<string> dismissOptions = new List<string>() { "From path", "From waypoint", "From world" };
internal static UIMenu pathMainMenu = new UIMenu("Scene Manager", "~o~Path Manager Main Menu"); internal static UIMenu pathMainMenu = new UIMenu("Scene Manager", "~o~Path Manager Main Menu");
internal static UIMenuItem createNewPath; internal static UIMenuItem createNewPath;
@ -41,13 +36,13 @@ namespace SceneManager
{ {
pathMainMenu.ParentMenu = MainMenu.mainMenu; pathMainMenu.ParentMenu = MainMenu.mainMenu;
MenuManager.menuPool.Add(pathMainMenu); MenuManager.menuPool.Add(pathMainMenu);
pathMainMenu.OnItemSelect += PathMenu_OnItemSelected;
pathMainMenu.OnCheckboxChange += PathMenu_OnCheckboxChange;
pathMainMenu.OnMenuOpen += PathMenu_OnMouseDown;
} }
internal static void BuildPathMenu() internal static void BuildPathMenu()
{ {
// Need to unsubscribe from events, else there will be duplicate firings if the user left the menu and re-entered
ResetEventHandlerSubscriptions();
MenuManager.menuPool.CloseAllMenus(); MenuManager.menuPool.CloseAllMenus();
pathMainMenu.Clear(); pathMainMenu.Clear();
@ -81,14 +76,6 @@ namespace SceneManager
} }
MenuManager.menuPool.RefreshIndex(); MenuManager.menuPool.RefreshIndex();
void ResetEventHandlerSubscriptions()
{
pathMainMenu.OnItemSelect -= PathMenu_OnItemSelected;
pathMainMenu.OnCheckboxChange -= PathMenu_OnCheckboxChange;
pathMainMenu.OnItemSelect += PathMenu_OnItemSelected;
pathMainMenu.OnCheckboxChange += PathMenu_OnCheckboxChange;
}
} }
private static bool VehicleAndDriverValid(this Vehicle v) private static bool VehicleAndDriverValid(this Vehicle v)
@ -103,6 +90,68 @@ namespace SceneManager
} }
} }
private static void GoToPathCreationMenu()
{
if (createNewPath.Text.Contains("Continue"))
{
pathMainMenu.Visible = false;
PathCreationMenu.pathCreationMenu.Visible = true;
}
else
{
PathCreationMenu.pathCreationMenu.Clear();
PathCreationMenu.BuildPathCreationMenu();
pathMainMenu.Visible = false;
PathCreationMenu.pathCreationMenu.Visible = true;
//Draw3DWaypointOnPlayer();
// For each element in paths, determine if the element exists but is not finished yet, or if it doesn't exist, create it.
for (int i = 0; i <= paths.Count; i++)
{
if (paths.ElementAtOrDefault(i) != null && paths[i].State == State.Creating)
{
//Game.LogTrivial($"Resuming path {paths[i].Number}");
Game.DisplayNotification($"~o~Scene Manager~y~[Creating]\n~w~Resuming path {paths[i].Number}");
break;
}
}
}
}
private static void DisableAllPaths()
{
if (disableAllPaths.Checked)
{
foreach (Path path in paths)
{
path.DisablePath();
}
Game.LogTrivial($"All paths disabled.");
}
else
{
foreach (Path path in paths)
{
path.EnablePath();
}
Game.LogTrivial($"All paths enabled.");
}
}
private static void DeleteAllPaths()
{
for (int i = 0; i < paths.Count; i++)
{
DeletePath(paths[i], Delete.All);
}
disableAllPaths.Checked = false;
paths.Clear();
BuildPathMenu();
pathMainMenu.Visible = true;
Game.LogTrivial($"All paths deleted");
Game.DisplayNotification($"~o~Scene Manager\n~w~All paths deleted.");
}
internal static void DeletePath(Path path, Delete pathsToDelete) internal static void DeletePath(Path path, Delete pathsToDelete)
{ {
//Game.LogTrivial($"Preparing to delete path {path.Number}"); //Game.LogTrivial($"Preparing to delete path {path.Number}");
@ -196,48 +245,7 @@ namespace SceneManager
} }
} }
private static void PathMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index) private static void DirectDriver()
{
if (selectedItem == createNewPath)
{
pathMainMenu.Visible = false;
PathCreationMenu.pathCreationMenu.Visible = true;
Draw3DWaypointOnPlayer();
// For each element in paths, determine if the element exists but is not finished yet, or if it doesn't exist, create it.
for (int i = 0; i <= paths.Count; i++)
{
if (paths.ElementAtOrDefault(i) != null && paths[i].State == State.Creating)
{
//Game.LogTrivial($"Resuming path {paths[i].Number}");
Game.DisplayNotification($"~o~Scene Manager\n~y~[Creating]~w~ Resuming path {paths[i].Number}");
break;
}
}
}
if (selectedItem == editPath)
{
pathMainMenu.Visible = false;
EditPathMenu.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], Delete.All);
}
disableAllPaths.Checked = false;
paths.Clear();
BuildPathMenu();
pathMainMenu.Visible = true;
Game.LogTrivial($"All paths deleted");
Game.DisplayNotification($"~o~Scene Manager\n~w~All paths deleted.");
}
if (selectedItem == directDriver)
{ {
var nearbyVehicle = Game.LocalPlayer.Character.GetNearbyVehicles(16).Where(v => v != Game.LocalPlayer.Character.CurrentVehicle && v.VehicleAndDriverValid()).FirstOrDefault(); var nearbyVehicle = Game.LocalPlayer.Character.GetNearbyVehicles(16).Where(v => v != Game.LocalPlayer.Character.CurrentVehicle && v.VehicleAndDriverValid()).FirstOrDefault();
var path = paths[directDriver.Index]; var path = paths[directDriver.Index];
@ -249,7 +257,7 @@ namespace SceneManager
if (nearbyVehicle) if (nearbyVehicle)
{ {
var nearbyVehiclePath = paths.Where(p => p.CollectedVehicles.Any(v => v.Vehicle == nearbyVehicle)).FirstOrDefault(); var nearbyVehiclePath = paths.Where(p => p.CollectedVehicles.Any(v => v.Vehicle == nearbyVehicle)).FirstOrDefault();
if(nearbyVehiclePath != null) if (nearbyVehiclePath != null)
{ {
var nearbyCollectedVehicle = nearbyVehiclePath.CollectedVehicles.Where(v => v.Vehicle == nearbyVehicle).FirstOrDefault(); var nearbyCollectedVehicle = nearbyVehiclePath.CollectedVehicles.Where(v => v.Vehicle == nearbyVehicle).FirstOrDefault();
if (nearbyCollectedVehicle != null) if (nearbyCollectedVehicle != null)
@ -313,7 +321,7 @@ namespace SceneManager
} }
} }
if (selectedItem == dismissDriver) private static void DismissDriver()
{ {
var nearbyVehicle = Game.LocalPlayer.Character.GetNearbyVehicles(16).Where(v => v != Game.LocalPlayer.Character.CurrentVehicle && v.VehicleAndDriverValid()).FirstOrDefault(); var nearbyVehicle = Game.LocalPlayer.Character.GetNearbyVehicles(16).Where(v => v != Game.LocalPlayer.Character.CurrentVehicle && v.VehicleAndDriverValid()).FirstOrDefault();
if (nearbyVehicle) if (nearbyVehicle)
@ -336,7 +344,7 @@ namespace SceneManager
return; return;
} }
foreach(Path path in paths) foreach (Path path in paths)
{ {
var collectedVehicle = path.CollectedVehicles.Where(cv => cv.Vehicle == nearbyVehicle).FirstOrDefault(); var collectedVehicle = path.CollectedVehicles.Where(cv => cv.Vehicle == nearbyVehicle).FirstOrDefault();
if (collectedVehicle != null) if (collectedVehicle != null)
@ -364,60 +372,195 @@ namespace SceneManager
} }
} }
} }
private static void PathMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
{
if (selectedItem == createNewPath)
{
GoToPathCreationMenu();
}
if (selectedItem == editPath)
{
pathMainMenu.Visible = false;
EditPathMenu.editPathMenu.Visible = true;
}
if (selectedItem == deleteAllPaths)
{
DeleteAllPaths();
}
if (selectedItem == directDriver)
{
DirectDriver();
}
if (selectedItem == dismissDriver)
{
DismissDriver();
}
} }
private static void PathMenu_OnCheckboxChange(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked) private static void PathMenu_OnCheckboxChange(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked)
{ {
if (checkboxItem == disableAllPaths) if (checkboxItem == disableAllPaths)
{ {
if (disableAllPaths.Checked) DisableAllPaths();
{
foreach (Path path in paths)
{
path.DisablePath();
}
Game.LogTrivial($"All paths disabled.");
}
else
{
foreach (Path path in paths)
{
path.EnablePath();
}
Game.LogTrivial($"All paths enabled.");
}
} }
} }
private static void Draw3DWaypointOnPlayer() private static void PathMenu_OnMouseDown(UIMenu menu)
{ {
GameFiber.StartNew(() => GameFiber.StartNew(() =>
{ {
while (SettingsMenu.threeDWaypoints.Checked) while (menu.Visible)
{ {
if (PathCreationMenu.pathCreationMenu.Visible) var selectedScroller = menu.MenuItems.Where(x => (x == directOptions || x == directDriver || x == dismissDriver || x == editPath) && x.Selected).FirstOrDefault();
if (selectedScroller != null)
{ {
if (PathCreationMenu.collectorWaypoint.Checked) HandleScrollerItemsWithMouseWheel(selectedScroller);
{
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Game.LocalPlayer.Character.Position.X, Game.LocalPlayer.Character.Position.Y, Game.LocalPlayer.Character.Position.Z - 1, 0, 0, 0, 0, 0, 0, (float)PathCreationMenu.collectorRadius.Value * 2, (float)PathCreationMenu.collectorRadius.Value * 2, 1f, 80, 130, 255, 80, false, false, 2, false, 0, 0, false);
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Game.LocalPlayer.Character.Position.X, Game.LocalPlayer.Character.Position.Y, Game.LocalPlayer.Character.Position.Z - 1, 0, 0, 0, 0, 0, 0, (float)PathCreationMenu.speedZoneRadius.Value * 2, (float)PathCreationMenu.speedZoneRadius.Value * 2, 1f, 255, 185, 80, 80, false, false, 2, false, 0, 0, false);
} }
else if (PathCreationMenu.stopWaypointType.Checked)
// Add waypoint if menu item is selected and user left clicks
if (Game.IsKeyDown(Keys.LButton))
{ {
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Game.LocalPlayer.Character.Position.X, Game.LocalPlayer.Character.Position.Y, Game.LocalPlayer.Character.Position.Z - 1, 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 255, 65, 65, 80, false, false, 2, false, 0, 0, false); OnCheckboxItemClicked();
} OnMenuItemClicked();
else
{
Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Game.LocalPlayer.Character.Position.X, Game.LocalPlayer.Character.Position.Y, Game.LocalPlayer.Character.Position.Z - 1, 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 65, 255, 65, 80, false, false, 2, false, 0, 0, false);
}
}
else
{
break;
} }
GameFiber.Yield(); GameFiber.Yield();
} }
}); });
void OnCheckboxItemClicked()
{
if (disableAllPaths.Selected && disableAllPaths.Enabled)
{
disableAllPaths.Checked = !disableAllPaths.Checked;
DisableAllPaths();
} }
} }
void OnMenuItemClicked()
{
if (createNewPath.Selected)
{
GoToPathCreationMenu();
}
else if (editPath.Selected)
{
menu.Visible = false;
EditPathMenu.editPathMenu.Visible = true;
}
else if (deleteAllPaths.Selected)
{
DeleteAllPaths();
}
else if (directDriver.Selected)
{
DirectDriver();
}
else if (dismissDriver.Selected)
{
DismissDriver();
}
}
void HandleScrollerItemsWithMouseWheel(UIMenuItem selectedScroller)
{
var menuScrollingDisabled = false;
var menuItems = menu.MenuItems.Where(x => x != selectedScroller);
while (Game.IsShiftKeyDownRightNow)
{
menu.ResetKey(Common.MenuControls.Up);
menu.ResetKey(Common.MenuControls.Down);
menuScrollingDisabled = true;
ScrollMenuItem();
GameFiber.Yield();
}
if (menuScrollingDisabled)
{
menuScrollingDisabled = false;
menu.SetKey(Common.MenuControls.Up, GameControl.CursorScrollUp);
menu.SetKey(Common.MenuControls.Up, GameControl.CellphoneUp);
menu.SetKey(Common.MenuControls.Down, GameControl.CursorScrollDown);
menu.SetKey(Common.MenuControls.Down, GameControl.CellphoneDown);
}
void ScrollMenuItem()
{
if (Game.GetMouseWheelDelta() > 0)
{
if (selectedScroller == editPath)
{
editPath.ScrollToNextOption();
}
else if (selectedScroller == directOptions)
{
directOptions.ScrollToNextOption();
}
else if (selectedScroller == directDriver)
{
directDriver.ScrollToNextOption();
}
else if (selectedScroller == dismissDriver)
{
dismissDriver.ScrollToNextOption();
}
}
else if (Game.GetMouseWheelDelta() < 0)
{
if (selectedScroller == editPath)
{
editPath.ScrollToPreviousOption();
}
else if (selectedScroller == directOptions)
{
directOptions.ScrollToPreviousOption();
}
else if (selectedScroller == directDriver)
{
directDriver.ScrollToPreviousOption();
}
else if (selectedScroller == dismissDriver)
{
dismissDriver.ScrollToPreviousOption();
}
}
}
}
}
//private static void Draw3DWaypointOnPlayer()
//{
// GameFiber.StartNew(() =>
// {
// while (SettingsMenu.threeDWaypoints.Checked)
// {
// if (PathCreationMenu.pathCreationMenu.Visible)
// {
// if (PathCreationMenu.collectorWaypoint.Checked)
// {
// Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Game.LocalPlayer.Character.Position.X, Game.LocalPlayer.Character.Position.Y, Game.LocalPlayer.Character.Position.Z - 1, 0, 0, 0, 0, 0, 0, (float)PathCreationMenu.collectorRadius.Value * 2, (float)PathCreationMenu.collectorRadius.Value * 2, 1f, 80, 130, 255, 80, false, false, 2, false, 0, 0, false);
// Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Game.LocalPlayer.Character.Position.X, Game.LocalPlayer.Character.Position.Y, Game.LocalPlayer.Character.Position.Z - 1, 0, 0, 0, 0, 0, 0, (float)PathCreationMenu.speedZoneRadius.Value * 2, (float)PathCreationMenu.speedZoneRadius.Value * 2, 1f, 255, 185, 80, 80, false, false, 2, false, 0, 0, false);
// }
// else if (PathCreationMenu.stopWaypointType.Checked)
// {
// Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Game.LocalPlayer.Character.Position.X, Game.LocalPlayer.Character.Position.Y, Game.LocalPlayer.Character.Position.Z - 1, 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 255, 65, 65, 80, false, false, 2, false, 0, 0, false);
// }
// else
// {
// Rage.Native.NativeFunction.Natives.DRAW_MARKER(1, Game.LocalPlayer.Character.Position.X, Game.LocalPlayer.Character.Position.Y, Game.LocalPlayer.Character.Position.Z - 1, 0, 0, 0, 0, 0, 0, 1f, 1f, 1f, 65, 255, 65, 80, false, false, 2, false, 0, 0, false);
// }
// }
// else
// {
// break;
// }
// GameFiber.Yield();
// }
// });
//}
}
} }

View file

@ -2,6 +2,8 @@
using RAGENativeUI; using RAGENativeUI;
using RAGENativeUI.Elements; using RAGENativeUI.Elements;
using System; using System;
using System.Linq;
using System.Windows.Forms;
namespace SceneManager namespace SceneManager
{ {
@ -19,6 +21,10 @@ namespace SceneManager
{ {
settingsMenu.ParentMenu = MainMenu.mainMenu; settingsMenu.ParentMenu = MainMenu.mainMenu;
MenuManager.menuPool.Add(settingsMenu); MenuManager.menuPool.Add(settingsMenu);
settingsMenu.OnCheckboxChange += SettingsMenu_OnCheckboxChange;
settingsMenu.OnScrollerChange += SettingsMenu_OnScrollerChange;
settingsMenu.OnItemSelect += SettingsMenu_OnItemSelected;
settingsMenu.OnMenuOpen += SettingsMenu_OnMouseDown;
} }
internal static void BuildSettingsMenu() internal static void BuildSettingsMenu()
@ -30,30 +36,15 @@ namespace SceneManager
speedUnits.Index = Array.IndexOf(speedArray, Settings.SpeedUnit); speedUnits.Index = Array.IndexOf(speedArray, Settings.SpeedUnit);
settingsMenu.AddItem(saveSettings); settingsMenu.AddItem(saveSettings);
saveSettings.ForeColor = System.Drawing.Color.Gold; saveSettings.ForeColor = System.Drawing.Color.Gold;
settingsMenu.OnCheckboxChange += SettingsMenu_OnCheckboxChange;
settingsMenu.OnScrollerChange += SettingsMenu_OnScrollerChange;
settingsMenu.OnItemSelect += SettingsMenu_OnItemSelected;
} }
private static void SettingsMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index) internal static void ToggleMapBlips()
{
if(selectedItem == saveSettings)
{
Settings.UpdateSettings(threeDWaypoints.Checked, mapBlips.Checked, hints.Checked, speedUnits.SelectedItem);
Game.DisplayHelp($"Settings saved");
}
}
private static void SettingsMenu_OnCheckboxChange(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked)
{
if (checkboxItem == mapBlips)
{ {
if (mapBlips.Checked) if (mapBlips.Checked)
{ {
foreach(Path path in PathMainMenu.paths) foreach (Path path in PathMainMenu.paths)
{ {
foreach(Waypoint wp in path.Waypoints) foreach (Waypoint wp in path.Waypoints)
{ {
wp.EnableBlip(); wp.EnableBlip();
} }
@ -71,6 +62,22 @@ namespace SceneManager
} }
} }
private static void SettingsMenu_OnItemSelected(UIMenu sender, UIMenuItem selectedItem, int index)
{
if(selectedItem == saveSettings)
{
Settings.UpdateSettings(threeDWaypoints.Checked, mapBlips.Checked, hints.Checked, speedUnits.SelectedItem);
Game.DisplayHelp($"Scene Manager settings saved");
}
}
private static void SettingsMenu_OnCheckboxChange(UIMenu sender, UIMenuCheckboxItem checkboxItem, bool @checked)
{
if (checkboxItem == mapBlips)
{
ToggleMapBlips();
}
if (checkboxItem == hints) if (checkboxItem == hints)
{ {
Hints.Enabled = hints.Checked ? true : false; Hints.Enabled = hints.Checked ? true : false;
@ -86,5 +93,100 @@ namespace SceneManager
PathCreationMenu.BuildPathCreationMenu(); PathCreationMenu.BuildPathCreationMenu();
} }
} }
private static void SettingsMenu_OnMouseDown(UIMenu menu)
{
GameFiber.StartNew(() =>
{
while (menu.Visible)
{
var selectedScroller = menu.MenuItems.Where(x => x == speedUnits && x.Selected).FirstOrDefault();
if (selectedScroller != null)
{
HandleScrollerItemsWithMouseWheel(selectedScroller);
}
// Add waypoint if menu item is selected and user left clicks
if (Game.IsKeyDown(Keys.LButton))
{
OnCheckboxItemClicked();
OnMenuItemClicked();
}
GameFiber.Yield();
}
});
void OnCheckboxItemClicked()
{
if (threeDWaypoints.Selected && threeDWaypoints.Enabled)
{
threeDWaypoints.Checked = !threeDWaypoints.Checked;
}
else if (mapBlips.Selected)
{
mapBlips.Checked = !mapBlips.Checked;
ToggleMapBlips();
}
else if (hints.Selected)
{
hints.Checked = !hints.Checked;
Hints.Enabled = hints.Checked ? true : false;
}
}
void OnMenuItemClicked()
{
if (saveSettings.Selected)
{
Settings.UpdateSettings(threeDWaypoints.Checked, mapBlips.Checked, hints.Checked, speedUnits.SelectedItem);
Game.DisplayHelp($"Scene Manager settings saved");
}
}
void HandleScrollerItemsWithMouseWheel(UIMenuItem selectedScroller)
{
var menuScrollingDisabled = false;
var menuItems = menu.MenuItems.Where(x => x != selectedScroller);
while (Game.IsShiftKeyDownRightNow)
{
menu.ResetKey(Common.MenuControls.Up);
menu.ResetKey(Common.MenuControls.Down);
menuScrollingDisabled = true;
ScrollMenuItem();
GameFiber.Yield();
}
if (menuScrollingDisabled)
{
menuScrollingDisabled = false;
menu.SetKey(Common.MenuControls.Up, GameControl.CursorScrollUp);
menu.SetKey(Common.MenuControls.Up, GameControl.CellphoneUp);
menu.SetKey(Common.MenuControls.Down, GameControl.CursorScrollDown);
menu.SetKey(Common.MenuControls.Down, GameControl.CellphoneDown);
}
void ScrollMenuItem()
{
if (Game.GetMouseWheelDelta() > 0)
{
if (selectedScroller == speedUnits)
{
speedUnits.ScrollToNextOption();
PathCreationMenu.pathCreationMenu.Clear();
PathCreationMenu.BuildPathCreationMenu();
}
}
else if (Game.GetMouseWheelDelta() < 0)
{
if (selectedScroller == speedUnits)
{
speedUnits.ScrollToPreviousOption();
PathCreationMenu.pathCreationMenu.Clear();
PathCreationMenu.BuildPathCreationMenu();
}
}
}
}
}
} }
} }