1
0
Fork 0

Codechange: Replace FindVehicleOnPos with 'for' loop.

pull/14082/head
frosch 2025-04-22 15:54:43 +02:00 committed by frosch
parent 06c399b79e
commit 2bee313642
12 changed files with 144 additions and 288 deletions

View File

@ -355,15 +355,6 @@ public:
return 0; return 0;
} }
static Vehicle *CountShipProc(Vehicle *v, void *data)
{
uint *count = (uint*)data;
/* Ignore other vehicles (aircraft) and ships inside depot. */
if (v->type == VEH_SHIP && !v->vehstatus.Test(VehState::Hidden)) (*count)++;
return nullptr;
}
/** /**
* Called by YAPF to calculate the cost from the origin to the given node. * Called by YAPF to calculate the cost from the origin to the given node.
* Calculates only the cost of given node, adds it to the parent node cost * Calculates only the cost of given node, adds it to the parent node cost
@ -378,8 +369,10 @@ public:
if (IsDockingTile(n.GetTile())) { if (IsDockingTile(n.GetTile())) {
/* Check docking tile for occupancy. */ /* Check docking tile for occupancy. */
uint count = 0; uint count = std::ranges::count_if(VehiclesOnTile(n.GetTile()), [](const Vehicle *v) {
FindVehicleOnPos(n.GetTile(), &count, &CountShipProc); /* Ignore other vehicles (aircraft) and ships inside depot. */
return v->type == VEH_SHIP && !v->vehstatus.Test(VehState::Hidden);
});
c += count * 3 * YAPF_TILE_LENGTH; c += count * 3 * YAPF_TILE_LENGTH;
} }

View File

@ -259,23 +259,20 @@ struct FindTrainOnTrackInfo {
FindTrainOnTrackInfo() : best(nullptr) {} FindTrainOnTrackInfo() : best(nullptr) {}
}; };
/** Callback for Has/FindVehicleOnPos to find a train on a specific track. */ /** Find the best matching vehicle on a tile. */
static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data) static void CheckTrainsOnTrack(FindTrainOnTrackInfo &info, TileIndex tile)
{ {
FindTrainOnTrackInfo *info = (FindTrainOnTrackInfo *)data; for (Vehicle *v : VehiclesOnTile(tile)) {
if (v->type != VEH_TRAIN || v->vehstatus.Test(VehState::Crashed)) continue;
if (v->type != VEH_TRAIN || v->vehstatus.Test(VehState::Crashed)) return nullptr; Train *t = Train::From(v);
if (t->track == TRACK_BIT_WORMHOLE || HasBit(static_cast<TrackBits>(t->track), TrackdirToTrack(info.res.trackdir))) {
t = t->First();
Train *t = Train::From(v); /* ALWAYS return the lowest ID (anti-desync!) */
if (t->track == TRACK_BIT_WORMHOLE || HasBit((TrackBits)t->track, TrackdirToTrack(info->res.trackdir))) { if (info.best == nullptr || t->index < info.best->index) info.best = t;
t = t->First(); }
/* ALWAYS return the lowest ID (anti-desync!) */
if (info->best == nullptr || t->index < info->best->index) info->best = t;
return t;
} }
return nullptr;
} }
/** /**
@ -298,7 +295,7 @@ PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->railtype)->compatible_railtypes, tile, trackdir); ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->railtype)->compatible_railtypes, tile, trackdir);
ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg); ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg);
if (train_on_res != nullptr) { if (train_on_res != nullptr) {
FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum); CheckTrainsOnTrack(ftoti, ftoti.res.tile);
if (ftoti.best != nullptr) *train_on_res = ftoti.best->First(); if (ftoti.best != nullptr) *train_on_res = ftoti.best->First();
if (*train_on_res == nullptr && IsRailStationTile(ftoti.res.tile)) { if (*train_on_res == nullptr && IsRailStationTile(ftoti.res.tile)) {
/* The target tile is a rail station. The track follower /* The target tile is a rail station. The track follower
@ -307,13 +304,13 @@ PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
* for a possible train. */ * for a possible train. */
TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir))); TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
for (TileIndex st_tile = ftoti.res.tile + diff; *train_on_res == nullptr && IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) { for (TileIndex st_tile = ftoti.res.tile + diff; *train_on_res == nullptr && IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum); CheckTrainsOnTrack(ftoti, st_tile);
if (ftoti.best != nullptr) *train_on_res = ftoti.best->First(); if (ftoti.best != nullptr) *train_on_res = ftoti.best->First();
} }
} }
if (*train_on_res == nullptr && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) { if (*train_on_res == nullptr && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
/* The target tile is a bridge/tunnel, also check the other end tile. */ /* The target tile is a bridge/tunnel, also check the other end tile. */
FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum); CheckTrainsOnTrack(ftoti, GetOtherTunnelBridgeEnd(ftoti.res.tile));
if (ftoti.best != nullptr) *train_on_res = ftoti.best->First(); if (ftoti.best != nullptr) *train_on_res = ftoti.best->First();
} }
} }
@ -345,21 +342,21 @@ Train *GetTrainForReservation(TileIndex tile, Track track)
FindTrainOnTrackInfo ftoti; FindTrainOnTrackInfo ftoti;
ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true); ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true);
FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum); CheckTrainsOnTrack(ftoti, ftoti.res.tile);
if (ftoti.best != nullptr) return ftoti.best; if (ftoti.best != nullptr) return ftoti.best;
/* Special case for stations: check the whole platform for a vehicle. */ /* Special case for stations: check the whole platform for a vehicle. */
if (IsRailStationTile(ftoti.res.tile)) { if (IsRailStationTile(ftoti.res.tile)) {
TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir))); TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) { for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum); CheckTrainsOnTrack(ftoti, st_tile);
if (ftoti.best != nullptr) return ftoti.best; if (ftoti.best != nullptr) return ftoti.best;
} }
} }
/* Special case for bridges/tunnels: check the other end as well. */ /* Special case for bridges/tunnels: check the other end as well. */
if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) { if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum); CheckTrainsOnTrack(ftoti, GetOtherTunnelBridgeEnd(ftoti.res.tile));
if (ftoti.best != nullptr) return ftoti.best; if (ftoti.best != nullptr) return ftoti.best;
} }
} }

