Skip to content

Commit 6597b09

Browse files
authored
Merge pull request #1725 from dmwever/Add-Cost-Field-Dirty-Flag
Add dirty flag and integrate
2 parents ca254e7 + 0645469 commit 6597b09

20 files changed

Lines changed: 330 additions & 80 deletions

.mailmap

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ Tobias Feldballe <tobias@osandweb.dk> <tobi.fp@gmail.com>
2020
Tobias Feldballe <tobias@osandweb.dk> <tf@jumpstory.com>
2121
Jonas Borchelt <jonas.borchelt@connected.link>
2222
Derek Frogget <fro22003@byui.edu> <114030121+derekfrogget@users.noreply.github.com>
23-
Nikhil Ghosh <nghosh606@gmail.com>
23+
Nikhil Ghosh <nghosh606@gmail.com>
24+
David Wever <dmwever@crimson.ua.edu> <56411717+dmwever@users.noreply.github.com>

copying.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ _the openage authors_ are:
158158
| Jeremiah Morgan | jere8184 | jeremiahmorgan dawt bham à outlook dawt com |
159159
| Tobias Alam | alamt22 | tobiasal à umich dawt edu |
160160
| Alex Zhuohao He | ZzzhHe | zhuohao dawt he à outlook dawt com |
161+
| David Wever | dmwever | dmwever à crimson dawt ua dawt edu |
161162

162163
If you're a first-time committer, add yourself to the above list. This is not
163164
just for legal reasons, but also to keep an overview of all those nicknames.

libopenage/gamestate/map.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Map::Map(const std::shared_ptr<GameState> &state,
4949

5050
auto sector = grid->get_sector(chunk_idx);
5151
auto cost_field = sector->get_cost_field();
52-
cost_field->set_cost(tile_idx, path_cost.second);
52+
cost_field->set_cost(tile_idx, path_cost.second, time::TIME_ZERO);
5353
}
5454
}
5555
}

libopenage/gamestate/system/move.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2023-2024 the openage authors. See copying.md for legal info.
1+
// Copyright 2023-2025 the openage authors. See copying.md for legal info.
22

33
#include "move.h"
44

