mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Add VehiclesNearTileXY and HasVehicleNearTileXY to iterate over/check for ground vehicles near a tile coordinate.
parent
ac3ed9f3ad
commit
9f1c04c0e1
|
@ -502,6 +502,52 @@ bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
|
||||||
return VehicleFromPosXY(x, y, data, proc, true) != nullptr;
|
return VehicleFromPosXY(x, y, data, proc, true) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterator constructor.
|
||||||
|
* Find first vehicle near (x, y).
|
||||||
|
*/
|
||||||
|
VehiclesNearTileXY::Iterator::Iterator(int32_t x, int32_t y)
|
||||||
|
{
|
||||||
|
const int COLL_DIST = 6;
|
||||||
|
|
||||||
|
/* Hash area to scan */
|
||||||
|
this->hxmin = this->hx = GetTileHash1D((x - COLL_DIST) / TILE_SIZE);
|
||||||
|
this->hxmax = GetTileHash1D((x + COLL_DIST) / TILE_SIZE);
|
||||||
|
this->hymin = this->hy = GetTileHash1D((y - COLL_DIST) / TILE_SIZE);
|
||||||
|
this->hymax = GetTileHash1D((y + COLL_DIST) / TILE_SIZE);
|
||||||
|
|
||||||
|
this->current_veh = _vehicle_tile_hash[ComposeTileHash(this->hx, this->hy)];
|
||||||
|
this->SkipEmptyBuckets();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advance the internal state to the next potential vehicle.
|
||||||
|
*/
|
||||||
|
void VehiclesNearTileXY::Iterator::Increment()
|
||||||
|
{
|
||||||
|
assert(this->current_veh != nullptr);
|
||||||
|
this->current_veh = this->current_veh->hash_tile_next;
|
||||||
|
this->SkipEmptyBuckets();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advance the internal state until we reach a non-empty bucket, or the end.
|
||||||
|
*/
|
||||||
|
void VehiclesNearTileXY::Iterator::SkipEmptyBuckets()
|
||||||
|
{
|
||||||
|
while (this->current_veh == nullptr) {
|
||||||
|
if (this->hx != this->hxmax) {
|
||||||
|
this->hx = IncTileHash1D(this->hx);
|
||||||
|
} else if (this->hy != this->hymax) {
|
||||||
|
this->hx = this->hxmin;
|
||||||
|
this->hy = IncTileHash1D(this->hy);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->current_veh = _vehicle_tile_hash[ComposeTileHash(this->hx, this->hy)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterator constructor.
|
* Iterator constructor.
|
||||||
* Find first vehicle on tile.
|
* Find first vehicle on tile.
|
||||||
|
|
|
@ -111,6 +111,73 @@ bool HasVehicleOnTile(TileIndex tile, UnaryPred &&predicate)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over all vehicles near a given world coordinate.
|
||||||
|
* @warning This only works for vehicles with proper Vehicle::Tile, so only ground vehicles outside wormholes.
|
||||||
|
* @warning The order is non-deterministic. You have to make sure, that your processing is not order dependant.
|
||||||
|
*/
|
||||||
|
class VehiclesNearTileXY {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Forward iterator
|
||||||
|
*/
|
||||||
|
class Iterator {
|
||||||
|
public:
|
||||||
|
using value_type = Vehicle *;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using pointer = void;
|
||||||
|
using reference = void;
|
||||||
|
|
||||||
|
explicit Iterator(int32_t x, int32_t y);
|
||||||
|
|
||||||
|
bool operator==(const Iterator &rhs) const { return this->current_veh == rhs.current_veh; }
|
||||||
|
bool operator==(const std::default_sentinel_t &) const { return this->current_veh == nullptr; }
|
||||||
|
|
||||||
|
Vehicle *operator*() const { return this->current_veh; }
|
||||||
|
|
||||||
|
Iterator &operator++()
|
||||||
|
{
|
||||||
|
this->Increment();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator operator++(int)
|
||||||
|
{
|
||||||
|
Iterator result = *this;
|
||||||
|
++*this;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
uint hxmin, hxmax, hymin, hymax;
|
||||||
|
uint hx, hy;
|
||||||
|
Vehicle *current_veh;
|
||||||
|
|
||||||
|
void Increment();
|
||||||
|
void SkipEmptyBuckets();
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit VehiclesNearTileXY(int32_t x, int32_t y) : start(x, y) {}
|
||||||
|
Iterator begin() const { return this->start; }
|
||||||
|
std::default_sentinel_t end() const { return std::default_sentinel_t(); }
|
||||||
|
private:
|
||||||
|
Iterator start;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop over vehicles near a given world coordinate, and check whether a predicate is true for any of them.
|
||||||
|
* The predicate must have the signature: bool Predicate(const Vehicle *);
|
||||||
|
* @warning This only works for vehicles with proper Vehicle::Tile, so only ground vehicles outside wormholes.
|
||||||
|
*/
|
||||||
|
template <class UnaryPred>
|
||||||
|
bool HasVehicleNearTileXY(int32_t x, int32_t y, UnaryPred &&predicate)
|
||||||
|
{
|
||||||
|
for (const auto *v : VehiclesNearTileXY(x, y)) {
|
||||||
|
if (predicate(v)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
typedef Vehicle *VehicleFromPosProc(Vehicle *v, void *data);
|
typedef Vehicle *VehicleFromPosProc(Vehicle *v, void *data);
|
||||||
|
|
||||||
void VehicleServiceInDepot(Vehicle *v);
|
void VehicleServiceInDepot(Vehicle *v);
|
||||||
|
|
Loading…
Reference in New Issue