View File

@ -1528,17 +1528,6 @@ CommandCost CmdRemoveSignalTrack(DoCommandFlags flags, TileIndex tile, TileIndex
return CmdSignalTrackHelper(flags, tile, end_tile, track, SIGTYPE_BLOCK, SIG_ELECTRIC, false, true, autofill, false, 1); // bit 5 is remove bit return CmdSignalTrackHelper(flags, tile, end_tile, track, SIGTYPE_BLOCK, SIG_ELECTRIC, false, true, autofill, false, 1); // bit 5 is remove bit
} }
/** Update power of train under which is the railtype being converted */
static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
{
if (v->type != VEH_TRAIN) return nullptr;
TrainList *affected_trains = static_cast<TrainList*>(data);
include(*affected_trains, Train::From(v)->First());
return nullptr;
}
/** /**
* Convert one rail type to the other. You can convert normal rail to * Convert one rail type to the other. You can convert normal rail to
* monorail/maglev easily or vice-versa. * monorail/maglev easily or vice-versa.
@ -1640,7 +1629,9 @@ CommandCost CmdConvertRail(DoCommandFlags flags, TileIndex tile, TileIndex area_
SetRailType(tile, totype); SetRailType(tile, totype);
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
/* update power of train on this tile */ /* update power of train on this tile */
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc); for (Vehicle *v : VehiclesOnTile(tile)) {
if (v->type == VEH_TRAIN) include(affected_trains, Train::From(v)->First());
}
} }
} }
@ -1717,8 +1708,12 @@ CommandCost CmdConvertRail(DoCommandFlags flags, TileIndex tile, TileIndex area_
SetRailType(tile, totype); SetRailType(tile, totype);
SetRailType(endtile, totype); SetRailType(endtile, totype);
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc); for (Vehicle *v : VehiclesOnTile(tile)) {
FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc); if (v->type == VEH_TRAIN) include(affected_trains, Train::From(v)->First());
}
for (Vehicle *v : VehiclesOnTile(endtile)) {
if (v->type == VEH_TRAIN) include(affected_trains, Train::From(v)->First());
}
YapfNotifyTrackLayoutChange(tile, track); YapfNotifyTrackLayoutChange(tile, track);
YapfNotifyTrackLayoutChange(endtile, track); YapfNotifyTrackLayoutChange(endtile, track);

