Compare commits

...

5 Commits

Author SHA1 Message Date
Zac 528fd61a81
Merge c1256d8211 into bf8de188ec 2024-04-27 00:36:58 +02:00
Peter Nelson bf8de188ec
Codechange: Use member initialization of GRFFilePropsBase. (#12581)
Don't blame compilers for our sloppy initialisation.

Removes memset, and lengthof.
2024-04-26 22:58:54 +01:00
Peter Nelson 72c55128d2
Codechange: Remove write-only spec_id from RoadStopSpec. (#12582)
Comment is incorrect about its value too.
2024-04-26 21:56:30 +01:00
Peter Nelson a6d401debf
Fix: Properly test for presence of waypoint in NewGRF resolver. (#12579)
Test whether the BaseStation itself a Station or Waypoint, instead of by the station class ID assigned to it.
2024-04-26 17:47:53 +01:00
zacc c1256d8211 Change: [RoadStop] For DriveThroughRoadStop, calculate the occupied level based on actual vehicles on the tile. 2024-04-23 23:06:37 +09:00
9 changed files with 84 additions and 121 deletions

View File

@ -4846,7 +4846,6 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, ByteR
uint32_t classid = buf->ReadDWord();
rs->cls_id = RoadStopClass::Allocate(BSWAP32(classid));
rs->spec_id = id + i;
break;
}

View File

@ -308,25 +308,15 @@ bool Convert8bitBooleanCallback(const struct GRFFile *grffile, uint16_t cbid, ui
*/
template <size_t Tcnt>
struct GRFFilePropsBase {
GRFFilePropsBase() : local_id(0), grffile(nullptr)
{
/* The lack of some compilers to provide default constructors complying to the specs
* requires us to zero the stuff ourself. */
memset(spritegroup, 0, sizeof(spritegroup));
}
uint16_t local_id; ///< id defined by the grf file for this entity
const struct GRFFile *grffile; ///< grf file that introduced this entity
const struct SpriteGroup *spritegroup[Tcnt]; ///< pointer to the different sprites of the entity
uint16_t local_id = 0; ///< id defined by the grf file for this entity
const struct GRFFile *grffile = nullptr; ///< grf file that introduced this entity
std::array<const struct SpriteGroup *, Tcnt> spritegroup{}; ///< pointers to the different sprites of the entity
};
/** Data related to the handling of grf files. */
struct GRFFileProps : GRFFilePropsBase<1> {
/** Set all default data constructor for the props. */
GRFFileProps(uint16_t subst_id = 0) :
GRFFilePropsBase<1>(), subst_id(subst_id), override(subst_id)
{
}
constexpr GRFFileProps(uint16_t subst_id = 0) : subst_id(subst_id), override(subst_id) {}
uint16_t subst_id;
uint16_t override; ///< id of the entity been replaced by

View File

@ -53,7 +53,7 @@ const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoID cargo, Eng
void SetCustomEngineSprites(EngineID engine, uint8_t cargo, const SpriteGroup *group)
{
Engine *e = Engine::Get(engine);
assert(cargo < lengthof(e->grf_prop.spritegroup));
assert(cargo < std::size(e->grf_prop.spritegroup));
if (e->grf_prop.spritegroup[cargo] != nullptr) {
GrfMsg(6, "SetCustomEngineSprites: engine {} cargo {} already has group -- replacing", engine, cargo);
@ -1062,7 +1062,7 @@ VehicleResolverObject::VehicleResolverObject(EngineID engine_type, const Vehicle
if (this->root_spritegroup == nullptr) {
const Engine *e = Engine::Get(engine_type);
CargoID cargo = v != nullptr ? v->cargo_type : SpriteGroupCargo::SG_PURCHASE;
assert(cargo < lengthof(e->grf_prop.spritegroup));
assert(cargo < std::size(e->grf_prop.spritegroup));
this->root_spritegroup = e->grf_prop.spritegroup[cargo] != nullptr ? e->grf_prop.spritegroup[cargo] : e->grf_prop.spritegroup[SpriteGroupCargo::SG_DEFAULT];
}
}

View File

@ -127,7 +127,6 @@ struct RoadStopSpec {
*/
GRFFilePropsBase<NUM_CARGO + 3> grf_prop;
RoadStopClassID cls_id; ///< The class to which this spec belongs.
int spec_id; ///< The ID of this spec inside the class.
StringID name; ///< Name of this stop
RoadStopAvailabilityType stop_type = ROADSTOPTYPE_ALL;

View File

@ -504,7 +504,7 @@ uint32_t Waypoint::GetNewGRFVariable(const ResolverObject &, uint8_t variable, [
/* virtual */ const SpriteGroup *StationResolverObject::ResolveReal(const RealSpriteGroup *group) const
{
if (this->station_scope.st == nullptr || this->station_scope.statspec->cls_id == STAT_CLASS_WAYP) {
if (this->station_scope.st == nullptr || !Station::IsExpected(this->station_scope.st)) {
return group->loading[0];
}

View File

@ -368,7 +368,7 @@ static int32_t NPFRoadPathCost(AyStar *, AyStarNode *current, OpenListNode *)
/* When we're the first road stop in a 'queue' of them we increase
* cost based on the fill percentage of the whole queue. */
const RoadStop::Entry *entry = rs->GetEntry(dir);
cost += entry->GetOccupied() * _settings_game.pf.npf.npf_road_dt_occupied_penalty / entry->GetLength();
cost += entry->GetOccupied(rs, dir) * _settings_game.pf.npf.npf_road_dt_occupied_penalty / entry->GetLength();
}
} else {
/* Increase cost for filled road stops */

View File

@ -75,11 +75,11 @@ protected:
/* Increase the cost for drive-through road stops */
cost += Yapf().PfGetSettings().road_stop_penalty;
DiagDirection dir = TrackdirToExitdir(trackdir);
if (!RoadStop::IsDriveThroughRoadStopContinuation(tile, tile - TileOffsByDiagDir(dir))) {
/* When we're the first road stop in a 'queue' of them we increase
* cost based on the fill percentage of the whole queue. */
if (Yapf().PfDetectDestinationTile(tile, trackdir)){
/* We've found the destination file so get the occupied
* level from the Entry object. */
const RoadStop::Entry *entry = rs->GetEntry(dir);
cost += entry->GetOccupied() * Yapf().PfGetSettings().road_stop_occupied_penalty / entry->GetLength();
cost += entry->GetOccupied(rs, dir) * Yapf().PfGetSettings().road_stop_occupied_penalty / entry->GetLength();
}
} else {
/* Increase cost for filled road stops */

View File

@ -88,8 +88,6 @@ void RoadStop::MakeDriveThrough()
if (south && rs_south->east != nullptr) { // (east != nullptr) == (west != nullptr)
/* There more southern tiles too, they must 'join' us too */
ClrBit(rs_south->status, RSSFB_BASE_ENTRY);
this->east->occupied += rs_south->east->occupied;
this->west->occupied += rs_south->west->occupied;
/* Free the now unneeded entry structs */
delete rs_south->east;
@ -175,12 +173,7 @@ void RoadStop::ClearDriveThrough()
rs_north = RoadStop::GetByTile(north_tile, rst);
}
/* We have to rebuild the entries because we cannot easily determine
* how full each part is. So instead of keeping and maintaining a list
* of vehicles and using that to 'rebuild' the occupied state we just
* rebuild it from scratch as that removes lots of maintenance code
* for the vehicle list and it's faster in real games as long as you
* do not keep split and merge road stop every tick by the millions. */
/* We have to rebuild the entries to determine the length of the roadstop. */
rs_south_base->east->Rebuild(rs_south_base);
rs_south_base->west->Rebuild(rs_south_base);
@ -219,9 +212,6 @@ void RoadStop::Leave(RoadVehicle *rv)
/* Vehicle is leaving a road stop tile, mark bay as free */
this->FreeBay(HasBit(rv->state, RVS_USING_SECOND_BAY));
this->SetEntranceBusy(false);
} else {
/* Otherwise just leave the drive through's entry cache. */
this->GetEntry(DirToDiagDir(rv->direction))->Leave(rv);
}
}
@ -248,9 +238,6 @@ bool RoadStop::Enter(RoadVehicle *rv)
return true;
}
/* Vehicles entering a drive-through stop from the 'normal' side use first bay (bay 0). */
this->GetEntry(DirToDiagDir(rv->direction))->Enter(rv);
/* Indicate a drive-through stop */
SetBit(rv->state, RVS_IN_DT_ROAD_STOP);
return true;
@ -273,28 +260,6 @@ bool RoadStop::Enter(RoadVehicle *rv)
}
}
/**
* Leave the road stop
* @param rv the vehicle that leaves the stop
*/
void RoadStop::Entry::Leave(const RoadVehicle *rv)
{
this->occupied -= rv->gcache.cached_total_length;
assert(this->occupied >= 0);
}
/**
* Enter the road stop
* @param rv the vehicle that enters the stop
*/
void RoadStop::Entry::Enter(const RoadVehicle *rv)
{
/* we cannot assert on this->occupied < this->length because of the
* remote possibility that RVs are running through each other when
* trying to prevention an infinite jam. */
this->occupied += rv->gcache.cached_total_length;
}
/**
* Checks whether the 'next' tile is still part of the road same drive through
* stop 'rs' in the same direction for the same vehicle.
@ -311,67 +276,88 @@ void RoadStop::Entry::Enter(const RoadVehicle *rv)
IsDriveThroughStopTile(next);
}
typedef std::list<const RoadVehicle *> RVList; ///< A list of road vehicles
/** Helper for finding RVs in a road stop. */
struct RoadStopEntryRebuilderHelper {
RVList vehicles; ///< The list of vehicles to possibly add to.
DiagDirection dir; ///< The direction the vehicle has to face to be added.
};
/**
* Add road vehicles to the station's list if needed.
* @param v the found vehicle
* @param data the extra data used to make our decision
* @return always nullptr
*/
Vehicle *FindVehiclesInRoadStop(Vehicle *v, void *data)
{
RoadStopEntryRebuilderHelper *rserh = (RoadStopEntryRebuilderHelper*)data;
/* Not a RV or not in the right direction or crashed :( */
if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != rserh->dir || !v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) return nullptr;
RoadVehicle *rv = RoadVehicle::From(v);
/* Don't add ones not in a road stop */
if (rv->state < RVSB_IN_ROAD_STOP) return nullptr;
/* Do not add duplicates! */
for (const auto &it : rserh->vehicles) {
if (rv == it) return nullptr;
}
rserh->vehicles.push_back(rv);
return nullptr;
}
/**
* Rebuild, from scratch, the vehicles and other metadata on this stop.
* @param rs the roadstop this entry is part of
* @param side the side of the road stop to look at
*/
void RoadStop::Entry::Rebuild(const RoadStop *rs, int side)
void RoadStop::Entry::Rebuild(const RoadStop *rs)
{
assert(HasBit(rs->status, RSSFB_BASE_ENTRY));
DiagDirection dir = GetRoadStopDir(rs->xy);
if (side == -1) side = (rs->east == this);
RoadStopEntryRebuilderHelper rserh;
rserh.dir = side ? dir : ReverseDiagDir(dir);
this->length = 0;
TileIndexDiff offset = abs(TileOffsByDiagDir(dir));
for (TileIndex tile = rs->xy; IsDriveThroughRoadStopContinuation(rs->xy, tile); tile += offset) {
this->length += TILE_SIZE;
FindVehicleOnPos(tile, &rserh, FindVehiclesInRoadStop);
}
this->occupied = 0;
for (const auto &it : rserh.vehicles) {
this->occupied += it->gcache.cached_total_length;
}
}
struct TileDataHelper
{
TileIndex tile; ///< The tile we are working on.
DiagDirection dir; ///< The direction the tile is oriented following Trackdir.
uint free = TILE_SIZE;
};
/* Find the amount of free space in this tile, measured from the direction of entry. */
Vehicle *FindTileFreeSpace(Vehicle *v, void *data)
{
TileDataHelper *tdh = (TileDataHelper*)data;
/* Exclude if not a RV, not travelling in the Trackdir direction */
if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != tdh->dir) return nullptr;
RoadVehicle *rv = RoadVehicle::From(v);
uint veh_pos = DiagDirToAxis(tdh->dir) == AXIS_X ? rv->x_pos : rv->y_pos;
uint tile_pos = DiagDirToAxis(tdh->dir) == AXIS_X ? TileX(tdh->tile) : TileY(tdh->tile);
uint tile_free_space = TILE_SIZE;
switch (tdh->dir) {
case DIAGDIR_NE:
case DIAGDIR_NW:
tile_free_space = veh_pos % tile_pos < TILE_SIZE / 2 ? TILE_SIZE / 2 : 0;
tdh->free = std::min(tdh->free, tile_free_space);
break;
case DIAGDIR_SE:
case DIAGDIR_SW:
tile_free_space = veh_pos % tile_pos < TILE_SIZE / 2 ? 0 : TILE_SIZE / 2;
tdh->free = std::min(tdh->free, tile_free_space);
break;
default:
return nullptr;
}
return nullptr;
}
/**
* Get the amount of occupied space in this drive through stop.
* @param rs the roadstop this entry is part of
* @return the occupied space in tile units.
*/
int RoadStop::Entry::GetOccupied(const RoadStop *rs, const DiagDirection dir) const
{
const RoadStop::Entry *entry = rs->GetEntry(dir);
TileDataHelper tdh;
tdh.dir = dir;
int free = 0;
TileIndexDiff offset = TileOffsByDiagDir(dir);
for (TileIndex tile = rs->xy; RoadStop::IsDriveThroughRoadStopContinuation(rs->xy, tile); tile += offset) {
tdh.tile = tile;
FindVehicleOnPos(tile, &tdh, FindTileFreeSpace);
free += tdh.free;
// Tile contains a vehicle - no need to keep calculating.
if (tdh.free < TILE_SIZE) break;
};
return entry->GetLength() - free;
}
/**
* Check the integrity of the data in this struct.
@ -385,6 +371,6 @@ void RoadStop::Entry::CheckIntegrity(const RoadStop *rs) const
assert(!IsDriveThroughRoadStopContinuation(rs->xy, rs->xy - abs(TileOffsByDiagDir(GetRoadStopDir(rs->xy)))));
Entry temp;
temp.Rebuild(rs, rs->east == this);
if (temp.length != this->length || temp.occupied != this->occupied) NOT_REACHED();
temp.Rebuild(rs);
if (temp.length != this->length) NOT_REACHED();
}

View File

@ -32,13 +32,12 @@ struct RoadStop : RoadStopPool::PoolItem<&_roadstop_pool> {
struct Entry {
private:
int length; ///< The length of the stop in tile 'units'
int occupied; ///< The amount of occupied stop in tile 'units'
public:
friend struct RoadStop; ///< Oh yeah, the road stop may play with me.
/** Create an entry */
Entry() : length(0), occupied(0) {}
Entry() : length(0) {}
/**
* Get the length of this drive through stop.
@ -49,19 +48,9 @@ struct RoadStop : RoadStopPool::PoolItem<&_roadstop_pool> {
return this->length;
}
/**
* Get the amount of occupied space in this drive through stop.
* @return the occupied space in tile units.
*/
inline int GetOccupied() const
{
return this->occupied;
}
void Leave(const RoadVehicle *rv);
void Enter(const RoadVehicle *rv);
int GetOccupied(const RoadStop *rs, const DiagDirection dir) const;
void CheckIntegrity(const RoadStop *rs) const;
void Rebuild(const RoadStop *rs, int side = -1);
void Rebuild(const RoadStop *rs);
};
TileIndex xy; ///< Position on the map