Skip to content

Commit

Permalink
Pathfinder using in-game trapezoids, broken
Browse files Browse the repository at this point in the history
  • Loading branch information
3vcloud committed Nov 30, 2023
1 parent 3cbecf5 commit be97833
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Dependencies/GWCA
Submodule GWCA updated from 124690 to d66b75
1 change: 0 additions & 1 deletion GWToolboxdll/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ file(GLOB SOURCES
"Windows/*.cpp"
)


source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${SOURCES})
target_sources(GWToolboxdll PRIVATE ${SOURCES})

Expand Down
2 changes: 2 additions & 0 deletions GWToolboxdll/Modules/ToolboxSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#include <Windows/DoorMonitorWindow.h>
#include <Windows/StringDecoderWindow.h>
#include <Windows/SkillListingWindow.h>
#include <Windows/Pathfinder.h>
#endif
#include <Windows/RerollWindow.h>
#include <Windows/ArmoryWindow.h>
Expand Down Expand Up @@ -208,6 +209,7 @@ void ToolboxSettings::LoadModules(ToolboxIni* ini)
GWToolbox::ToggleModule(StringDecoderWindow::Instance());
GWToolbox::ToggleModule(DoorMonitorWindow::Instance());
GWToolbox::ToggleModule(SkillListingWindow::Instance());
GWToolbox::ToggleModule(Pathfinder::Instance());
#endif
for (const auto& m : optional_modules) {
GWToolbox::ToggleModule(*m.toolbox_module, m.enabled);
Expand Down
202 changes: 202 additions & 0 deletions GWToolboxdll/Windows/Pathfinder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
#include "stdafx.h"

#include <GWCA/GameEntities/Agent.h>
#include <GWCA/GameEntities/Pathing.h>

#include <GWCA/Packets/StoC.h>

#include <GWCA/Managers/AgentMgr.h>
#include <GWCA/Managers/MapMgr.h>
#include <GWCA/Managers/UIMgr.h>
#include <GWCA/Managers/StoCMgr.h>

#include <Utils/GuiUtils.h>
#include <GWToolbox.h>
#include <Logger.h>

#include <Timer.h>

#include <Windows/Pathfinder.h>


namespace {

GW::Vec2f target_location = { 0,0 };
std::vector<const GW::PathingTrapezoid*> path_chosen;
bool recalculate_path = false;
size_t draw_pos = 0;
clock_t last_draw = 0;

void CmdPathfind(const wchar_t*, const int, const LPWSTR*) {
const auto target = GW::Agents::GetTarget();
if (!target) {
Log::Error("No target");
return;
}
target_location = target->pos;
recalculate_path = true;
}

const GW::Vec2f* GetCurrentPos() {
const auto player = GW::Agents::GetPlayer();
if (!player) return nullptr;
// No copy thanks.
return (GW::Vec2f*) & player->pos;
}
constexpr float GetSquareDistance(const GW::Vec2f& p1, const GW::Vec2f& p2) {
return (p1.x - p2.x) * (p1.x - p2.x) +
(p1.y - p2.y) * (p1.y - p2.y);
}

// Calculate closest vertex to trapezoid. if less than min_distance, will return value.
constexpr float GetClosestVertex(const GW::Vec2f& point, GW::PathingTrapezoid* trapezoid, float min_distance, GW::Vec2f* closest_vertex) {
if (!trapezoid)
return .0f;
GW::Vec2f top_left = { trapezoid->XTL, trapezoid->YT };
GW::Vec2f top_right = { trapezoid->XTR, trapezoid->YT };
GW::Vec2f bottom_right = { trapezoid->XBR, trapezoid->YB };
GW::Vec2f bottom_left = { trapezoid->XBL, trapezoid->YB };

GW::Vec2f* closest = nullptr;

float dist = ::GetSquareDistance(point, top_left);
if (dist < min_distance) {
min_distance = dist;
closest = &top_left;
}
dist = ::GetSquareDistance(point, top_right);
if (dist < min_distance) {
min_distance = dist;
closest = &top_right;
}
dist = ::GetSquareDistance(point, bottom_right);
if (dist < min_distance) {
min_distance = dist;
closest = &bottom_right;
}
dist = ::GetSquareDistance(point, bottom_left);
if (dist < min_distance) {
min_distance = dist;
closest = &bottom_left;
}

if (closest) {
*closest_vertex = *closest;
return min_distance;
}
return .0f;
}
const GW::PathingTrapezoid* GetClosestTrapezoid(const GW::Vec2f& point, GW::Vec2f* closest_vertex) {
const auto pathing_maps = GW::Map::GetPathingMap();

float closest_distance = 99999.0f;
float this_distance = .0f;
GW::PathingTrapezoid* closest_trapezoid = nullptr;
if (!pathing_maps) return nullptr;
for (auto& pathing_map : *pathing_maps) {
for (uint32_t i = 0; i < pathing_map.trapezoid_count; i++) {
this_distance = ::GetClosestVertex(point, &pathing_map.trapezoids[i], closest_distance, closest_vertex);
if (this_distance != .0f && (!closest_trapezoid || this_distance < closest_distance)) {
closest_trapezoid = &pathing_map.trapezoids[i];
closest_distance = this_distance;
}
}
}
return closest_trapezoid;
}
const GW::PathingTrapezoid* GetClosestNeighbor(const GW::Vec2f& point, const GW::PathingTrapezoid* trapezoid, GW::Vec2f* closest_vertex) {
float closest_distance = 99999.0f;
float this_distance = .0f;
GW::PathingTrapezoid* closest_trapezoid = nullptr;

for (uint32_t i = 0; i < _countof(trapezoid->adjacent); i++) {
this_distance = ::GetClosestVertex(point, trapezoid->adjacent[i], closest_distance, closest_vertex);
if (this_distance != .0f && (!closest_trapezoid || this_distance < closest_distance)) {
closest_trapezoid = trapezoid->adjacent[i];
}
}
return closest_trapezoid;
}

bool IsPointWithinTrapezoid(const GW::Vec2f& point, const GW::PathingTrapezoid* trapezoid) {

float x_min = trapezoid->XBL;
if (trapezoid->XTL < x_min)
x_min = trapezoid->XTL;
float x_max = trapezoid->XBR;
if (trapezoid->XTR > x_max)
x_max = trapezoid->XTR;


if (point.x < x_min || point.x > x_max || point.y < trapezoid->YT || point.y > trapezoid->YB) {
// Definitely not within the polygon!
return false;
}
// TODO: Maths.
return true;
}

void Recalculate() {
recalculate_path = false;
Log::Info("Recalculating path");
GW::Vec2f closest_vertex;
const auto pos = GetCurrentPos();
if (!pos) {
Log::Error("No player pos?");
return;
}
path_chosen.clear();
auto trapezoid = GetClosestTrapezoid(*pos, &closest_vertex);
while (trapezoid) {
if (std::find(path_chosen.begin(),path_chosen.end(), trapezoid) != path_chosen.end())
break;
path_chosen.push_back(trapezoid);
if (IsPointWithinTrapezoid(target_location, trapezoid))
break;

trapezoid = GetClosestNeighbor(target_location, trapezoid, &closest_vertex);
}
if (!path_chosen.size()) {
Log::Error("No closest trapezoid?");
return;
}
Log::Info("%d trapezoids, check compass", path_chosen.size());
draw_pos = 0;
}
}

void Pathfinder::Draw(IDirect3DDevice9*)
{
if (recalculate_path) {
Recalculate();
}
if (draw_pos < path_chosen.size()
&& TIMER_DIFF(last_draw) > 1000) {
const auto trapezoid = path_chosen[draw_pos];
GW::Vec2f points[4];
points[0] = { trapezoid->XTL, trapezoid->YT };
points[1] = { trapezoid->XTR, trapezoid->YT };
points[2] = { trapezoid->XBR, trapezoid->YB };
points[3] = { trapezoid->XBL, trapezoid->YB };
GW::UI::DrawOnCompass((unsigned int)&trapezoid, _countof(points), points);

GW::Packet::StoC::CompassEvent event;
event.NumberPts = _countof(points);
event.Player = GW::Agents::GetPlayerAsAgentLiving()->player_number;
for (size_t i = 0; i < event.NumberPts; i++) {
event.points[i].x = (short)points[i].x;
event.points[i].y = (short)points[i].y;
}
GW::StoC::EmulatePacket(&event);
last_draw = TIMER_INIT();
draw_pos++;
}

}

void Pathfinder::Initialize()
{
ToolboxWindow::Initialize();

GW::Chat::CreateCommand(L"pathfind", CmdPathfind);
}
25 changes: 25 additions & 0 deletions GWToolboxdll/Windows/Pathfinder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <GWCA/Constants/Constants.h>

#include <ToolboxWindow.h>


class Pathfinder : public ToolboxWindow {
Pathfinder() = default;
~Pathfinder() override = default;

public:
static Pathfinder& Instance()
{
static Pathfinder instance;
return instance;
}

[[nodiscard]] const char* Name() const override { return "Pathfinder"; }
[[nodiscard]] const char* Icon() const override { return ICON_FA_MAP; }

void Initialize() override;

void Draw(IDirect3DDevice9* pDevice) override;
};

0 comments on commit be97833

Please sign in to comment.