View File

@ -2370,17 +2370,6 @@ static CommandCost TerraformTile_Road(TileIndex tile, DoCommandFlags flags, int
return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile); return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
} }
/** Update power of road vehicle under which is the roadtype being converted */
static Vehicle *UpdateRoadVehPowerProc(Vehicle *v, void *data)
{
if (v->type != VEH_ROAD) return nullptr;
RoadVehicleList *affected_rvs = static_cast<RoadVehicleList*>(data);
include(*affected_rvs, RoadVehicle::From(v)->First());
return nullptr;
}
/** /**
* Checks the tile and returns whether the current player is allowed to convert the roadtype to another roadtype without taking ownership * Checks the tile and returns whether the current player is allowed to convert the roadtype to another roadtype without taking ownership
* @param owner the tile owner. * @param owner the tile owner.
@ -2538,7 +2527,9 @@ CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
/* update power of train on this tile */ /* update power of train on this tile */
FindVehicleOnPos(tile, &affected_rvs, &UpdateRoadVehPowerProc); for (Vehicle *v : VehiclesOnTile(tile)) {
if (v->type == VEH_ROAD) include(affected_rvs, RoadVehicle::From(v)->First());
}
if (IsRoadDepotTile(tile)) { if (IsRoadDepotTile(tile)) {
/* Update build vehicle window related to this depot */ /* Update build vehicle window related to this depot */
@ -2595,8 +2586,12 @@ CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_
SetRoadType(tile, rtt, to_type); SetRoadType(tile, rtt, to_type);
SetRoadType(endtile, rtt, to_type); SetRoadType(endtile, rtt, to_type);
FindVehicleOnPos(tile, &affected_rvs, &UpdateRoadVehPowerProc); for (Vehicle *v : VehiclesOnTile(tile)) {
FindVehicleOnPos(endtile, &affected_rvs, &UpdateRoadVehPowerProc); if (v->type == VEH_ROAD) include(affected_rvs, RoadVehicle::From(v)->First());
}
for (Vehicle *v : VehiclesOnTile(endtile)) {
if (v->type == VEH_ROAD) include(affected_rvs, RoadVehicle::From(v)->First());
}
if (IsBridge(tile)) { if (IsBridge(tile)) {
MarkBridgeDirty(tile); MarkBridgeDirty(tile);

View File

@ -10,6 +10,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "roadveh.h" #include "roadveh.h"
#include "core/pool_func.hpp" #include "core/pool_func.hpp"
#include "core/container_func.hpp"
#include "roadstop_base.h" #include "roadstop_base.h"
#include "station_base.h" #include "station_base.h"
#include "vehicle_func.h" #include "vehicle_func.h"
@ -309,39 +310,6 @@ void RoadStop::Entry::Enter(const RoadVehicle *rv)
GetDriveThroughStopAxis(next) == GetDriveThroughStopAxis(rs); GetDriveThroughStopAxis(next) == GetDriveThroughStopAxis(rs);
} }
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.Test(VehState::Crashed)) 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;
}
/** /**
* Get the DiagDirection for entering the drive through stop from the given 'side' (east or west) on the given axis. * Get the DiagDirection for entering the drive through stop from the given 'side' (east or west) on the given axis.
* @param east Enter from the east when true or from the west when false. * @param east Enter from the east when true or from the west when false.
@ -369,18 +337,27 @@ void RoadStop::Entry::Rebuild(const RoadStop *rs, int side)
Axis axis = GetDriveThroughStopAxis(rs->xy); Axis axis = GetDriveThroughStopAxis(rs->xy);
if (side == -1) side = (rs->east == this); if (side == -1) side = (rs->east == this);
RoadStopEntryRebuilderHelper rserh; auto entry_dir = GetEntryDirection(side, axis);
rserh.dir = GetEntryDirection(side, axis); std::vector<const RoadVehicle *> vehicles;
this->length = 0; this->length = 0;
TileIndexDiff offset = TileOffsByAxis(axis); TileIndexDiff offset = TileOffsByAxis(axis);
for (TileIndex tile = rs->xy; IsDriveThroughRoadStopContinuation(rs->xy, tile); tile += offset) { for (TileIndex tile = rs->xy; IsDriveThroughRoadStopContinuation(rs->xy, tile); tile += offset) {
this->length += TILE_SIZE; this->length += TILE_SIZE;
FindVehicleOnPos(tile, &rserh, FindVehiclesInRoadStop); for (const Vehicle *v : VehiclesOnTile(tile)) {
/* Not a RV or not in the right direction or crashed :( */
if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != entry_dir || !v->IsPrimaryVehicle() || v->vehstatus.Test(VehState::Crashed)) continue;
const RoadVehicle *rv = RoadVehicle::From(v);
/* Don't add ones not in a road stop */
if (rv->state < RVSB_IN_ROAD_STOP) continue;
include(vehicles, rv);
}
} }
this->occupied = 0; this->occupied = 0;
for (const auto &it : rserh.vehicles) { for (const auto &it : vehicles) {
this->occupied += it->gcache.cached_total_length; this->occupied += it->gcache.cached_total_length;
} }
} }