@@ -37,7 +37,8 @@ namespace openage::gamestate::system {
3737
std::vector<coord::phys3> find_path(const std::shared_ptr<path::Pathfinder> &pathfinder,
3838
path::grid_id_t grid_id,
3939
const coord::phys3 &start,
40-
const coord::phys3 &end) {
40+
const coord::phys3 &end,
41+
const time::time_t &start_time) {
4142
auto start_tile = start.to_tile();
4243
auto end_tile = end.to_tile();
4344

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

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

127129
// use waypoints for movement
128130
double total_time = 0;

libopenage/pathfinding/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_sources(libopenage
22
cost_field.cpp
33
definitions.cpp
4+
field_cache.cpp
45
flow_field.cpp
56
grid.cpp
67
integration_field.cpp

libopenage/pathfinding/cost_field.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2024-2024 the openage authors. See copying.md for legal info.
1+
// Copyright 2024-2025 the openage authors. See copying.md for legal info.
22

33
#include "cost_field.h"
44

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

1414
CostField::CostField(size_t size) :
1515
size{size},
16+
valid_until{time::TIME_MIN},
1617
cells(this->size * this->size, COST_MIN) {
1718
log::log(DBG << "Created cost field with size " << this->size << "x" << this->size);
1819
}
@@ -33,29 +34,34 @@ cost_t CostField::get_cost(size_t idx) const {
3334
return this->cells.at(idx);
3435
}
3536

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

40-
void CostField::set_cost(size_t x, size_t y, cost_t cost) {
41-
this->cells[x + y * this->size] = cost;
42-
}
43-
44-
void CostField::set_cost(size_t idx, cost_t cost) {
45-
this->cells[idx] = cost;
41+
void CostField::set_cost(size_t x, size_t y, cost_t cost, const time::time_t &valid_until) {
42+
this->set_cost(x + y * this->size, cost, valid_until);
4643
}
4744

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

52-
void CostField::set_costs(std::vector<cost_t> &&cells) {
49+
void CostField::set_costs(std::vector<cost_t> &&cells, const time::time_t &valid_until) {
5350
ENSURE(cells.size() == this->cells.size(),
5451
"cells vector has wrong size: " << cells.size()
5552
<< "; expected: "
5653
<< this->cells.size());
5754

5855
this->cells = std::move(cells);
56+
this->valid_until = valid_until;
57+
}
58+
59+
bool CostField::is_dirty(const time::time_t &time) const {
60+
return time >= this->valid_until;
61+
}
62+
63+
void CostField::clear_dirty() {
64+
this->valid_until = time::TIME_MAX;
5965
}
6066

6167
} // namespace openage::path

libopenage/pathfinding/cost_field.h

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
// Copyright 2024-2024 the openage authors. See copying.md for legal info.
1+
// Copyright 2024-2025 the openage authors. See copying.md for legal info.
22

33
#pragma once
44

55
#include <cstddef>
66
#include <vector>
77

88
#include "pathfinding/types.h"
9+
#include "time/time.h"
910

1011

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

7072
/**
7173
* Set the cost at a specified position.
7274
*
7375
* @param x X-coordinate of the cell.
7476
* @param y Y-coordinate of the cell.
7577
* @param cost Cost to set.
78+
* @param valid_until Time at which the cost value expires.
7679
*/
77-
void set_cost(size_t x, size_t y, cost_t cost);
80+
void set_cost(size_t x, size_t y, cost_t cost, const time::time_t &valid_until);
7881

7982
/**
8083
* Set the cost at a specified position.
8184
*
8285
* @param idx Index of the cell.
8386
* @param cost Cost to set.
87+
* @param valid_until Time at which the cost value expires.
8488
*/
85-
void set_cost(size_t idx, cost_t cost);
89+
inline void set_cost(size_t idx, cost_t cost, const time::time_t &valid_until) {
90+
this->cells[idx] = cost;
91+
this->valid_until = valid_until;
92+
}
8693

8794
/**
8895
* Get the cost field values.
@@ -95,15 +102,35 @@ class CostField {
95102
* Set the cost field values.
96103
*
97104
* @param cells Cost field values.
105+
* @param valid_until Time at which the cost value expires.
98106
*/
99-
void set_costs(std::vector<cost_t> &&cells);
107+
void set_costs(std::vector<cost_t> &&cells, const time::time_t &changed);
108+
109+
/**
110+
* Check if the cost field is dirty at the specified time.
111+
*
112+
* @param time Time of access to the cost field.
113+
*
114+
* @return Whether the cost field is dirty.
115+
*/
116+
bool is_dirty(const time::time_t &time) const;
117+
118+
/**
119+
* Clear the dirty flag.
120+
*/
121+
void clear_dirty();
100122

101123
private:
102124
/**
103125
* Side length of the field.
104126
*/
105127
size_t size;
106128

129+
/**
130+
* Time the cost field expires.
131+
*/
132+
time::time_t valid_until;
133+
107134
/**
108135
* Cost field values.
109136
*/

libopenage/pathfinding/demo/demo_0.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2024-2024 the openage authors. See copying.md for legal info.
1+
// Copyright 2024-2025 the openage authors. See copying.md for legal info.
22

33
#include "demo_0.h"
44

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

3434
// Cost field with some obstacles
3535
auto cost_field = std::make_shared<CostField>(field_length);
36-
cost_field->set_cost(coord::tile_delta{0, 0}, COST_IMPASSABLE);
37-
cost_field->set_cost(coord::tile_delta{1, 0}, 254);
38-
cost_field->set_cost(coord::tile_delta{4, 3}, 128);
39-
cost_field->set_cost(coord::tile_delta{5, 3}, 128);
40-
cost_field->set_cost(coord::tile_delta{6, 3}, 128);
41-
cost_field->set_cost(coord::tile_delta{4, 4}, 128);
42-
cost_field->set_cost(coord::tile_delta{5, 4}, 128);
43-
cost_field->set_cost(coord::tile_delta{6, 4}, 128);
44-
cost_field->set_cost(coord::tile_delta{1, 7}, COST_IMPASSABLE);
36+
37+
const time::time_t time = time::TIME_ZERO;
38+
cost_field->set_cost(coord::tile_delta{0, 0}, COST_IMPASSABLE, time);
39+
cost_field->set_cost(coord::tile_delta{1, 0}, 254, time);
40+
cost_field->set_cost(coord::tile_delta{4, 3}, 128, time);
41+
cost_field->set_cost(coord::tile_delta{5, 3}, 128, time);
42+
cost_field->set_cost(coord::tile_delta{6, 3}, 128, time);
43+
cost_field->set_cost(coord::tile_delta{4, 4}, 128, time);
44+
cost_field->set_cost(coord::tile_delta{5, 4}, 128, time);
45+
cost_field->set_cost(coord::tile_delta{6, 4}, 128, time);
46+
cost_field->set_cost(coord::tile_delta{1, 7}, COST_IMPASSABLE, time);
4547
log::log(INFO << "Created cost field");
4648

4749
// Create an integration field from the cost field

libopenage/pathfinding/demo/demo_1.cpp

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2024-2024 the openage authors. See copying.md for legal info.
1+
// Copyright 2024-2025 the openage authors. See copying.md for legal info.
22

33
#include "demo_1.h"
44

@@ -30,29 +30,42 @@ void path_demo_1(const util::Path &path) {
3030
// Initialize the cost field for each sector.
3131
for (auto &sector : grid->get_sectors()) {
3232
auto cost_field = sector->get_cost_field();
33-
std::vector<cost_t> sector_cost = sectors_cost.at(sector->get_id());
34-
cost_field->set_costs(std::move(sector_cost));
33+
34+
// Read the data from the preconfigured table
35+
std::vector<cost_t> sector_cost = SECTORS_COST.at(sector->get_id());
36+
37+
// Set the cost field for the sector
38+
cost_field->set_costs(std::move(sector_cost), time::TIME_MAX);
3539
}
3640

37-
// Initialize portals between sectors.
41+
// Initialize portals between sectors
3842
util::Vector2s grid_size = grid->get_size();
3943
portal_id_t portal_id = 0;
4044
for (size_t y = 0; y < grid_size[1]; y++) {
4145
for (size_t x = 0; x < grid_size[0]; x++) {
46+
// For each sector on the grid, we will seatch for portals to the east and south
47+
// sectors and connect them
48+
4249
auto sector = grid->get_sector(x, y);
4350

4451
if (x < grid_size[0] - 1) {
52+
// Check the sector to the east
4553
auto neighbor = grid->get_sector(x + 1, y);
4654
auto portals = sector->find_portals(neighbor, PortalDirection::EAST_WEST, portal_id);
55+
56+
// Add the portals to the sector and the neighbor
4757
for (auto &portal : portals) {
4858
sector->add_portal(portal);
4959
neighbor->add_portal(portal);
5060
}
5161
portal_id += portals.size();
5262
}
5363
if (y < grid_size[1] - 1) {
64+
// Check the sector to the south
5465
auto neighbor = grid->get_sector(x, y + 1);
5566
auto portals = sector->find_portals(neighbor, PortalDirection::NORTH_SOUTH, portal_id);
67+
68+
// Add the portals to the sector and the neighbor
5669
for (auto &portal : portals) {
5770
sector->add_portal(portal);
5871
neighbor->add_portal(portal);
@@ -62,7 +75,8 @@ void path_demo_1(const util::Path &path) {
6275
}
6376
}
6477

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

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

98+
// Add a timer to measure the pathfinding speed
8499
util::Timer timer;
85100

86-
// Create a path request and get the path
101+
// Create a path request from one end of the grid to the other
87102
coord::tile start{2, 26};
88103
coord::tile target{36, 2};
89-
90104
PathRequest path_request{
91105
grid->get_id(),
92106
start,
93107
target,
108+
time::TIME_ZERO,
94109
};
110+
111+
// Initialize the portal nodes of the grid
112+
// This is used for the A* pathfinding search at the beginning
95113
grid->init_portal_nodes();
114+
96115
timer.start();
116+
// Let the pathfinder search for a path
97117
Path path_result = pathfinder->get_path(path_request);
98118
timer.stop();
99119

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

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

132156
timer.reset();
@@ -147,6 +171,7 @@ void path_demo_1(const util::Path &path) {
147171
grid->get_id(),
148172
start,
149173
target,
174+
time::TIME_ZERO,
150175
};
151176

152177
timer.reset();

libopenage/pathfinding/demo/demo_1.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2024-2024 the openage authors. See copying.md for legal info.
1+
// Copyright 2024-2025 the openage authors. See copying.md for legal info.
22

33
#pragma once
44

@@ -182,7 +182,7 @@ class RenderManager1 {
182182

183183
// Cost for the sectors in the grid
184184
// taken from Figure 23.1 in "Crowd Pathfinding and Steering Using Flow Field Tiles"
185-
const std::vector<std::vector<cost_t>> sectors_cost = {
185+
const std::vector<std::vector<cost_t>> SECTORS_COST = {
186186
{
187187
// clang-format off
188188
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

0 commit comments

Comments
 (0)