diff --git a/src/core/pool_type.hpp b/src/core/pool_type.hpp index c430b908af..20c5f848b5 100644 --- a/src/core/pool_type.hpp +++ b/src/core/pool_type.hpp @@ -117,12 +117,17 @@ struct Pool : PoolBase { Pool(const char *name); void CleanPool() override; - inline PtrType GetRaw(size_t index) + inline PtrType &GetRawRef(size_t index) { dbg_assert_msg(index < this->first_unused, "index: " PRINTF_SIZE ", first_unused: " PRINTF_SIZE ", name: %s", index, this->first_unused, this->name); return this->data[index]; } + inline PtrType GetRaw(size_t index) + { + return this->GetRawRef(index); + } + /** * Returns Titem with given index * @param index of item to get diff --git a/src/departures_gui.cpp b/src/departures_gui.cpp index 02d99c311e..d7311949eb 100644 --- a/src/departures_gui.cpp +++ b/src/departures_gui.cpp @@ -164,7 +164,7 @@ protected: CompanyMask companies = 0; int unitnumber_max[4] = { -1, -1, -1, -1 }; - for (const Vehicle *v : Vehicle::Iterate()) { + for (const Vehicle *v : Vehicle::IterateFrontOnly()) { if (v->type < 4 && this->show_types[v->type] && v->IsPrimaryVehicle()) { for(const Order *order : v->Orders()) { if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT)) diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp index 2a1bf034a5..9539384590 100644 --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -368,7 +368,7 @@ static bool DisasterTick_Ufo(DisasterVehicle *v) } n = RandomRange(n); // Choose one of them. - for (const RoadVehicle *u : RoadVehicle::Iterate()) { + for (const RoadVehicle *u : RoadVehicle::IterateFrontOnly()) { /* Find (n+1)-th road vehicle. */ if (u->IsFrontEngine() && (n-- == 0)) { if (u->crashed_ctr != 0 || !SetDisasterVehicleTargetingVehicle(u->index, v->index)) { diff --git a/src/economy.cpp b/src/economy.cpp index 57b96f8991..ca3397398f 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -236,7 +236,7 @@ int UpdateCompanyRatingAndValue(Company *c, bool update) bool min_profit_first = true; uint num = 0; - for (const Vehicle *v : Vehicle::Iterate()) { + for (const Vehicle *v : Vehicle::IterateFrontOnly()) { if (v->owner != owner) continue; if (IsCompanyBuildableVehicleType(v->type) && v->IsPrimaryVehicle() && !HasBit(v->subtype, GVSF_VIRTUAL)) { if (v->profit_last_year > 0) num++; // For the vehicle score only count profitable vehicles diff --git a/src/elrail.cpp b/src/elrail.cpp index 4a39b11f0f..30d55f3a6e 100644 --- a/src/elrail.cpp +++ b/src/elrail.cpp @@ -731,7 +731,7 @@ void SettingsDisableElrail(int32_t new_value) } /* Fix the total power and acceleration for trains */ - for (Train *t : Train::Iterate()) { + for (Train *t : Train::IterateFrontOnly()) { /* power and acceleration is cached only for front engines */ if (t->IsFrontEngine()) { t->ConsistChanged(CCF_TRACK); diff --git a/src/group_cmd.cpp b/src/group_cmd.cpp index f19732e81d..a09d52afa7 100644 --- a/src/group_cmd.cpp +++ b/src/group_cmd.cpp @@ -220,7 +220,7 @@ uint16_t GroupStatistics::GetNumEngines(EngineID engine) const g->statistics.ClearProfits(); } - for (const Vehicle *v : Vehicle::Iterate()) { + for (const Vehicle *v : Vehicle::IterateFrontOnly()) { if (v->IsPrimaryVehicle() && !HasBit(v->subtype, GVSF_VIRTUAL)) { GroupStatistics::AddProfitLastYear(v); if (v->age > VEHICLE_PROFIT_MIN_AGE) GroupStatistics::VehicleReachedMinAge(v); @@ -333,7 +333,7 @@ void IterateDescendantsOfGroup(GroupID id_top, F func) static void PropagateChildLiveryResetVehicleCache(const Group *g) { /* Company colour data is indirectly cached. */ - for (Vehicle *v : Vehicle::Iterate()) { + for (Vehicle *v : Vehicle::IterateFrontOnly()) { if (v->IsPrimaryVehicle() && (v->group_id == g->index || IsGroupIDDescendantOfGroupID(v->group_id, g->index, g->owner))) { for (Vehicle *u = v; u != nullptr; u = u->Next()) { u->colourmap = PAL_NONE; @@ -823,7 +823,7 @@ CommandCost CmdAddSharedVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 if (flags & DC_EXEC) { /* Find the first front engine which belong to the group id_g * then add all shared vehicles of this front engine to the group id_g */ - for (const Vehicle *v : Vehicle::IterateType(type)) { + for (const Vehicle *v : Vehicle::IterateTypeFrontOnly(type)) { if (v->IsPrimaryVehicle()) { if (v->group_id != id_g) continue; @@ -860,7 +860,7 @@ CommandCost CmdRemoveAllVehiclesGroup(TileIndex tile, DoCommandFlag flags, uint3 if (flags & DC_EXEC) { /* Find each Vehicle that belongs to the group old_g and add it to the default group */ - for (const Vehicle *v : Vehicle::Iterate()) { + for (const Vehicle *v : Vehicle::IterateFrontOnly()) { if (v->IsPrimaryVehicle()) { if (v->group_id != old_g) continue; diff --git a/src/infrastructure.cpp b/src/infrastructure.cpp index f8a5341dd5..6fc6da4a6a 100644 --- a/src/infrastructure.cpp +++ b/src/infrastructure.cpp @@ -206,7 +206,7 @@ static void FixAllReservations() { /* if this function is called, we can safely assume that sharing of rails is being switched off */ assert(!_settings_game.economy.infrastructure_sharing[VEH_TRAIN]); - for (Train *v : Train::Iterate()) { + for (Train *v : Train::IterateFrontOnly()) { if (!v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0 || HasBit(v->subtype, GVSF_VIRTUAL)) continue; /* It might happen that the train reserved additional tracks, * but FollowTrainReservation can't detect those because they are no longer reachable. @@ -254,9 +254,8 @@ bool CheckSharingChangePossible(VehicleType type, bool new_value) }); StringID error_message = STR_NULL; - for (Vehicle *v : Vehicle::IterateType(type)) { + for (Vehicle *v : Vehicle::IterateTypeFrontOnly(type)) { if (HasBit(v->subtype, GVSF_VIRTUAL)) continue; - if (v->Previous() != nullptr) continue; /* Check vehicle positiion */ if (!VehiclePositionIsAllowed(v)) { @@ -280,7 +279,7 @@ bool CheckSharingChangePossible(VehicleType type, bool new_value) } if (type == VEH_TRAIN && _settings_game.vehicle.train_braking_model == TBM_REALISTIC) { - for (Train *v : Train::Iterate()) { + for (Train *v : Train::IterateFrontOnly()) { if (!v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0 || HasBit(v->subtype, GVSF_VIRTUAL)) continue; /* It might happen that the train reserved additional tracks, * but FollowTrainReservation can't detect those because they are no longer reachable. @@ -329,9 +328,9 @@ void HandleSharingCompanyDeletion(Owner owner) Vehicle *si_v = nullptr; SCOPE_INFO_FMT([&si_v], "HandleSharingCompanyDeletion: veh: %s", scope_dumper().VehicleInfo(si_v)); - for (Vehicle *v : Vehicle::Iterate()) { + for (Vehicle *v : Vehicle::IterateFrontOnly()) { si_v = v; - if (!IsCompanyBuildableVehicleType(v) || v->Previous() != nullptr) continue; + if (!IsCompanyBuildableVehicleType(v)) continue; /* vehicle position */ if (v->owner == owner || !VehiclePositionIsAllowed(v, owner)) { RemoveAndSellVehicle(v, v->owner != owner); diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 65a0106b98..8f14867e36 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -1759,7 +1759,7 @@ void NetworkPopulateCompanyStats(NetworkCompanyStats *stats) memset(stats, 0, sizeof(*stats) * MAX_COMPANIES); /* Go through all vehicles and count the type of vehicles */ - for (const Vehicle *v : Vehicle::Iterate()) { + for (const Vehicle *v : Vehicle::IterateFrontOnly()) { if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle() || HasBit(v->subtype, GVSF_VIRTUAL)) continue; byte type = 0; switch (v->type) { diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index ea7a967408..027401e030 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -66,9 +66,9 @@ CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID s void IntialiseOrderDestinationRefcountMap() { ClearOrderDestinationRefcountMap(); - for (const Vehicle *v : Vehicle::Iterate()) { + for (const Vehicle *v : Vehicle::IterateFrontOnly()) { if (v != v->FirstShared()) continue; - for(const Order *order : v->Orders()) { + for (const Order *order : v->Orders()) { if (order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT)) { _order_destination_refcount_map[OrderDestinationRefcountMapKey(order->GetDestination(), v->owner, order->GetType(), v->type)]++; } @@ -2933,7 +2933,7 @@ void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool */ /* Go through all vehicles */ - for (Vehicle *v : Vehicle::Iterate()) { + for (Vehicle *v : Vehicle::IterateFrontOnly()) { Order *order = &v->current_order; if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) && !hangar ? OT_GOTO_STATION : order->GetType()) == type && (!hangar || v->type == VEH_AIRCRAFT) && order->GetDestination() == destination) { @@ -3786,7 +3786,7 @@ CommandCost CmdMassChangeOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, DestinationID to_dest = GB(p2, 0, 16); if (flags & DC_EXEC) { - for (Vehicle *v : Vehicle::IterateType(vehtype)) { + for (Vehicle *v : Vehicle::IterateTypeFrontOnly(vehtype)) { if (v->IsPrimaryVehicle() && CheckOwnership(v->owner).Succeeded() && VehicleCargoFilter(v, cargo_filter)) { int index = 0; bool changed = false; diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 5580b2d0b2..27ccb178ed 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -203,7 +203,7 @@ bool RoadVehiclesAreBuilt() */ bool RoadVehiclesExistOutsideDepots() { - for (const RoadVehicle *rv : RoadVehicle::Iterate()) { + for (const RoadVehicle *rv : RoadVehicle::IterateFrontOnly()) { if (rv->IsFrontEngine() && !rv->IsChainInDepot()) return true; } return false; diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 88436783f8..34205b0e09 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -308,10 +308,8 @@ static void InitializeWindowsAndCaches() it->tile = t->xy; } } - for (RoadVehicle *rv : RoadVehicle::Iterate()) { - if (rv->IsFrontEngine()) { - rv->CargoChanged(); - } + for (RoadVehicle *rv : RoadVehicle::IterateFrontOnly()) { + rv->CargoChanged(); } RecomputePrices(); @@ -1735,7 +1733,7 @@ bool AfterLoadGame() } } - for (Train *v : Train::Iterate()) { + for (Train *v : Train::IterateFrontOnly()) { if (v->IsFrontEngine() || v->IsFreeWagon()) v->ConsistChanged(CCF_TRACK); } @@ -2370,8 +2368,8 @@ bool AfterLoadGame() GroupStatistics::UpdateAfterLoad(); // Ensure statistics pool is initialised before trying to delete vehicles /* Remove all trams from savegames without tram support. * There would be trams without tram track under causing crashes sooner or later. */ - for (RoadVehicle *v : RoadVehicle::Iterate()) { - if (v->First() == v && HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM)) { + for (RoadVehicle *v : RoadVehicle::IterateFrontOnly()) { + if (HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM)) { ShowErrorMessage(STR_WARNING_LOADGAME_REMOVED_TRAMS, INVALID_STRING_ID, WL_CRITICAL); delete v; } @@ -2466,8 +2464,8 @@ bool AfterLoadGame() /* Reserve all tracks trains are currently on. */ if (IsSavegameVersionBefore(SLV_101)) { - for (const Train *t : Train::Iterate()) { - if (t->First() == t) t->ReserveTrackUnderConsist(); + for (const Train *t : Train::IterateFrontOnly()) { + t->ReserveTrackUnderConsist(); } } @@ -3196,7 +3194,7 @@ bool AfterLoadGame() } /* Fill Vehicle::cur_real_order_index */ - for (Vehicle *v : Vehicle::Iterate()) { + for (Vehicle *v : Vehicle::IterateFrontOnly()) { if (!v->IsPrimaryVehicle()) continue; /* Older versions are less strict with indices being in range and fix them on the fly */ @@ -3501,7 +3499,7 @@ bool AfterLoadGame() * So, make articulated parts catch up. */ bool roadside = _settings_game.vehicle.road_side == 1; std::vector skip_frames; - for (RoadVehicle *v : RoadVehicle::Iterate()) { + for (RoadVehicle *v : RoadVehicle::IterateFrontOnly()) { if (!v->IsFrontEngine()) continue; skip_frames.clear(); TileIndex prev_tile = v->tile; @@ -3706,7 +3704,7 @@ bool AfterLoadGame() } if (!IsSavegameVersionBefore(SLV_DEPOT_UNBUNCHING)) { - for (Vehicle *v : Vehicle::Iterate()) { + for (Vehicle *v : Vehicle::IterateFrontOnly()) { if (v->unbunch_state != nullptr) { if (v->unbunch_state->depot_unbunching_last_departure > 0) { v->unbunch_state->depot_unbunching_last_departure += _state_ticks.base() - _tick_counter; @@ -4217,7 +4215,7 @@ bool AfterLoadGame() } if (!SlXvIsFeaturePresent(XSLFI_REALISTIC_TRAIN_BRAKING, 5) && _settings_game.vehicle.train_braking_model == TBM_REALISTIC) { - for (Train *t : Train::Iterate()) { + for (Train *t : Train::IterateFrontOnly()) { if (t->lookahead != nullptr) { t->lookahead->SetNextExtendPosition(); } @@ -4225,7 +4223,7 @@ bool AfterLoadGame() } if (!SlXvIsFeaturePresent(XSLFI_REALISTIC_TRAIN_BRAKING, 6) && _settings_game.vehicle.train_braking_model == TBM_REALISTIC) { - for (Train *t : Train::Iterate()) { + for (Train *t : Train::IterateFrontOnly()) { if (t->lookahead != nullptr) { t->lookahead->cached_zpos = t->CalculateOverallZPos(); t->lookahead->zpos_refresh_remaining = t->GetZPosCacheUpdateInterval(); @@ -4366,7 +4364,7 @@ bool AfterLoadGame() } if (!SlXvIsFeaturePresent(XSLFI_REALISTIC_TRAIN_BRAKING, 9) && _settings_game.vehicle.train_braking_model == TBM_REALISTIC) { - for (Train *t : Train::Iterate()) { + for (Train *t : Train::IterateFrontOnly()) { if (t->lookahead != nullptr) { t->lookahead->lookahead_end_position = t->lookahead->reservation_end_position + 1; } diff --git a/src/script/api/script_group.cpp b/src/script/api/script_group.cpp index 859888b4ee..bd66bfa919 100644 --- a/src/script/api/script_group.cpp +++ b/src/script/api/script_group.cpp @@ -180,7 +180,7 @@ Money profit = 0; - for (const Vehicle *v : Vehicle::Iterate()) { + for (const Vehicle *v : Vehicle::IterateFrontOnly()) { if (v->group_id != group_id) continue; if (!v->IsPrimaryVehicle()) continue; @@ -204,7 +204,7 @@ uint32_t occupancy = 0; uint32_t vehicle_count = 0; - for (const Vehicle *v : Vehicle::Iterate()) { + for (const Vehicle *v : Vehicle::IterateFrontOnly()) { if (v->group_id != group_id) continue; if (!v->IsPrimaryVehicle()) continue; diff --git a/src/settings.cpp b/src/settings.cpp index b061a21032..228c018b3e 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1141,7 +1141,7 @@ static void StationSpreadChanged(int32_t new_value) static void UpdateConsists(int32_t new_value) { - for (Train *t : Train::Iterate()) { + for (Train *t : Train::IterateFrontOnly()) { /* Update the consist of all trains so the maximum speed is set correctly. */ if (t->IsFrontEngine() || t->IsFreeWagon()) { t->ConsistChanged(CCF_TRACK); @@ -1196,7 +1196,7 @@ static void UpdateAllServiceInterval(int32_t new_value) if (update_vehicles) { const Company *c = Company::Get(_current_company); - for (Vehicle *v : Vehicle::Iterate()) { + for (Vehicle *v : Vehicle::IterateFrontOnly()) { if (v->owner == _current_company && v->IsPrimaryVehicle() && !v->ServiceIntervalIsCustom()) { v->SetServiceInterval(CompanyServiceInterval(c, v->type)); v->SetServiceIntervalIsPercent(new_value != 0); @@ -1224,7 +1224,7 @@ static bool CanUpdateServiceInterval(VehicleType type, int32_t &new_value) static void UpdateServiceInterval(VehicleType type, int32_t new_value) { if (_game_mode != GM_MENU && Company::IsValidID(_current_company)) { - for (Vehicle *v : Vehicle::IterateType(type)) { + for (Vehicle *v : Vehicle::IterateTypeFrontOnly(type)) { if (v->owner == _current_company && v->IsPrimaryVehicle() && !v->ServiceIntervalIsCustom()) { v->SetServiceInterval(new_value); } @@ -1330,7 +1330,7 @@ static void ChangeMinutesPerYear(int32_t new_value) static void TrainAccelerationModelChanged(int32_t new_value) { - for (Train *t : Train::Iterate()) { + for (Train *t : Train::IterateFrontOnly()) { if (t->IsFrontEngine()) { t->tcache.cached_max_curve_speed = t->GetCurveSpeedLimit(); t->UpdateAcceleration(); @@ -1406,13 +1406,13 @@ static void TrainBrakingModelChanged(int32_t new_value) SCOPE_INFO_FMT([&v_cur], "TrainBrakingModelChanged: %s", scope_dumper().VehicleInfo(v_cur)); extern bool _long_reserve_disabled; _long_reserve_disabled = true; - for (Train *v : Train::Iterate()) { + for (Train *v : Train::IterateFrontOnly()) { v_cur = v; if (!v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0 || HasBit(v->subtype, GVSF_VIRTUAL) || v->track == TRACK_BIT_DEPOT) continue; TryPathReserve(v, true, HasStationTileRail(v->tile)); } _long_reserve_disabled = false; - for (Train *v : Train::Iterate()) { + for (Train *v : Train::IterateFrontOnly()) { v_cur = v; if (!v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0 || HasBit(v->subtype, GVSF_VIRTUAL) || v->track == TRACK_BIT_DEPOT) continue; TryPathReserve(v, true, HasStationTileRail(v->tile)); @@ -1421,7 +1421,7 @@ static void TrainBrakingModelChanged(int32_t new_value) } else if (new_value == TBM_ORIGINAL && (_game_mode == GM_NORMAL || _game_mode == GM_EDITOR)) { Train *v_cur = nullptr; SCOPE_INFO_FMT([&v_cur], "TrainBrakingModelChanged: %s", scope_dumper().VehicleInfo(v_cur)); - for (Train *v : Train::Iterate()) { + for (Train *v : Train::IterateFrontOnly()) { v_cur = v; if (!v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0 || HasBit(v->subtype, GVSF_VIRTUAL) || v->track == TRACK_BIT_DEPOT) { v->lookahead.reset(); @@ -1451,7 +1451,7 @@ static void TrainBrakingModelChanged(int32_t new_value) */ static void TrainSlopeSteepnessChanged(int32_t new_value) { - for (Train *t : Train::Iterate()) { + for (Train *t : Train::IterateFrontOnly()) { if (t->IsFrontEngine()) { t->CargoChanged(); if (t->lookahead != nullptr) SetBit(t->lookahead->flags, TRLF_APPLY_ADVISORY); @@ -1466,17 +1466,13 @@ static void TrainSlopeSteepnessChanged(int32_t new_value) static void RoadVehAccelerationModelChanged(int32_t new_value) { if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) { - for (RoadVehicle *rv : RoadVehicle::Iterate()) { - if (rv->IsFrontEngine()) { - rv->CargoChanged(); - } + for (RoadVehicle *rv : RoadVehicle::IterateFrontOnly()) { + rv->CargoChanged(); } } if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL || !_settings_game.vehicle.improved_breakdowns) { - for (RoadVehicle *rv : RoadVehicle::Iterate()) { - if (rv->IsFrontEngine()) { - rv->breakdown_chance_factor = 128; - } + for (RoadVehicle *rv : RoadVehicle::IterateFrontOnly()) { + rv->breakdown_chance_factor = 128; } } @@ -1493,8 +1489,8 @@ static void RoadVehAccelerationModelChanged(int32_t new_value) */ static void RoadVehSlopeSteepnessChanged(int32_t new_value) { - for (RoadVehicle *rv : RoadVehicle::Iterate()) { - if (rv->IsFrontEngine()) rv->CargoChanged(); + for (RoadVehicle *rv : RoadVehicle::IterateFrontOnly()) { + rv->CargoChanged(); } } @@ -2022,8 +2018,8 @@ static void ImprovedBreakdownsSettingChanged(int32_t new_value) { if (!_settings_game.vehicle.improved_breakdowns) return; - for (Vehicle *v : Vehicle::Iterate()) { - switch(v->type) { + for (Vehicle *v : Vehicle::IterateFrontOnly()) { + switch (v->type) { case VEH_TRAIN: if (v->IsFrontEngine()) { v->breakdown_chance_factor = 128; diff --git a/src/sl/vehicle_sl.cpp b/src/sl/vehicle_sl.cpp index c98662b21d..113c623e57 100644 --- a/src/sl/vehicle_sl.cpp +++ b/src/sl/vehicle_sl.cpp @@ -273,6 +273,9 @@ void AfterLoadVehicles(bool part_of_load) /* Reinstate the previous pointer */ if (v->Next() != nullptr) { v->Next()->previous = v; +#if OTTD_UPPER_TAGGED_PTR + VehiclePoolOps::SetIsNonFrontVehiclePtr(_vehicle_pool.GetRawRef(v->Next()->index), true); +#endif if (v->type == VEH_TRAIN && (HasBit(v->subtype, GVSF_VIRTUAL) != HasBit(v->Next()->subtype, GVSF_VIRTUAL))) { SlErrorCorrupt("Mixed virtual/non-virtual train consist"); } @@ -387,7 +390,7 @@ void AfterLoadVehicles(bool part_of_load) if (IsSavegameVersionBefore(SLV_180)) { /* Set service interval flags */ - for (Vehicle *v : Vehicle::Iterate()) { + for (Vehicle *v : Vehicle::IterateFrontOnly()) { si_v = v; if (!v->IsPrimaryVehicle()) continue; @@ -429,7 +432,7 @@ void AfterLoadVehicles(bool part_of_load) CheckValidVehicles(); - for (Vehicle *v : Vehicle::Iterate()) { + for (Vehicle *v : Vehicle::IterateFrontOnly()) { si_v = v; assert(v->first != nullptr); @@ -595,7 +598,7 @@ void FixupTrainLengths() { /* Vehicle center was moved from 4 units behind the front to half the length * behind the front. Move vehicles so they end up on the same spot. */ - for (Train *v : Train::Iterate()) { + for (Train *v : Train::IterateFrontOnly()) { if (v->IsPrimaryVehicle()) { /* The vehicle center is now more to the front depending on vehicle length, * so we need to move all vehicles forward to cover the difference to the @@ -1622,7 +1625,7 @@ const SaveLoadTable GetVehicleUnbunchStateDescription() void Save_VUBS() { - for (Vehicle *v : Vehicle::Iterate()) { + for (Vehicle *v : Vehicle::IterateFrontOnly()) { if (v->unbunch_state != nullptr) { SlSetArrayIndex(v->index); SlObject(v->unbunch_state.get(), GetVehicleUnbunchStateDescription()); diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 6f755b14b4..147891531a 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -2456,9 +2456,8 @@ CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags, int replacement_ delete cur_stop; /* Make sure no vehicle is going to the old roadstop */ - for (RoadVehicle *v : RoadVehicle::Iterate()) { - if (v->First() == v && v->current_order.IsType(OT_GOTO_STATION) && - v->dest_tile == tile) { + for (RoadVehicle *v : RoadVehicle::IterateFrontOnly()) { + if (v->current_order.IsType(OT_GOTO_STATION) && v->dest_tile == tile) { v->SetDestTile(v->GetOrderStationLocation(st->index)); } } @@ -3236,9 +3235,7 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags) ClearDockingTilesCheckingNeighbours(tile1); ClearDockingTilesCheckingNeighbours(tile2); - for (Ship *s : Ship::Iterate()) { - if (!s->IsPrimaryVehicle()) continue; - + for (Ship *s : Ship::IterateFrontOnly()) { /* Find all ships going to our dock. */ if (s->current_order.GetDestination() != st->index) { continue; diff --git a/src/tbtr_template_vehicle.cpp b/src/tbtr_template_vehicle.cpp index d2e6f87101..590e2533c3 100644 --- a/src/tbtr_template_vehicle.cpp +++ b/src/tbtr_template_vehicle.cpp @@ -204,7 +204,7 @@ static void MarkTrainsInGroupAsPendingTemplateReplacement(GroupID gid, const Tem std::sort(groups.begin(), groups.end()); - for (Train *t : Train::Iterate()) { + for (Train *t : Train::IterateFrontOnly()) { if (!t->IsFrontEngine() || t->owner != owner || t->group_id >= NEW_GROUP) continue; if (std::binary_search(groups.begin(), groups.end(), t->group_id)) { @@ -217,7 +217,7 @@ void MarkTrainsUsingTemplateAsPendingTemplateReplacement(const TemplateVehicle * { Owner owner = tv->owner; - for (Train *t : Train::Iterate()) { + for (Train *t : Train::IterateFrontOnly()) { if (!t->IsFrontEngine() || t->owner != owner || t->group_id >= NEW_GROUP) continue; if (GetTemplateIDByGroupIDRecursive(t->group_id) == tv->index) { diff --git a/src/tbtr_template_vehicle_func.cpp b/src/tbtr_template_vehicle_func.cpp index cf83b44887..a977de3adc 100644 --- a/src/tbtr_template_vehicle_func.cpp +++ b/src/tbtr_template_vehicle_func.cpp @@ -327,7 +327,7 @@ uint CountsTrainsNeedingTemplateReplacement(GroupID g_id, const TemplateVehicle uint count = 0; if (!tv) return count; - for (Train *t : Train::Iterate()) { + for (Train *t : Train::IterateFrontOnly()) { if (t->IsPrimaryVehicle() && t->group_id == g_id && TrainTemplateDifference(t, tv) != TBTRDF_NONE) { count++; } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 9793b74c8e..cc6ca8f09b 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -170,8 +170,8 @@ void CheckTrainsLengths() { bool first = true; - for (const Train *v : Train::Iterate()) { - if (v->First() == v && !(v->vehstatus & VS_CRASHED) && !v->IsVirtual()) { + for (const Train *v : Train::IterateFrontOnly()) { + if (!(v->vehstatus & VS_CRASHED) && !v->IsVirtual()) { for (const Train *u = v, *w = v->Next(); w != nullptr; u = w, w = w->Next()) { if (u->track != TRACK_BIT_DEPOT) { if ((w->track != TRACK_BIT_DEPOT && @@ -1503,7 +1503,7 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const CheckConsistencyOfArticulatedVehicle(v); /* Try to connect the vehicle to one of free chains of wagons. */ - for (Train *w : Train::Iterate()) { + for (Train *w : Train::IterateFrontOnly()) { if (w->tile == tile && ///< Same depot w->IsFreeWagon() && ///< A free wagon chain w->engine_type == e->index && ///< Same type @@ -1527,7 +1527,7 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const void NormalizeTrainVehInDepot(const Train *u) { assert(u->IsEngine()); - for (const Train *v : Train::Iterate()) { + for (const Train *v : Train::IterateFrontOnly()) { if (v->IsFreeWagon() && v->tile == u->tile && v->track == TRACK_BIT_DEPOT && v->owner == u->owner && @@ -1674,7 +1674,7 @@ static Train *FindGoodVehiclePos(const Train *src) EngineID eng = src->engine_type; TileIndex tile = src->tile; - for (Train *dst : Train::Iterate()) { + for (Train *dst : Train::IterateFrontOnly()) { if (dst->IsFreeWagon() && dst->tile == tile && !(dst->vehstatus & VS_CRASHED) && dst->owner == src->owner && !dst->IsVirtual()) { /* check so all vehicles in the line have the same engine. */ Train *t = dst; diff --git a/src/train_gui.cpp b/src/train_gui.cpp index 6816ee35dd..b7a9edbd82 100644 --- a/src/train_gui.cpp +++ b/src/train_gui.cpp @@ -36,7 +36,7 @@ void CcBuildWagon(const CommandCost &result, TileIndex tile, uint32_t p1, uint32 /* find a locomotive in the depot. */ const Vehicle *found = nullptr; - for (const Train *t : Train::Iterate()) { + for (const Train *t : Train::IterateFrontOnly()) { if (t->IsFrontEngine() && t->tile == tile && t->IsStoppedInDepot() && !t->IsVirtual()) { if (found != nullptr) return; // must be exactly one. found = t; diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index 8298e3fdec..a0d94ab2dd 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -2861,7 +2861,7 @@ static bool ClickTile_TunnelBridge(TileIndex tile) if (IsTunnelTile(tile)) { int count = 0; TileIndex tile_end = GetOtherTunnelBridgeEnd(tile); - for (const Train *t : Train::Iterate()) { + for (const Train *t : Train::IterateFrontOnly()) { if (!t->IsFrontEngine()) continue; if (tile == t->tile || tile_end == t->tile) { ShowVehicleViewWindow(t); diff --git a/src/vehicle.cpp b/src/vehicle.cpp index a3bb54974f..bfc069e9a5 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -4317,6 +4317,9 @@ void Vehicle::SetNext(Vehicle *next) v->first = this->next; } this->next->previous = nullptr; +#if OTTD_UPPER_TAGGED_PTR + VehiclePoolOps::SetIsNonFrontVehiclePtr(_vehicle_pool.GetRawRef(this->next->index), false); +#endif } this->next = next; @@ -4325,6 +4328,9 @@ void Vehicle::SetNext(Vehicle *next) /* A new next vehicle. Update the first and previous pointers */ if (this->next->previous != nullptr) this->next->previous->next = nullptr; this->next->previous = this; +#if OTTD_UPPER_TAGGED_PTR + VehiclePoolOps::SetIsNonFrontVehiclePtr(_vehicle_pool.GetRawRef(this->next->index), true); +#endif for (Vehicle *v = this->next; v != nullptr; v = v->Next()) { v->first = this->first; } @@ -4549,7 +4555,7 @@ char *Vehicle::DumpVehicleFlagsMultiline(char *b, const char *last, const char * void VehiclesYearlyLoop() { - for (Vehicle *v : Vehicle::Iterate()) { + for (Vehicle *v : Vehicle::IterateFrontOnly()) { if (v->IsPrimaryVehicle()) { /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */ Money profit = v->GetDisplayProfitThisYear(); diff --git a/src/vehicle_base.h b/src/vehicle_base.h index fe0974b08d..8095661add 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -255,6 +255,9 @@ struct VehiclePoolOps { static constexpr VehicleType DefaultItemParam() { return VEH_INVALID; } static constexpr VehicleType GetVehicleType(uintptr_t ptr) { return static_cast(GB(ptr, 60, 3)); } + static constexpr bool IsNonFrontVehiclePtr(uintptr_t ptr) { return HasBit(ptr, 63); } + + static constexpr void SetIsNonFrontVehiclePtr(uintptr_t &ptr, bool non_front) { SB(ptr, 63, 1, non_front ? 1 : 0); } }; typedef Pool VehiclePool; @@ -1303,6 +1306,32 @@ public: } }; + struct VehicleFrontOnlyFilter { + bool operator() (size_t index) + { +#if OTTD_UPPER_TAGGED_PTR + return !VehiclePoolOps::IsNonFrontVehiclePtr(_vehicle_pool.GetRaw(index)); +#else + return Vehicle::Get(index)->Previous() == nullptr; +#endif + } + }; + + struct VehicleFrontOnlyTypeFilter { + VehicleType vt; + + bool operator() (size_t index) + { +#if OTTD_UPPER_TAGGED_PTR + uintptr_t vptr = _vehicle_pool.GetRaw(index); + return !VehiclePoolOps::IsNonFrontVehiclePtr(vptr) && VehiclePoolOps::GetVehicleType(vptr) == this->vt; +#else + const Vehicle *v = Vehicle::Get(index); + return v->type == this->vt && v->Previous() == nullptr; +#endif + } + }; + /** * Returns an iterable ensemble of all valid vehicles of the given type * @param vt the VehicleType to filter @@ -1313,6 +1342,27 @@ public: { return Pool::IterateWrapperFiltered(from, VehicleTypeFilter{ vt }); } + + /** + * Returns an iterable ensemble of all valid front vehicles (i.e. Previous() == nullptr) + * @param from index of the first vehicle to consider + * @return an iterable ensemble of all valid front vehicles + */ + static Pool::IterateWrapperFiltered IterateFrontOnly(size_t from = 0) + { + return Pool::IterateWrapperFiltered(from, VehicleFrontOnlyFilter{}); + } + + /** + * Returns an iterable ensemble of all valid front vehicles of the given type + * @param vt the VehicleType to filter + * @param from index of the first vehicle to consider + * @return an iterable ensemble of all valid front vehicles of the given type + */ + static Pool::IterateWrapperFiltered IterateTypeFrontOnly(VehicleType vt, size_t from = 0) + { + return Pool::IterateWrapperFiltered(from, VehicleFrontOnlyTypeFilter{ vt }); + } }; inline bool IsPointInViewportVehicleRedrawArea(const std::vector &viewport_redraw_rects, const Point &pt) @@ -1608,6 +1658,16 @@ public: * @return an iterable ensemble of all valid vehicles of type T */ static Pool::IterateWrapper Iterate(size_t from = 0) { return Pool::IterateWrapper(from); } + + /** + * Returns an iterable ensemble of all valid front vehicles (i.e. Previous() == nullptr) of type T + * @param from index of the first vehicle to consider + * @return an iterable ensemble of all valid front vehicles of type T + */ + static Pool::IterateWrapperFiltered IterateFrontOnly(size_t from = 0) + { + return Pool::IterateWrapperFiltered(from, VehicleFrontOnlyFilter{}); + } }; /** Generates sequence of free UnitID numbers */ diff --git a/src/vehiclelist.cpp b/src/vehiclelist.cpp index 2f88bcf37b..1d54be1c63 100644 --- a/src/vehiclelist.cpp +++ b/src/vehiclelist.cpp @@ -155,7 +155,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli }; auto fill_all_vehicles = [&]() { - for (const Vehicle *v : Vehicle::IterateType(vli.vtype)) { + for (const Vehicle *v : Vehicle::IterateTypeFrontOnly(vli.vtype)) { if (!HasBit(v->subtype, GVSF_VIRTUAL) && v->owner == vli.company && v->IsPrimaryVehicle()) { add_veh(v); } @@ -184,7 +184,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli case VL_GROUP_LIST: if (vli.index != ALL_GROUP) { - for (const Vehicle *v : Vehicle::IterateType(vli.vtype)) { + for (const Vehicle *v : Vehicle::IterateTypeFrontOnly(vli.vtype)) { if (!HasBit(v->subtype, GVSF_VIRTUAL) && v->IsPrimaryVehicle() && v->owner == vli.company && GroupIsInGroup(v->group_id, vli.index)) { add_veh(v);