View File

@ -659,8 +659,12 @@ static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction d
rvf.best_diff = UINT_MAX; rvf.best_diff = UINT_MAX;
if (front->state == RVSB_WORMHOLE) { if (front->state == RVSB_WORMHOLE) {
FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose); for (Vehicle *u : VehiclesOnTile(v->tile)) {
FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose); EnumCheckRoadVehClose(u, &rvf);
}
for (Vehicle *u : VehiclesOnTile(GetOtherTunnelBridgeEnd(v->tile))) {
EnumCheckRoadVehClose(u, &rvf);
}
} else { } else {
FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose); FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose);
} }

View File

@ -2108,24 +2108,6 @@ CommandCost CmdBuildRoadStop(DoCommandFlags flags, TileIndex tile, uint8_t width
return cost; return cost;
} }
static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *)
{
if (v->type == VEH_ROAD) {
/* Okay... we are a road vehicle on a drive through road stop.
* But that road stop has just been removed, so we need to make
* sure we are in a valid state... however, vehicles can also
* turn on road stop tiles, so only clear the 'road stop' state
* bits and only when the state was 'in road stop', otherwise
* we'll end up clearing the turn around bits. */
RoadVehicle *rv = RoadVehicle::From(v);
if (HasBit(rv->state, RVS_IN_DT_ROAD_STOP)) rv->state &= RVSB_ROAD_STOP_TRACKDIR_MASK;
}
return nullptr;
}
/** /**
* Remove a bus station/truck stop * Remove a bus station/truck stop
* @param tile TileIndex been queried * @param tile TileIndex been queried
@ -2159,7 +2141,19 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlags flags, int repl
/* don't do the check for drive-through road stops when company bankrupts */ /* don't do the check for drive-through road stops when company bankrupts */
if (IsDriveThroughStopTile(tile) && flags.Test(DoCommandFlag::Bankrupt)) { if (IsDriveThroughStopTile(tile) && flags.Test(DoCommandFlag::Bankrupt)) {
/* remove the 'going through road stop' status from all vehicles on that tile */ /* remove the 'going through road stop' status from all vehicles on that tile */
if (flags.Test(DoCommandFlag::Execute)) FindVehicleOnPos(tile, nullptr, &ClearRoadStopStatusEnum); if (flags.Test(DoCommandFlag::Execute)) {
for (Vehicle *v : VehiclesOnTile(tile)) {
if (v->type != VEH_ROAD) continue;
/* Okay... we are a road vehicle on a drive through road stop.
* But that road stop has just been removed, so we need to make
* sure we are in a valid state... however, vehicles can also
* turn on road stop tiles, so only clear the 'road stop' state
* bits and only when the state was 'in road stop', otherwise
* we'll end up clearing the turn around bits. */
RoadVehicle *rv = RoadVehicle::From(v);
if (HasBit(rv->state, RVS_IN_DT_ROAD_STOP)) rv->state &= RVSB_ROAD_STOP_TRACKDIR_MASK;
}
}
} else { } else {
CommandCost ret = EnsureNoVehicleOnGround(tile); CommandCost ret = EnsureNoVehicleOnGround(tile);
if (ret.Failed()) return ret; if (ret.Failed()) return ret;

View File

@ -3234,8 +3234,12 @@ static bool CheckTrainCollision(Train *v)
/* find colliding vehicles */ /* find colliding vehicles */
if (v->track == TRACK_BIT_WORMHOLE) { if (v->track == TRACK_BIT_WORMHOLE) {
FindVehicleOnPos(v->tile, &tcc, FindTrainCollideEnum); for (Vehicle *u : VehiclesOnTile(v->tile)) {
FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum); FindTrainCollideEnum(u, &tcc);
}
for (Vehicle *u : VehiclesOnTile(GetOtherTunnelBridgeEnd(v->tile))) {
FindTrainCollideEnum(u, &tcc);
}
} else { } else {
FindVehicleOnPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum); FindVehicleOnPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum);
} }
@ -3582,29 +3586,6 @@ reverse_train_direction:
return false; return false;
} }
/**
* Collect trackbits of all crashed train vehicles on a tile
* @param v Vehicle passed from Find/HasVehicleOnPos()
* @param data trackdirbits for the result
* @return nullptr to iterate over all vehicles on the tile.
*/
static Vehicle *CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data)
{
TrackBits *trackbits = (TrackBits *)data;
if (v->type == VEH_TRAIN && v->vehstatus.Test(VehState::Crashed)) {
TrackBits train_tbits = Train::From(v)->track;
if (train_tbits == TRACK_BIT_WORMHOLE) {
/* Vehicle is inside a wormhole, v->track contains no useful value then. */
*trackbits |= DiagDirToDiagTrackBits(GetTunnelBridgeDirection(v->tile));
} else if (train_tbits != TRACK_BIT_DEPOT) {
*trackbits |= train_tbits;
}
}
return nullptr;
}
static bool IsRailStationPlatformOccupied(TileIndex tile) static bool IsRailStationPlatformOccupied(TileIndex tile)
{ {
TileIndexDiff delta = TileOffsByAxis(GetRailStationAxis(tile)); TileIndexDiff delta = TileOffsByAxis(GetRailStationAxis(tile));
@ -3631,11 +3612,11 @@ static void DeleteLastWagon(Train *v)
Train *first = v->First(); Train *first = v->First();
/* Go to the last wagon and delete the link pointing there /* Go to the last wagon and delete the link pointing there
* *u is then the one-before-last wagon, and *v the last * new_last is then the one-before-last wagon, and v the last
* one which will physically be removed */ * one which will physically be removed */
Train *u = v; Train *new_last = v;
for (; v->Next() != nullptr; v = v->Next()) u = v; for (; v->Next() != nullptr; v = v->Next()) new_last = v;
u->SetNext(nullptr); new_last->SetNext(nullptr);
if (first != v) { if (first != v) {
/* Recalculate cached train properties */ /* Recalculate cached train properties */
@ -3667,7 +3648,16 @@ static void DeleteLastWagon(Train *v)
/* If there are still crashed vehicles on the tile, give the track reservation to them */ /* If there are still crashed vehicles on the tile, give the track reservation to them */
TrackBits remaining_trackbits = TRACK_BIT_NONE; TrackBits remaining_trackbits = TRACK_BIT_NONE;
FindVehicleOnPos(tile, &remaining_trackbits, CollectTrackbitsFromCrashedVehiclesEnum); for (const Vehicle *u : VehiclesOnTile(tile)) {
if (u->type != VEH_TRAIN || !u->vehstatus.Test(VehState::Crashed)) continue;
TrackBits train_tbits = Train::From(u)->track;
if (train_tbits == TRACK_BIT_WORMHOLE) {
/* Vehicle is inside a wormhole, u->track contains no useful value then. */
remaining_trackbits |= DiagDirToDiagTrackBits(GetTunnelBridgeDirection(u->tile));
} else if (train_tbits != TRACK_BIT_DEPOT) {
remaining_trackbits |= train_tbits;
}
}
/* It is important that these two are the first in the loop, as reservation cannot deal with every trackbit combination */ /* It is important that these two are the first in the loop, as reservation cannot deal with every trackbit combination */
assert(TRACK_BEGIN == TRACK_X && TRACK_Y == TRACK_BEGIN + 1); assert(TRACK_BEGIN == TRACK_X && TRACK_Y == TRACK_BEGIN + 1);

View File

@ -500,66 +500,6 @@ void VehiclesOnTile::Iterator::SkipFalseMatches()
while (this->current != nullptr && this->current->tile != this->tile) this->Increment(); while (this->current != nullptr && this->current->tile != this->tile) this->Increment();
} }
/**
* Helper function for FindVehicleOnPos/HasVehicleOnPos.
* @note Do not call this function directly!
* @param tile The location on the map
* @param data Arbitrary data passed to \a proc.
* @param proc The proc that determines whether a vehicle will be "found".
* @param find_first Whether to return on the first found or iterate over
* all vehicles
* @return the best matching or first vehicle (depending on find_first).
*/
static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
{
int x = GB(TileX(tile), HASH_RES, HASH_BITS);
int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
for (; v != nullptr; v = v->hash_tile_next) {
if (v->tile != tile) continue;
Vehicle *a = proc(v, data);
if (find_first && a != nullptr) return a;
}
return nullptr;
}
/**
* Find a vehicle from a specific location. It will call \a proc for ALL vehicles
* on the tile and YOU must make SURE that the "best one" is stored in the
* data value and is ALWAYS the same regardless of the order of the vehicles
* where proc was called on!
* When you fail to do this properly you create an almost untraceable DESYNC!
* @note The return value of \a proc will be ignored.
* @note Use this function when you have the intention that all vehicles
* should be iterated over.
* @param tile The location on the map
* @param data Arbitrary data passed to \a proc.
* @param proc The proc that determines whether a vehicle will be "found".
*/
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
{
VehicleFromPos(tile, data, proc, false);
}
/**
* Callback that returns 'real' vehicles lower or at height \c *(int*)data .
* @param v Vehicle to examine.
* @param data Pointer to height data.
* @return \a v if conditions are met, else \c nullptr.
*/
static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
{
int z = *(int*)data;
if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return nullptr;
if (v->z_pos > z) return nullptr;
return v;
}
/** /**
* Ensure there is no vehicle at the ground at the given position. * Ensure there is no vehicle at the ground at the given position.
* @param tile Position to examine. * @param tile Position to examine.
@ -573,20 +513,15 @@ CommandCost EnsureNoVehicleOnGround(TileIndex tile)
* error message only (which may be different for different machines). * error message only (which may be different for different machines).
* Such a message does not affect MP synchronisation. * Such a message does not affect MP synchronisation.
*/ */
Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true); for (const Vehicle *v : VehiclesOnTile(tile)) {
if (v != nullptr) return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type); if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) continue;
if (v->z_pos > z) continue;
return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
}
return CommandCost(); return CommandCost();
} }
/** Procedure called for every vehicle found in tunnel/bridge in the hash map */
static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
{
if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return nullptr;
if (v == (const Vehicle *)data) return nullptr;
return v;
}
/** /**
* Finds vehicle in tunnel / bridge * Finds vehicle in tunnel / bridge
* @param tile first end * @param tile first end
@ -596,29 +531,20 @@ static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
*/ */
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore) CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
{ {
/* Value v is not safe in MP games, however, it is used to generate a local for (TileIndex t : {tile, endtile}) {
* error message only (which may be different for different machines). /* Value v is not safe in MP games, however, it is used to generate a local
* Such a message does not affect MP synchronisation. * error message only (which may be different for different machines).
*/ * Such a message does not affect MP synchronisation.
Vehicle *v = VehicleFromPos(tile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true); */
if (v == nullptr) v = VehicleFromPos(endtile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true); for (const Vehicle *v : VehiclesOnTile(t)) {
if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) continue;
if (v != nullptr) return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type); if (v == ignore) continue;
return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
}
}
return CommandCost(); return CommandCost();
} }
static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
{
TrackBits rail_bits = *(TrackBits *)data;
if (v->type != VEH_TRAIN) return nullptr;
Train *t = Train::From(v);
if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return nullptr;
return v;
}
/** /**
* Tests if a vehicle interacts with the specified track bits. * Tests if a vehicle interacts with the specified track bits.
* All track bits interact except parallel #TRACK_BIT_HORZ or #TRACK_BIT_VERT. * All track bits interact except parallel #TRACK_BIT_HORZ or #TRACK_BIT_VERT.
@ -633,8 +559,14 @@ CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
* error message only (which may be different for different machines). * error message only (which may be different for different machines).
* Such a message does not affect MP synchronisation. * Such a message does not affect MP synchronisation.
*/ */
Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true); for (const Vehicle *v : VehiclesOnTile(tile)) {
if (v != nullptr) return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type); if (v->type != VEH_TRAIN) continue;
const Train *t = Train::From(v);
if ((t->track != track_bits) && !TracksOverlap(t->track | track_bits)) continue;
return CommandCost(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
}
return CommandCost(); return CommandCost();
} }

