mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-10-31 15:20:10 +00:00
Change ship path cache to be optional and use a ring buffer
This commit is contained in:
parent
2ae4e5bdc1
commit
92e632454e
@ -38,9 +38,6 @@ static const int YAPF_TILE_CORNER_LENGTH = 71;
|
|||||||
*/
|
*/
|
||||||
static const int YAPF_INFINITE_PENALTY = 1000 * YAPF_TILE_LENGTH;
|
static const int YAPF_INFINITE_PENALTY = 1000 * YAPF_TILE_LENGTH;
|
||||||
|
|
||||||
/** Maximum length of ship path cache */
|
|
||||||
static const int YAPF_SHIP_PATH_CACHE_LENGTH = 32;
|
|
||||||
|
|
||||||
/** Distance from destination road stops to not cache any further */
|
/** Distance from destination road stops to not cache any further */
|
||||||
static const int YAPF_ROADVEH_PATH_CACHE_DESTINATION_LIMIT = 8;
|
static const int YAPF_ROADVEH_PATH_CACHE_DESTINATION_LIMIT = 8;
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ public:
|
|||||||
uint steps = 0;
|
uint steps = 0;
|
||||||
for (Node *n = pNode; n->m_parent != nullptr; n = n->m_parent) steps++;
|
for (Node *n = pNode; n->m_parent != nullptr; n = n->m_parent) steps++;
|
||||||
uint skip = 0;
|
uint skip = 0;
|
||||||
if (path_found) skip = YAPF_SHIP_PATH_CACHE_LENGTH / 2;
|
if (path_found) skip = SHIP_PATH_CACHE_LENGTH / 2;
|
||||||
|
|
||||||
/* walk through the path back to the origin */
|
/* walk through the path back to the origin */
|
||||||
Node *pPrevNode = nullptr;
|
Node *pPrevNode = nullptr;
|
||||||
@ -181,7 +181,7 @@ public:
|
|||||||
steps--;
|
steps--;
|
||||||
/* Skip tiles at end of path near destination. */
|
/* Skip tiles at end of path near destination. */
|
||||||
if (skip > 0) skip--;
|
if (skip > 0) skip--;
|
||||||
if (skip == 0 && steps > 0 && steps < YAPF_SHIP_PATH_CACHE_LENGTH) {
|
if (skip == 0 && steps > 0 && steps < SHIP_PATH_CACHE_LENGTH) {
|
||||||
path_cache.push_front(pNode->GetTrackdir());
|
path_cache.push_front(pNode->GetTrackdir());
|
||||||
}
|
}
|
||||||
pPrevNode = pNode;
|
pPrevNode = pNode;
|
||||||
|
@ -293,7 +293,7 @@ public:
|
|||||||
inline static const SaveLoad description[] = {
|
inline static const SaveLoad description[] = {
|
||||||
SLEG_STRUCT("common", SlVehicleCommon),
|
SLEG_STRUCT("common", SlVehicleCommon),
|
||||||
SLE_VAR(Ship, state, SLE_UINT8),
|
SLE_VAR(Ship, state, SLE_UINT8),
|
||||||
SLE_CONDDEQUE(Ship, path, SLE_UINT8, SLV_SHIP_PATH_CACHE, SL_MAX_VERSION),
|
SLEG_CONDVECTOR("path", _path_td, SLE_UINT8, SLV_SHIP_PATH_CACHE, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR(Ship, rotation, SLE_UINT8, SLV_SHIP_ROTATION, SL_MAX_VERSION),
|
SLE_CONDVAR(Ship, rotation, SLE_UINT8, SLV_SHIP_ROTATION, SL_MAX_VERSION),
|
||||||
};
|
};
|
||||||
inline const static SaveLoadCompatTable compat_description = _vehicle_ship_sl_compat;
|
inline const static SaveLoadCompatTable compat_description = _vehicle_ship_sl_compat;
|
||||||
@ -308,6 +308,16 @@ public:
|
|||||||
{
|
{
|
||||||
if (v->type != VEH_SHIP) return;
|
if (v->type != VEH_SHIP) return;
|
||||||
SlObject(v, this->GetLoadDescription());
|
SlObject(v, this->GetLoadDescription());
|
||||||
|
|
||||||
|
if (!_path_td.empty() && _path_td.size() <= SHIP_PATH_CACHE_LENGTH) {
|
||||||
|
Ship *s = Ship::From(v);
|
||||||
|
s->cached_path.reset(new ShipPathCache());
|
||||||
|
s->cached_path->count = _path_td.size();
|
||||||
|
for (size_t i = 0; i < _path_td.size(); i++) {
|
||||||
|
s->cached_path->td[i] = _path_td[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_path_td.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FixPointers(Vehicle *v) const override
|
void FixPointers(Vehicle *v) const override
|
||||||
|
@ -1709,7 +1709,7 @@ static void MaxVehiclesChanged(int32 new_value)
|
|||||||
static void InvalidateShipPathCache(int32 new_value)
|
static void InvalidateShipPathCache(int32 new_value)
|
||||||
{
|
{
|
||||||
for (Ship *s : Ship::Iterate()) {
|
for (Ship *s : Ship::Iterate()) {
|
||||||
s->path.clear();
|
s->cached_path.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
53
src/ship.h
53
src/ship.h
@ -10,7 +10,7 @@
|
|||||||
#ifndef SHIP_H
|
#ifndef SHIP_H
|
||||||
#define SHIP_H
|
#define SHIP_H
|
||||||
|
|
||||||
#include <deque>
|
#include <array>
|
||||||
|
|
||||||
#include "vehicle_base.h"
|
#include "vehicle_base.h"
|
||||||
#include "water_map.h"
|
#include "water_map.h"
|
||||||
@ -20,14 +20,55 @@ extern const DiagDirection _ship_search_directions[TRACK_END][DIAGDIR_END];
|
|||||||
void GetShipSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type);
|
void GetShipSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type);
|
||||||
WaterClass GetEffectiveWaterClass(TileIndex tile);
|
WaterClass GetEffectiveWaterClass(TileIndex tile);
|
||||||
|
|
||||||
typedef std::deque<Trackdir> ShipPathCache;
|
/** Maximum segments of ship path cache */
|
||||||
|
static const uint8 SHIP_PATH_CACHE_LENGTH = 32;
|
||||||
|
static const uint8 SHIP_PATH_CACHE_MASK = (SHIP_PATH_CACHE_LENGTH - 1);
|
||||||
|
static_assert((SHIP_PATH_CACHE_LENGTH & SHIP_PATH_CACHE_MASK) == 0, ""); // Must be a power of 2
|
||||||
|
|
||||||
|
struct ShipPathCache {
|
||||||
|
std::array<Trackdir, SHIP_PATH_CACHE_LENGTH> td;
|
||||||
|
uint8 start = 0;
|
||||||
|
uint8 count = 0;
|
||||||
|
|
||||||
|
inline bool empty() const { return this->count == 0; }
|
||||||
|
inline uint8 size() const { return this->count; }
|
||||||
|
inline bool full() const { return this->count >= SHIP_PATH_CACHE_LENGTH; }
|
||||||
|
|
||||||
|
inline void clear()
|
||||||
|
{
|
||||||
|
this->start = 0;
|
||||||
|
this->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Trackdir front() const { return this->td[this->start]; }
|
||||||
|
inline Trackdir back() const { return this->td[(this->start + this->count - 1) & SHIP_PATH_CACHE_MASK]; }
|
||||||
|
|
||||||
|
/* push an item to the front of the ring, if the ring is already full, the back item is overwritten */
|
||||||
|
inline void push_front(Trackdir td)
|
||||||
|
{
|
||||||
|
this->start = (this->start - 1) & SHIP_PATH_CACHE_MASK;
|
||||||
|
if (!this->full()) this->count++;
|
||||||
|
this->td[this->start] = td;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void pop_front()
|
||||||
|
{
|
||||||
|
this->start = (this->start + 1) & SHIP_PATH_CACHE_MASK;
|
||||||
|
this->count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void pop_back()
|
||||||
|
{
|
||||||
|
this->count--;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All ships have this type.
|
* All ships have this type.
|
||||||
*/
|
*/
|
||||||
struct Ship FINAL : public SpecializedVehicle<Ship, VEH_SHIP> {
|
struct Ship FINAL : public SpecializedVehicle<Ship, VEH_SHIP> {
|
||||||
TrackBits state; ///< The "track" the ship is following.
|
TrackBits state; ///< The "track" the ship is following.
|
||||||
ShipPathCache path; ///< Cached path.
|
std::unique_ptr<ShipPathCache> cached_path; ///< Cached path.
|
||||||
Direction rotation; ///< Visible direction.
|
Direction rotation; ///< Visible direction.
|
||||||
int16 rotation_x_pos; ///< NOSAVE: X Position before rotation.
|
int16 rotation_x_pos; ///< NOSAVE: X Position before rotation.
|
||||||
int16 rotation_y_pos; ///< NOSAVE: Y Position before rotation.
|
int16 rotation_y_pos; ///< NOSAVE: Y Position before rotation.
|
||||||
@ -61,6 +102,12 @@ struct Ship FINAL : public SpecializedVehicle<Ship, VEH_SHIP> {
|
|||||||
ClosestDepot FindClosestDepot() override;
|
ClosestDepot FindClosestDepot() override;
|
||||||
void UpdateCache();
|
void UpdateCache();
|
||||||
void SetDestTile(TileIndex tile) override;
|
void SetDestTile(TileIndex tile) override;
|
||||||
|
|
||||||
|
inline ShipPathCache &GetOrCreatePathCache()
|
||||||
|
{
|
||||||
|
if (!this->cached_path) this->cached_path.reset(new ShipPathCache());
|
||||||
|
return *this->cached_path;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool IsShipDestinationTile(TileIndex tile, StationID station);
|
bool IsShipDestinationTile(TileIndex tile, StationID station);
|
||||||
|
@ -567,22 +567,22 @@ static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, Tr
|
|||||||
path_found = false;
|
path_found = false;
|
||||||
} else {
|
} else {
|
||||||
/* Attempt to follow cached path. */
|
/* Attempt to follow cached path. */
|
||||||
if (!v->path.empty()) {
|
if (v->cached_path != nullptr && !v->cached_path->empty()) {
|
||||||
track = TrackdirToTrack(v->path.front());
|
track = TrackdirToTrack(v->cached_path->front());
|
||||||
|
|
||||||
if (HasBit(tracks, track)) {
|
if (HasBit(tracks, track)) {
|
||||||
v->path.pop_front();
|
v->cached_path->pop_front();
|
||||||
/* HandlePathfindResult() is not called here because this is not a new pathfinder result. */
|
/* HandlePathfindResult() is not called here because this is not a new pathfinder result. */
|
||||||
return track;
|
return track;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cached path is invalid so continue with pathfinder. */
|
/* Cached path is invalid so continue with pathfinder. */
|
||||||
v->path.clear();
|
v->cached_path->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_settings_game.pf.pathfinder_for_ships) {
|
switch (_settings_game.pf.pathfinder_for_ships) {
|
||||||
case VPF_NPF: track = NPFShipChooseTrack(v, path_found); break;
|
case VPF_NPF: track = NPFShipChooseTrack(v, path_found); break;
|
||||||
case VPF_YAPF: track = YapfShipChooseTrack(v, tile, enterdir, tracks, path_found, v->path); break;
|
case VPF_YAPF: track = YapfShipChooseTrack(v, tile, enterdir, tracks, path_found, v->GetOrCreatePathCache()); break;
|
||||||
default: NOT_REACHED();
|
default: NOT_REACHED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -882,7 +882,7 @@ static void ReverseShipIntoTrackdir(Ship *v, Trackdir trackdir)
|
|||||||
v->rotation_x_pos = v->x_pos;
|
v->rotation_x_pos = v->x_pos;
|
||||||
v->rotation_y_pos = v->y_pos;
|
v->rotation_y_pos = v->y_pos;
|
||||||
UpdateShipSpeed(v, 0);
|
UpdateShipSpeed(v, 0);
|
||||||
v->path.clear();
|
if (v->cached_path != nullptr) v->cached_path->clear();
|
||||||
|
|
||||||
v->UpdatePosition();
|
v->UpdatePosition();
|
||||||
v->UpdateViewport(true, true);
|
v->UpdateViewport(true, true);
|
||||||
@ -896,7 +896,7 @@ static void ReverseShip(Ship *v)
|
|||||||
v->rotation_x_pos = v->x_pos;
|
v->rotation_x_pos = v->x_pos;
|
||||||
v->rotation_y_pos = v->y_pos;
|
v->rotation_y_pos = v->y_pos;
|
||||||
UpdateShipSpeed(v, 0);
|
UpdateShipSpeed(v, 0);
|
||||||
v->path.clear();
|
if (v->cached_path != nullptr) v->cached_path->clear();
|
||||||
|
|
||||||
v->UpdatePosition();
|
v->UpdatePosition();
|
||||||
v->UpdateViewport(true, true);
|
v->UpdateViewport(true, true);
|
||||||
@ -1081,7 +1081,7 @@ static void ShipController(Ship *v)
|
|||||||
|
|
||||||
/* Ship is back on the bridge head, we need to consume its path
|
/* Ship is back on the bridge head, we need to consume its path
|
||||||
* cache entry here as we didn't have to choose a ship track. */
|
* cache entry here as we didn't have to choose a ship track. */
|
||||||
if (!v->path.empty()) v->path.pop_front();
|
if (v->cached_path != nullptr && !v->cached_path->empty()) v->cached_path->pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update image of ship, as well as delta XY */
|
/* update image of ship, as well as delta XY */
|
||||||
@ -1107,7 +1107,7 @@ bool Ship::Tick()
|
|||||||
void Ship::SetDestTile(TileIndex tile)
|
void Ship::SetDestTile(TileIndex tile)
|
||||||
{
|
{
|
||||||
if (tile == this->dest_tile) return;
|
if (tile == this->dest_tile) return;
|
||||||
this->path.clear();
|
if (this->cached_path != nullptr) this->cached_path->clear();
|
||||||
this->dest_tile = tile;
|
this->dest_tile = tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -877,7 +877,7 @@ SaveLoadTable GetVehicleDescription(VehicleType vt)
|
|||||||
SLE_WRITEBYTE(Vehicle, type),
|
SLE_WRITEBYTE(Vehicle, type),
|
||||||
SLE_VEH_INCLUDE(),
|
SLE_VEH_INCLUDE(),
|
||||||
SLE_VAR(Ship, state, SLE_UINT8),
|
SLE_VAR(Ship, state, SLE_UINT8),
|
||||||
SLE_CONDDEQUE(Ship, path, SLE_UINT8, SLV_SHIP_PATH_CACHE, SL_MAX_VERSION),
|
SLEG_CONDVARVEC(_path_td, SLE_UINT8, SLV_SHIP_PATH_CACHE, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR(Ship, rotation, SLE_UINT8, SLV_SHIP_ROTATION, SL_MAX_VERSION),
|
SLE_CONDVAR(Ship, rotation, SLE_UINT8, SLV_SHIP_ROTATION, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR_X(Ship, lost_count, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SHIP_LOST_COUNTER)),
|
SLE_CONDVAR_X(Ship, lost_count, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SHIP_LOST_COUNTER)),
|
||||||
SLE_CONDVAR_X(Ship, critical_breakdown_count, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_IMPROVED_BREAKDOWNS, 8)),
|
SLE_CONDVAR_X(Ship, critical_breakdown_count, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_IMPROVED_BREAKDOWNS, 8)),
|
||||||
@ -1043,6 +1043,17 @@ static void Save_VEHS()
|
|||||||
}
|
}
|
||||||
_path_layout_ctr = rv->cached_path->layout_ctr;
|
_path_layout_ctr = rv->cached_path->layout_ctr;
|
||||||
}
|
}
|
||||||
|
} else if (v->type == VEH_SHIP) {
|
||||||
|
_path_td.clear();
|
||||||
|
|
||||||
|
Ship *s = Ship::From(v);
|
||||||
|
if (s->cached_path != nullptr && !s->cached_path->empty()) {
|
||||||
|
uint idx = s->cached_path->start;
|
||||||
|
for (uint i = 0; i < s->cached_path->size(); i++) {
|
||||||
|
_path_td.push_back(s->cached_path->td[idx]);
|
||||||
|
idx = (idx + 1) & SHIP_PATH_CACHE_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SlSetArrayIndex(v->index);
|
SlSetArrayIndex(v->index);
|
||||||
SlObjectSaveFiltered(v, GetVehicleDescriptionFiltered(v->type));
|
SlObjectSaveFiltered(v, GetVehicleDescriptionFiltered(v->type));
|
||||||
@ -1123,6 +1134,13 @@ void Load_VEHS()
|
|||||||
rv->cached_path->tile[i] = _path_tile[i];
|
rv->cached_path->tile[i] = _path_tile[i];
|
||||||
}
|
}
|
||||||
rv->cached_path->layout_ctr = _path_layout_ctr;
|
rv->cached_path->layout_ctr = _path_layout_ctr;
|
||||||
|
} else if (vtype == VEH_SHIP && !_path_td.empty() && _path_td.size() <= SHIP_PATH_CACHE_LENGTH) {
|
||||||
|
Ship *s = Ship::From(v);
|
||||||
|
s->cached_path.reset(new ShipPathCache());
|
||||||
|
s->cached_path->count = _path_td.size();
|
||||||
|
for (size_t i = 0; i < _path_td.size(); i++) {
|
||||||
|
s->cached_path->td[i] = _path_td[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user