This repository has been archived on 2024-10-22. You can view files and clone it, but cannot push or open issues or pull requests.
YimMenu/src/util/pathfind.hpp

161 lines
5.1 KiB
C++
Raw Normal View History

2023-04-05 19:54:29 +02:00
#pragma once
2023-04-23 17:23:00 +02:00
#include "gta/enums.hpp"
#include "math.hpp"
2023-04-05 19:54:29 +02:00
#include "natives.hpp"
#include "pointers.hpp"
#include "script.hpp"
2023-04-23 17:23:00 +02:00
#include <random>
2023-04-05 19:54:29 +02:00
namespace big::pathfind
{
inline bool load_path_nodes(Vector3 coords)
{
2023-04-23 17:23:00 +02:00
if (PATHFIND::ARE_NODES_LOADED_FOR_AREA(coords.x, coords.y, coords.z, coords.y))
return true;
2023-04-05 19:54:29 +02:00
PATHFIND::REQUEST_PATH_NODES_IN_AREA_THIS_FRAME(coords.x, coords.y, coords.z, coords.y);
for (int i = 0; i < 35 && !PATHFIND::ARE_NODES_LOADED_FOR_AREA(coords.x, coords.y, coords.z, coords.y); i++)
{
PATHFIND::REQUEST_PATH_NODES_IN_AREA_THIS_FRAME(coords.x, coords.y, coords.z, coords.y);
script::get_current()->yield(10ms);
}
return PATHFIND::ARE_NODES_LOADED_FOR_AREA(coords.x, coords.y, coords.z, coords.y);
}
inline bool load_navmesh_area(Vector3 coords, float radius)
{
2023-04-23 17:23:00 +02:00
if (PATHFIND::ARE_ALL_NAVMESH_REGIONS_LOADED())
return true;
2023-04-05 19:54:29 +02:00
PATHFIND::ADD_NAVMESH_REQUIRED_REGION(coords.x, coords.z, radius);
for (int i = 0; i < 35 && !PATHFIND::ARE_ALL_NAVMESH_REGIONS_LOADED(); i++)
{
script::get_current()->yield(10ms);
}
return PATHFIND::ARE_ALL_NAVMESH_REGIONS_LOADED();
}
/*
Be sure to call this after having added a required region to free up memory since the game files suggest it is rather demanding to load navmesh
*/
inline void remove_navmesh_required_areas()
{
PATHFIND::REMOVE_NAVMESH_REQUIRED_REGIONS();
}
inline bool find_safe_pos_ped(Vector3 coords, Vector3& outcoords, bool onGround, int flag)
{
if (load_path_nodes(coords))
return PATHFIND::GET_SAFE_COORD_FOR_PED(coords.x, coords.y, coords.z, onGround, &outcoords, flag);
else
return false;
}
/*
zMeasureMult: how strongly should the difference in Z direction be weighted?
0.0 = ignored completely, 1.0 = the same as 2d distance. Default is 3.0 since we tend to care about
height differences more than 2d distance.
zTolerance: how far apart to the Z coords have to be before zMeasureMult kicks in?
nth: Which coords are returned, 1 being closest, 2 being second closesst and so on
*/
inline bool find_closest_vehicle_node(Vector3 coords, Vector3& outcoords, float& outheading, int flag, int nth = 1, float zMeasureMult = 3.f, float zTolerance = 0.f)
{
int lanes;
if (load_path_nodes(coords))
return PATHFIND::GET_NTH_CLOSEST_VEHICLE_NODE_WITH_HEADING(coords.x, coords.y, coords.z, nth, &outcoords, &outheading, &lanes, flag, zMeasureMult, zTolerance);
else
return false;
}
2023-04-23 17:23:00 +02:00
inline bool find_random_vehicle_node(Vector3 center, Vector3& outcoords, float radius, bool avoid_dead_ends, bool avoid_highways, int min_lanes = 0)
{
int node_id;
if (load_path_nodes(center))
return PATHFIND::GET_RANDOM_VEHICLE_NODE(center.x, center.y, center.z, radius, 0, avoid_dead_ends, avoid_highways, &outcoords, &node_id);
else
return false;
}
inline void apply_distance_to_random_direction(Vector3& outcoords, float distance)
2023-04-05 19:54:29 +02:00
{
2023-04-23 17:23:00 +02:00
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 1);
if (dis(gen))
{
dis(gen) ? outcoords.x += distance : outcoords.x -= distance;
}
else
2023-04-05 19:54:29 +02:00
{
2023-04-23 17:23:00 +02:00
dis(gen) ? outcoords.y += distance : outcoords.y -= distance;
2023-04-05 19:54:29 +02:00
}
2023-04-23 17:23:00 +02:00
}
inline bool find_random_location_in_vicinity(Vector3 coords, Vector3& outcoords, float& outheading, int flag, int vicinity)
{
outcoords = coords;
apply_distance_to_random_direction(outcoords, vicinity);
2023-04-05 19:54:29 +02:00
2023-04-23 17:23:00 +02:00
Vector3 changed_coords = outcoords;
2023-04-05 19:54:29 +02:00
2023-04-23 17:23:00 +02:00
if (!find_closest_vehicle_node(outcoords, outcoords, outheading, flag) || math::distance_between_vectors(outcoords, coords) > vicinity || math::distance_between_vectors(outcoords, coords) < (vicinity / 2))
2023-04-05 19:54:29 +02:00
{
2023-04-23 17:23:00 +02:00
outcoords = coords;
if (!pathfind::find_safe_pos_ped(changed_coords, outcoords, false, 0))
2023-04-05 19:54:29 +02:00
{
outcoords = coords;
}
}
2023-04-23 17:23:00 +02:00
return outcoords != coords;
}
/*
The precision means the algorithm will try and get a position as close to the desired distance as possible
Param precision goes up to a value of 200 meaning how many positions it will try and filter from
Might prove resource demanding based on hardware
*/
inline bool find_random_location_in_vicinity_precise(Vector3 coords, Vector3& outcoords, float& outheading, int flag, float vicinity, int precision = 50)
{
if (precision > 200)
precision = 200;
std::vector<Vector3> found_locations{};
//Find random positions
for (int i = 0; i < precision; i++)
{
Vector3 new_pos{};
find_random_location_in_vicinity(coords, new_pos, outheading, flag, vicinity);
found_locations.push_back(new_pos);
}
Vector3 best_location = found_locations[0];
//Measure the distance of the position to the given vicinity distance
static float distance_to_vicinity = std::abs(vicinity - math::distance_between_vectors(best_location, coords));
for (auto l : found_locations)
{
float new_distance_to_vicinity = std::abs(vicinity - math::distance_between_vectors(l, coords));
//If the new distance is smaller, that means we have a position that is closer to the edge
if (new_distance_to_vicinity < distance_to_vicinity)
{
distance_to_vicinity = new_distance_to_vicinity;
best_location = l;
}
}
outcoords = best_location;
return outcoords != coords;
2023-04-05 19:54:29 +02:00
}
}