View File

@ -115,7 +115,6 @@ typedef Vehicle *VehicleFromPosProc(Vehicle *v, void *data);
void VehicleServiceInDepot(Vehicle *v); void VehicleServiceInDepot(Vehicle *v);
uint CountVehiclesInChain(const Vehicle *v); uint CountVehiclesInChain(const Vehicle *v);
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc); void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc);
bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc); bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc);
void CallVehicleTicks(); void CallVehicleTicks();

View File

@ -32,39 +32,6 @@ WindowNumber VehicleListIdentifier::ToWindowNumber() const
return c << 28 | this->type << 23 | this->vtype << 26 | this->index; return c << 28 | this->type << 23 | this->vtype << 26 | this->index;
} }
/** Data for building a depot vehicle list. */
struct BuildDepotVehicleListData
{
VehicleList *engines; ///< Pointer to list to add vehicles to.
VehicleList *wagons; ///< Pointer to list to add wagons to (can be nullptr).
VehicleType type; ///< Type of vehicle.
bool individual_wagons; ///< If true add every wagon to \a wagons which is not attached to an engine. If false only add the first wagon of every row.
};
/**
* Add vehicles to a depot vehicle list.
* @param v The found vehicle.
* @param data The depot vehicle list data.
* @return Always nullptr.
*/
static Vehicle *BuildDepotVehicleListProc(Vehicle *v, void *data)
{
auto bdvld = static_cast<BuildDepotVehicleListData *>(data);
if (v->type != bdvld->type || !v->IsInDepot()) return nullptr;
if (bdvld->type == VEH_TRAIN) {
const Train *t = Train::From(v);
if (t->IsArticulatedPart() || t->IsRearDualheaded()) return nullptr;
if (bdvld->wagons != nullptr && t->First()->IsFreeWagon()) {
if (bdvld->individual_wagons || t->IsFreeWagon()) bdvld->wagons->push_back(t);
return nullptr;
}
}
if (v->IsPrimaryVehicle()) bdvld->engines->push_back(v);
return nullptr;
};
/** /**
* Generate a list of vehicles inside a depot. * Generate a list of vehicles inside a depot.
* @param type Type of vehicle * @param type Type of vehicle
@ -78,8 +45,20 @@ void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engine
engines->clear(); engines->clear();
if (wagons != nullptr && wagons != engines) wagons->clear(); if (wagons != nullptr && wagons != engines) wagons->clear();
BuildDepotVehicleListData bdvld{engines, wagons, type, individual_wagons}; for (Vehicle *v : VehiclesOnTile(tile)) {
FindVehicleOnPos(tile, &bdvld, BuildDepotVehicleListProc); if (v->type != type || !v->IsInDepot()) continue;
if (type == VEH_TRAIN) {
const Train *t = Train::From(v);
if (t->IsArticulatedPart() || t->IsRearDualheaded()) continue;
if (wagons != nullptr && t->First()->IsFreeWagon()) {
if (individual_wagons || t->IsFreeWagon()) wagons->push_back(t);
continue;
}
}
if (v->IsPrimaryVehicle()) engines->push_back(v);
}
} }
/** /**

View File

@ -1012,12 +1012,11 @@ static void FloodVehicle(Vehicle *v)
/** /**
* Flood a vehicle if we are allowed to flood it, i.e. when it is on the ground. * Flood a vehicle if we are allowed to flood it, i.e. when it is on the ground.
* @param v The vehicle to test for flooding. * @param v The vehicle to test for flooding.
* @param data The z of level to flood. * @param z The z of level to flood.
* @return nullptr as we always want to remove everything.
*/ */
static Vehicle *FloodVehicleProc(Vehicle *v, void *data) static void FloodVehicleProc(Vehicle *v, int z)
{ {
if (v->vehstatus.Test(VehState::Crashed)) return nullptr; if (v->vehstatus.Test(VehState::Crashed)) return;
switch (v->type) { switch (v->type) {
default: break; default: break;
@ -1038,14 +1037,18 @@ static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
case VEH_TRAIN: case VEH_TRAIN:
case VEH_ROAD: { case VEH_ROAD: {
int z = *(int*)data;
if (v->z_pos > z) break; if (v->z_pos > z) break;
FloodVehicle(v->First()); FloodVehicle(v->First());
break; break;
} }
} }
}
return nullptr; static void FloodVehiclesOnTile(TileIndex tile, int z)
{
for (Vehicle *v : VehiclesOnTile(tile)) {
FloodVehicleProc(v, z);
}
} }
/** /**
@ -1055,12 +1058,10 @@ static Vehicle *FloodVehicleProc(Vehicle *v, void *data)
*/ */
static void FloodVehicles(TileIndex tile) static void FloodVehicles(TileIndex tile)
{ {
int z = 0;
if (IsAirportTile(tile)) { if (IsAirportTile(tile)) {
const Station *st = Station::GetByTile(tile); const Station *st = Station::GetByTile(tile);
for (TileIndex airport_tile : st->airport) { for (TileIndex airport_tile : st->airport) {
if (st->TileBelongsToAirport(airport_tile)) FindVehicleOnPos(airport_tile, &z, &FloodVehicleProc); if (st->TileBelongsToAirport(airport_tile)) FloodVehiclesOnTile(airport_tile, 0);
} }
/* No vehicle could be flooded on this airport anymore */ /* No vehicle could be flooded on this airport anymore */
@ -1068,15 +1069,15 @@ static void FloodVehicles(TileIndex tile)
} }
if (!IsBridgeTile(tile)) { if (!IsBridgeTile(tile)) {
FindVehicleOnPos(tile, &z, &FloodVehicleProc); FloodVehiclesOnTile(tile, 0);
return; return;
} }
TileIndex end = GetOtherBridgeEnd(tile); TileIndex end = GetOtherBridgeEnd(tile);
z = GetBridgePixelHeight(tile); int z = GetBridgePixelHeight(tile);
FindVehicleOnPos(tile, &z, &FloodVehicleProc); FloodVehiclesOnTile(tile, z);
FindVehicleOnPos(end, &z, &FloodVehicleProc); FloodVehiclesOnTile(end, z);
} }
/** /**