Skip to content

Commit

Permalink
Merge pull request #1725 from dmwever/Add-Cost-Field-Dirty-Flag
Browse files Browse the repository at this point in the history
Add dirty flag and integrate
  • Loading branch information
heinezen authored Jan 17, 2025
2 parents ca254e7 + 0645469 commit 6597b09
Show file tree
Hide file tree
Showing 20 changed files with 330 additions and 80 deletions.
3 changes: 2 additions & 1 deletion .mailmap
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ Tobias Feldballe <[email protected]> <[email protected]>
Tobias Feldballe <[email protected]> <[email protected]>
Jonas Borchelt <[email protected]>
Derek Frogget <[email protected]> <[email protected]>
Nikhil Ghosh <[email protected]>
Nikhil Ghosh <[email protected]>
David Wever <[email protected]> <[email protected]>
1 change: 1 addition & 0 deletions copying.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ _the openage authors_ are:
| Jeremiah Morgan | jere8184 | jeremiahmorgan dawt bham à outlook dawt com |
| Tobias Alam | alamt22 | tobiasal à umich dawt edu |
| Alex Zhuohao He | ZzzhHe | zhuohao dawt he à outlook dawt com |
| David Wever | dmwever | dmwever à crimson dawt ua dawt edu |

If you're a first-time committer, add yourself to the above list. This is not
just for legal reasons, but also to keep an overview of all those nicknames.
Expand Down
2 changes: 1 addition & 1 deletion libopenage/gamestate/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Map::Map(const std::shared_ptr<GameState> &state,

auto sector = grid->get_sector(chunk_idx);
auto cost_field = sector->get_cost_field();
cost_field->set_cost(tile_idx, path_cost.second);
cost_field->set_cost(tile_idx, path_cost.second, time::TIME_ZERO);
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions libopenage/gamestate/system/move.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023-2024 the openage authors. See copying.md for legal info.
// Copyright 2023-2025 the openage authors. See copying.md for legal info.

#include "move.h"

Expand Down Expand Up @@ -37,7 +37,8 @@ namespace openage::gamestate::system {
std::vector<coord::phys3> find_path(const std::shared_ptr<path::Pathfinder> &pathfinder,
path::grid_id_t grid_id,
const coord::phys3 &start,
const coord::phys3 &end) {
const coord::phys3 &end,
const time::time_t &start_time) {
auto start_tile = start.to_tile();
auto end_tile = end.to_tile();

Expand All @@ -46,6 +47,7 @@ std::vector<coord::phys3> find_path(const std::shared_ptr<path::Pathfinder> &pat
grid_id,
start_tile,
end_tile,
start_time,
};
auto tile_path = pathfinder->get_path(request);

Expand Down Expand Up @@ -122,7 +124,7 @@ const time::time_t Move::move_default(const std::shared_ptr<gamestate::GameEntit
auto map = state->get_map();
auto pathfinder = map->get_pathfinder();
auto grid_id = map->get_grid_id(move_path_grid->get_name());
auto waypoints = find_path(pathfinder, grid_id, current_pos, destination);
auto waypoints = find_path(pathfinder, grid_id, current_pos, destination, start_time);

// use waypoints for movement
double total_time = 0;
Expand Down
1 change: 1 addition & 0 deletions libopenage/pathfinding/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
add_sources(libopenage
cost_field.cpp
definitions.cpp
field_cache.cpp
flow_field.cpp
grid.cpp
integration_field.cpp
Expand Down
26 changes: 16 additions & 10 deletions libopenage/pathfinding/cost_field.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024-2024 the openage authors. See copying.md for legal info.
// Copyright 2024-2025 the openage authors. See copying.md for legal info.

#include "cost_field.h"

Expand All @@ -13,6 +13,7 @@ namespace openage::path {

CostField::CostField(size_t size) :
size{size},
valid_until{time::TIME_MIN},
cells(this->size * this->size, COST_MIN) {
log::log(DBG << "Created cost field with size " << this->size << "x" << this->size);
}
Expand All @@ -33,29 +34,34 @@ cost_t CostField::get_cost(size_t idx) const {
return this->cells.at(idx);
}

void CostField::set_cost(const coord::tile_delta &pos, cost_t cost) {
this->cells[pos.ne + pos.se * this->size] = cost;
void CostField::set_cost(const coord::tile_delta &pos, cost_t cost, const time::time_t &valid_until) {
this->set_cost(pos.ne + pos.se * this->size, cost, valid_until);
}

void CostField::set_cost(size_t x, size_t y, cost_t cost) {
this->cells[x + y * this->size] = cost;
}

void CostField::set_cost(size_t idx, cost_t cost) {
this->cells[idx] = cost;
void CostField::set_cost(size_t x, size_t y, cost_t cost, const time::time_t &valid_until) {
this->set_cost(x + y * this->size, cost, valid_until);
}

const std::vector<cost_t> &CostField::get_costs() const {
return this->cells;
}

void CostField::set_costs(std::vector<cost_t> &&cells) {
void CostField::set_costs(std::vector<cost_t> &&cells, const time::time_t &valid_until) {
ENSURE(cells.size() == this->cells.size(),
"cells vector has wrong size: " << cells.size()
<< "; expected: "
<< this->cells.size());

this->cells = std::move(cells);
this->valid_until = valid_until;
}

bool CostField::is_dirty(const time::time_t &time) const {
return time >= this->valid_until;
}

void CostField::clear_dirty() {
this->valid_until = time::TIME_MAX;
}

} // namespace openage::path
37 changes: 32 additions & 5 deletions libopenage/pathfinding/cost_field.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// Copyright 2024-2024 the openage authors. See copying.md for legal info.
// Copyright 2024-2025 the openage authors. See copying.md for legal info.

#pragma once

#include <cstddef>
#include <vector>

#include "pathfinding/types.h"
#include "time/time.h"


namespace openage {
Expand Down Expand Up @@ -64,25 +65,31 @@ class CostField {
*
* @param pos Coordinates of the cell (relative to field origin).
* @param cost Cost to set.
* @param valid_until Time at which the cost value expires.
*/
void set_cost(const coord::tile_delta &pos, cost_t cost);
void set_cost(const coord::tile_delta &pos, cost_t cost, const time::time_t &valid_until);

/**
* Set the cost at a specified position.
*
* @param x X-coordinate of the cell.
* @param y Y-coordinate of the cell.
* @param cost Cost to set.
* @param valid_until Time at which the cost value expires.
*/
void set_cost(size_t x, size_t y, cost_t cost);
void set_cost(size_t x, size_t y, cost_t cost, const time::time_t &valid_until);

/**
* Set the cost at a specified position.
*
* @param idx Index of the cell.
* @param cost Cost to set.
* @param valid_until Time at which the cost value expires.
*/
void set_cost(size_t idx, cost_t cost);
inline void set_cost(size_t idx, cost_t cost, const time::time_t &valid_until) {
this->cells[idx] = cost;
this->valid_until = valid_until;
}

/**
* Get the cost field values.
Expand All @@ -95,15 +102,35 @@ class CostField {
* Set the cost field values.
*
* @param cells Cost field values.
* @param valid_until Time at which the cost value expires.
*/
void set_costs(std::vector<cost_t> &&cells);
void set_costs(std::vector<cost_t> &&cells, const time::time_t &changed);

/**
* Check if the cost field is dirty at the specified time.
*
* @param time Time of access to the cost field.
*
* @return Whether the cost field is dirty.
*/
bool is_dirty(const time::time_t &time) const;

/**
* Clear the dirty flag.
*/
void clear_dirty();

private:
/**
* Side length of the field.
*/
size_t size;

/**
* Time the cost field expires.
*/
time::time_t valid_until;

/**
* Cost field values.
*/
Expand Down
22 changes: 12 additions & 10 deletions libopenage/pathfinding/demo/demo_0.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024-2024 the openage authors. See copying.md for legal info.
// Copyright 2024-2025 the openage authors. See copying.md for legal info.

#include "demo_0.h"

Expand Down Expand Up @@ -33,15 +33,17 @@ void path_demo_0(const util::Path &path) {

// Cost field with some obstacles
auto cost_field = std::make_shared<CostField>(field_length);
cost_field->set_cost(coord::tile_delta{0, 0}, COST_IMPASSABLE);
cost_field->set_cost(coord::tile_delta{1, 0}, 254);
cost_field->set_cost(coord::tile_delta{4, 3}, 128);
cost_field->set_cost(coord::tile_delta{5, 3}, 128);
cost_field->set_cost(coord::tile_delta{6, 3}, 128);
cost_field->set_cost(coord::tile_delta{4, 4}, 128);
cost_field->set_cost(coord::tile_delta{5, 4}, 128);
cost_field->set_cost(coord::tile_delta{6, 4}, 128);
cost_field->set_cost(coord::tile_delta{1, 7}, COST_IMPASSABLE);

const time::time_t time = time::TIME_ZERO;
cost_field->set_cost(coord::tile_delta{0, 0}, COST_IMPASSABLE, time);
cost_field->set_cost(coord::tile_delta{1, 0}, 254, time);
cost_field->set_cost(coord::tile_delta{4, 3}, 128, time);
cost_field->set_cost(coord::tile_delta{5, 3}, 128, time);
cost_field->set_cost(coord::tile_delta{6, 3}, 128, time);
cost_field->set_cost(coord::tile_delta{4, 4}, 128, time);
cost_field->set_cost(coord::tile_delta{5, 4}, 128, time);
cost_field->set_cost(coord::tile_delta{6, 4}, 128, time);
cost_field->set_cost(coord::tile_delta{1, 7}, COST_IMPASSABLE, time);
log::log(INFO << "Created cost field");

// Create an integration field from the cost field
Expand Down
39 changes: 32 additions & 7 deletions libopenage/pathfinding/demo/demo_1.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024-2024 the openage authors. See copying.md for legal info.
// Copyright 2024-2025 the openage authors. See copying.md for legal info.

#include "demo_1.h"

Expand Down Expand Up @@ -30,29 +30,42 @@ void path_demo_1(const util::Path &path) {
// Initialize the cost field for each sector.
for (auto &sector : grid->get_sectors()) {
auto cost_field = sector->get_cost_field();
std::vector<cost_t> sector_cost = sectors_cost.at(sector->get_id());
cost_field->set_costs(std::move(sector_cost));

// Read the data from the preconfigured table
std::vector<cost_t> sector_cost = SECTORS_COST.at(sector->get_id());

// Set the cost field for the sector
cost_field->set_costs(std::move(sector_cost), time::TIME_MAX);
}

// Initialize portals between sectors.
// Initialize portals between sectors
util::Vector2s grid_size = grid->get_size();
portal_id_t portal_id = 0;
for (size_t y = 0; y < grid_size[1]; y++) {
for (size_t x = 0; x < grid_size[0]; x++) {
// For each sector on the grid, we will seatch for portals to the east and south
// sectors and connect them

auto sector = grid->get_sector(x, y);

if (x < grid_size[0] - 1) {
// Check the sector to the east
auto neighbor = grid->get_sector(x + 1, y);
auto portals = sector->find_portals(neighbor, PortalDirection::EAST_WEST, portal_id);

// Add the portals to the sector and the neighbor
for (auto &portal : portals) {
sector->add_portal(portal);
neighbor->add_portal(portal);
}
portal_id += portals.size();
}
if (y < grid_size[1] - 1) {
// Check the sector to the south
auto neighbor = grid->get_sector(x, y + 1);
auto portals = sector->find_portals(neighbor, PortalDirection::NORTH_SOUTH, portal_id);

// Add the portals to the sector and the neighbor
for (auto &portal : portals) {
sector->add_portal(portal);
neighbor->add_portal(portal);
Expand All @@ -62,7 +75,8 @@ void path_demo_1(const util::Path &path) {
}
}

// Connect portals inside sectors.
// Connect portals that can mutually reach each other
// within the same sector
for (auto sector : grid->get_sectors()) {
sector->connect_exits();

Expand All @@ -81,19 +95,25 @@ void path_demo_1(const util::Path &path) {
auto pathfinder = std::make_shared<path::Pathfinder>();
pathfinder->add_grid(grid);

// Add a timer to measure the pathfinding speed
util::Timer timer;

// Create a path request and get the path
// Create a path request from one end of the grid to the other
coord::tile start{2, 26};
coord::tile target{36, 2};

PathRequest path_request{
grid->get_id(),
start,
target,
time::TIME_ZERO,
};

// Initialize the portal nodes of the grid
// This is used for the A* pathfinding search at the beginning
grid->init_portal_nodes();

timer.start();
// Let the pathfinder search for a path
Path path_result = pathfinder->get_path(path_request);
timer.stop();

Expand All @@ -109,8 +129,11 @@ void path_demo_1(const util::Path &path) {
auto render_manager = std::make_shared<RenderManager1>(qtapp, window, path, grid);
log::log(INFO << "Created render manager for pathfinding demo");

// Callbacks for mouse button events
// Used to set the start and target cells for pathfinding
window->add_mouse_button_callback([&](const QMouseEvent &ev) {
if (ev.type() == QEvent::MouseButtonRelease) {
// From the mouse position, calculate the position/cell on the grid
auto cell_count_x = grid->get_size()[0] * grid->get_sector_size();
auto cell_count_y = grid->get_size()[1] * grid->get_sector_size();
auto window_size = window->get_size();
Expand All @@ -127,6 +150,7 @@ void path_demo_1(const util::Path &path) {
grid->get_id(),
start,
target,
time::TIME_ZERO,
};

timer.reset();
Expand All @@ -147,6 +171,7 @@ void path_demo_1(const util::Path &path) {
grid->get_id(),
start,
target,
time::TIME_ZERO,
};

timer.reset();
Expand Down
4 changes: 2 additions & 2 deletions libopenage/pathfinding/demo/demo_1.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024-2024 the openage authors. See copying.md for legal info.
// Copyright 2024-2025 the openage authors. See copying.md for legal info.

#pragma once

Expand Down Expand Up @@ -182,7 +182,7 @@ class RenderManager1 {

// Cost for the sectors in the grid
// taken from Figure 23.1 in "Crowd Pathfinding and Steering Using Flow Field Tiles"
const std::vector<std::vector<cost_t>> sectors_cost = {
const std::vector<std::vector<cost_t>> SECTORS_COST = {
{
// clang-format off
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
Expand Down
Loading

0 comments on commit 6597b09

Please sign in to comment.